├── .eslintrc.json ├── .github └── workflows │ └── lint.yml ├── .gitignore ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── .yarnrc ├── CHANGELOG.md ├── DEVELOPERDOCS.md ├── LICENSE ├── README.md ├── build └── node-extension.webpack.config.js ├── package-lock.json ├── package.json ├── res ├── library │ ├── atcoder │ │ ├── LICENSE │ │ ├── all │ │ ├── convolution │ │ ├── convolution.hpp │ │ ├── dsu │ │ ├── dsu.hpp │ │ ├── fenwicktree │ │ ├── fenwicktree.hpp │ │ ├── internal_bit │ │ ├── internal_bit.hpp │ │ ├── internal_csr │ │ ├── internal_csr.hpp │ │ ├── internal_math │ │ ├── internal_math.hpp │ │ ├── internal_queue │ │ ├── internal_queue.hpp │ │ ├── internal_scc │ │ ├── internal_scc.hpp │ │ ├── internal_type_traits │ │ ├── internal_type_traits.hpp │ │ ├── lazysegtree │ │ ├── lazysegtree.hpp │ │ ├── math │ │ ├── math.hpp │ │ ├── maxflow │ │ ├── maxflow.hpp │ │ ├── mincostflow │ │ ├── mincostflow.hpp │ │ ├── modint │ │ ├── modint.hpp │ │ ├── scc │ │ ├── scc.hpp │ │ ├── segtree │ │ ├── segtree.hpp │ │ ├── string │ │ ├── string.hpp │ │ ├── twosat │ │ └── twosat.hpp │ └── expander.py └── svg │ ├── AclIntellisense.png │ ├── CreateFolder backup.png │ ├── CreateFolder.jpg │ ├── CreateFolder.png │ ├── IconLabels.png │ ├── add_TestCase.png │ ├── add_TestCase1.jpeg │ ├── brackets.svg │ ├── contestRegistration.png │ ├── copy.png │ ├── createAclCombinedFile.png │ ├── createFile.png │ ├── createStressTestingFiles.png │ ├── createStressTestingFiles.svg │ ├── cross-mark.png │ ├── filter backup.png │ ├── filter.png │ ├── filter.svg │ ├── green-tick.png │ ├── logo.png │ ├── openAclDocumentation.png │ ├── play_button.png │ ├── question_mark.png │ ├── refresh.svg │ ├── registerContest.jpeg │ ├── registration.jpeg │ ├── registration.png │ ├── stressTest.png │ ├── stressTest.svg │ ├── submit.png │ ├── submit.svg │ └── upload.png ├── src ├── classes │ ├── contest.ts │ └── problem.ts ├── data_providers │ ├── contests │ │ ├── contest_data_provider.ts │ │ └── contest_tree_item.ts │ ├── problems │ │ ├── problem_data_provider.ts │ │ └── problem_tree_item.ts │ └── user_profile │ │ ├── profile_data_provider.ts │ │ └── profile_tree_item.ts ├── extension.ts ├── features │ ├── ACL │ │ ├── createAclCombinedFile.ts │ │ └── openAclDocumentation.ts │ ├── contest_registration │ │ └── contest_registration.ts │ ├── contests_list │ │ ├── contests_list.ts │ │ └── submission_status.ts │ ├── copy_url │ │ ├── copy_contest_url.ts │ │ └── copy_problem_url.ts │ ├── folder_creation │ │ ├── contest_folder_creation.ts │ │ ├── manual_contest_folder.ts │ │ ├── manual_problem_folder.ts │ │ ├── problem_folder_creation.ts │ │ └── test_cases_fetch.ts │ ├── open_problem_statement │ │ ├── open_contest.ts │ │ ├── open_problem_from_problem_list.ts │ │ └── open_problem_statement.ts │ ├── problems_list │ │ ├── problems_filter.ts │ │ ├── problems_filter_input.ts │ │ └── submission_status.ts │ ├── run_test_cases │ │ ├── add_test_cases.ts │ │ ├── compile_solution.ts │ │ ├── report_error.ts │ │ ├── run_solution.ts │ │ └── run_test_cases.ts │ ├── stress_test │ │ ├── compile_all_files.ts │ │ ├── createStressTestingFiles.ts │ │ └── stress_test.ts │ ├── submit_problem │ │ └── submit_problem.ts │ └── user_profile │ │ ├── fetch_user_info_api.ts │ │ └── get_user_handle.ts ├── test │ ├── runTest.ts │ └── suite │ │ ├── extension.test.ts │ │ └── index.ts └── utils │ ├── consts.ts │ └── utils.ts ├── tsconfig.json ├── vsc-extension-quickstart.md └── yarn.lock /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": [ 9 | "@typescript-eslint" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/naming-convention": "error", 13 | "@typescript-eslint/semi": "error", 14 | "curly": "error", 15 | "indent": ["error",4,{"SwitchCase": 1}], 16 | "eqeqeq": "error", 17 | "no-throw-literal": "error", 18 | "semi": "off" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: ESlint 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | 8 | jobs: 9 | test: 10 | runs-on: ${{ matrix.os }} # runs a test on Ubuntu, Windows and macOS 11 | 12 | strategy: 13 | matrix: 14 | os: [ubuntu-latest] 15 | 16 | steps: 17 | - uses: actions/checkout@v1 18 | - name: install node v12 19 | uses: actions/setup-node@v1 20 | with: 21 | node-version: 12 22 | - name: yarn install 23 | run: yarn install 24 | - name: yarn run lint 25 | run: yarn run lint 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | dist 3 | node_modules 4 | .vscode-test/ 5 | *.vsix 6 | yarn-error.log 7 | a.out 8 | .env 9 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "dbaeumer.vscode-eslint", 6 | "eamodio.tsl-problem-matcher" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": [ 13 | "--extensionDevelopmentPath=${workspaceFolder}" 14 | ], 15 | "outFiles": [ 16 | "${workspaceFolder}/dist/**/*.js" 17 | ], 18 | "preLaunchTask": "${defaultBuildTask}" 19 | }, 20 | { 21 | "name": "Extension Tests", 22 | "type": "extensionHost", 23 | "request": "launch", 24 | "args": [ 25 | "--extensionDevelopmentPath=${workspaceFolder}", 26 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 27 | ], 28 | "outFiles": [ 29 | "${workspaceFolder}/out/test/**/*.js" 30 | ], 31 | "preLaunchTask": "npm: test-watch" 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 10 | "typescript.tsc.autoDetect": "off" 11 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": [ 10 | "$ts-webpack-watch", 11 | "$tslint-webpack-watch" 12 | ], 13 | "isBackground": true, 14 | "presentation": { 15 | "reveal": "never" 16 | }, 17 | "group": { 18 | "kind": "build", 19 | "isDefault": true 20 | } 21 | }, 22 | { 23 | "type": "npm", 24 | "script": "test-watch", 25 | "problemMatcher": "$tsc-watch", 26 | "isBackground": true, 27 | "presentation": { 28 | "reveal": "never" 29 | }, 30 | "group": "build" 31 | }, 32 | { 33 | "type": "npm", 34 | "script": "compile", 35 | "group": "build", 36 | "problemMatcher": [], 37 | "label": "npm: compile", 38 | "detail": "webpack --config ./build/node-extension.webpack.config.js" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/** 4 | src/** 5 | .gitignore 6 | .yarnrc 7 | vsc-extension-quickstart.md 8 | **/tsconfig.json 9 | **/.eslintrc.json 10 | **/*.map 11 | **/*.ts 12 | DEVELOPERDOCS.md 13 | res/GIFS 14 | 15 | -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | --ignore-engines true -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "codepal" extension will be documented in this file. 4 | 5 | ## [1.4.0] 6 | - Fix window presentation error while adding new testcases. 7 | - Add AtCoder Library support for C++ 8 | 9 | ## [1.2.0] 10 | - Add Kotlin support 11 | 12 | ## [1.1.2] 13 | - Add more meaningful error messages. 14 | 15 | ## [1.1.1] 16 | - Fixed icon dimensions according to the new VS Code update 1.56.0. 17 | 18 | ## [1.1.0] 19 | - Added feature to manually create a folder for any problem or contest (No of problems to be specified manually along with name of contest or problem). 20 | - Added a feature to automatically copy code written by user when he clicks submit button. 21 | - Add a button in tree view to open problem statement to view problem before creating folder. 22 | - Fixed [Issue #63](https://github.com/IEEE-NITK/CodePal/issues/63) by displaying future contests in ascending order. 23 | - Fixed [Issue #58](https://github.com/IEEE-NITK/CodePal/issues/58) by adding a provision in settings to specify generator file template path. 24 | 25 | ## [1.0.1] 26 | - Added a feature to filter problems based on submission status. 27 | - Added a feature to copy the link of Codeforces problems and contests. 28 | - Fixed a bug related to displaying submission status of contest problems. 29 | 30 | ## [1.0.0] 31 | - Added a feature to stress test. 32 | - Added a feature to accept handle and give a personalized experience by showing submission status on problems and user profile. 33 | - Added Keyboard shortcuts for many features. 34 | - Fixed a bug by killing process after TLE on Linux/Mac 35 | 36 | ## [0.0.3] 37 | - Fixed a bug regarding running of test cases on Windows Operating System, where a process that times out will have to be killed explicitly. 38 | 39 | ## [0.0.2] 40 | - Fixed g++,gcc run testcases features that were creating a.out on compiling in a folder without write access on MAC. 41 | - Changed the file naming conventions for contests/problems folder creation because java needs file name same as class name and spaces and hyphens aren't allowed in a class name. 42 | 43 | ## [0.0.1] (First Release) 44 | - Added treeviews for viewing problem set and Contest list along with date and time of future contests. 45 | - Added feature to make problems explandable to show tags associated as well. 46 | - Added feature to create a folder consisting of all sample tests for a contest or for any individual problem. 47 | - Added feature to filter through problem set based on tags and rating. 48 | - Added Feature to Run test cases feature with language configurable in the settings. Languages that can be chosen are C,C++,Java,Python.Additional compilation flags may also be added through the codepal settings. 49 | - Added feature to add additional test for any problem. 50 | - Added feature to directly open problem statement and Submission page on users default website. 51 | 52 | 53 | -------------------------------------------------------------------------------- /DEVELOPERDOCS.md: -------------------------------------------------------------------------------- 1 | # Developer Documentation 2 | - Please use [yarn](https://classic.yarnpkg.com/en/docs/install/) package manager to install all dependencies of this extension. 3 | - Also make sure [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) has been already installed on your system before you run the extension development host becuase many build tasks consist of npm commands. 4 | 5 | ## Setting up instructions 6 | 1. Clone the repository 7 | 2. Change directory into CodePal. ("cd CodePal") 8 | 3. Install all dependencies. ("yarn install") 9 | 4. Open the project files in VS code. ("code .") 10 | 5. Press F5 and click the "run extension" button below to run the compiled extension in an extension host window. 11 | 12 | -------------------------------------------------------------------------------- /build/node-extension.webpack.config.js: -------------------------------------------------------------------------------- 1 | //@ts-check 2 | 3 | 'use strict'; 4 | 5 | const path = require('path'); 6 | 7 | /**@type {import('webpack').Configuration}*/ 8 | const config = { 9 | target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ 10 | mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production') 11 | 12 | entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ 13 | output: { 14 | // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ 15 | path: path.resolve(__dirname, '..', 'dist'), 16 | filename: 'extension.js', 17 | libraryTarget: 'commonjs2' 18 | }, 19 | devtool: 'nosources-source-map', 20 | externals: { 21 | vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ 22 | }, 23 | resolve: { 24 | // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader 25 | extensions: ['.ts', '.js'] 26 | }, 27 | module: { 28 | rules: [ 29 | { 30 | test: /\.ts$/, 31 | exclude: /node_modules/, 32 | use: [ 33 | { 34 | loader: 'ts-loader' 35 | } 36 | ] 37 | } 38 | ] 39 | } 40 | }; 41 | module.exports = config; -------------------------------------------------------------------------------- /res/library/atcoder/LICENSE: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | 3 | Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an "owner") of an original work of 8 | authorship and/or a database (each, a "Work"). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific 12 | works ("Commons") that the public can reliably and without fear of later 13 | claims of infringement build upon, modify, incorporate in other works, reuse 14 | and redistribute as freely as possible in any form whatsoever and for any 15 | purposes, including without limitation commercial purposes. These owners may 16 | contribute to the Commons to promote the ideal of a free culture and the 17 | further production of creative, cultural and scientific works, or to gain 18 | reputation or greater distribution for their Work in part through the use and 19 | efforts of others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation 22 | of additional consideration or compensation, the person associating CC0 with a 23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 25 | and publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | 1. Copyright and Related Rights. A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights ("Copyright and 31 | Related Rights"). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 34 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 35 | and translate a Work; 36 | 37 | ii. moral rights retained by the original author(s) and/or performer(s); 38 | 39 | iii. publicity and privacy rights pertaining to a person's image or likeness 40 | depicted in a Work; 41 | 42 | iv. rights protecting against unfair competition in regards to a Work, 43 | subject to the limitations in paragraph 4(a), below; 44 | 45 | v. rights protecting the extraction, dissemination, use and reuse of data in 46 | a Work; 47 | 48 | vi. database rights (such as those arising under Directive 96/9/EC of the 49 | European Parliament and of the Council of 11 March 1996 on the legal 50 | protection of databases, and under any national implementation thereof, 51 | including any amended or successor version of such directive); and 52 | 53 | vii. other similar, equivalent or corresponding rights throughout the world 54 | based on applicable law or treaty, and any national implementations thereof. 55 | 56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 59 | and Related Rights and associated claims and causes of action, whether now 60 | known or unknown (including existing as well as future claims and causes of 61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 62 | duration provided by applicable law or treaty (including future time 63 | extensions), (iii) in any current or future medium and for any number of 64 | copies, and (iv) for any purpose whatsoever, including without limitation 65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 66 | the Waiver for the benefit of each member of the public at large and to the 67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 68 | shall not be subject to revocation, rescission, cancellation, termination, or 69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 70 | by the public as contemplated by Affirmer's express Statement of Purpose. 71 | 72 | 3. Public License Fallback. Should any part of the Waiver for any reason be 73 | judged legally invalid or ineffective under applicable law, then the Waiver 74 | shall be preserved to the maximum extent permitted taking into account 75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 76 | is so judged Affirmer hereby grants to each affected person a royalty-free, 77 | non transferable, non sublicensable, non exclusive, irrevocable and 78 | unconditional license to exercise Affirmer's Copyright and Related Rights in 79 | the Work (i) in all territories worldwide, (ii) for the maximum duration 80 | provided by applicable law or treaty (including future time extensions), (iii) 81 | in any current or future medium and for any number of copies, and (iv) for any 82 | purpose whatsoever, including without limitation commercial, advertising or 83 | promotional purposes (the "License"). The License shall be deemed effective as 84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 85 | License for any reason be judged legally invalid or ineffective under 86 | applicable law, such partial invalidity or ineffectiveness shall not 87 | invalidate the remainder of the License, and in such case Affirmer hereby 88 | affirms that he or she will not (i) exercise any of his or her remaining 89 | Copyright and Related Rights in the Work or (ii) assert any associated claims 90 | and causes of action with respect to the Work, in either case contrary to 91 | Affirmer's express Statement of Purpose. 92 | 93 | 4. Limitations and Disclaimers. 94 | 95 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 96 | surrendered, licensed or otherwise affected by this document. 97 | 98 | b. Affirmer offers the Work as-is and makes no representations or warranties 99 | of any kind concerning the Work, express, implied, statutory or otherwise, 100 | including without limitation warranties of title, merchantability, fitness 101 | for a particular purpose, non infringement, or the absence of latent or 102 | other defects, accuracy, or the present or absence of errors, whether or not 103 | discoverable, all to the greatest extent permissible under applicable law. 104 | 105 | c. Affirmer disclaims responsibility for clearing rights of other persons 106 | that may apply to the Work or any use thereof, including without limitation 107 | any person's Copyright and Related Rights in the Work. Further, Affirmer 108 | disclaims responsibility for obtaining any necessary consents, permissions 109 | or other rights required for any use of the Work. 110 | 111 | d. Affirmer understands and acknowledges that Creative Commons is not a 112 | party to this document and has no duty or obligation with respect to this 113 | CC0 or use of the Work. 114 | 115 | For more information, please see 116 | -------------------------------------------------------------------------------- /res/library/atcoder/all: -------------------------------------------------------------------------------- 1 | #include "atcoder/convolution" 2 | #include "atcoder/dsu" 3 | #include "atcoder/fenwicktree" 4 | #include "atcoder/lazysegtree" 5 | #include "atcoder/math" 6 | #include "atcoder/maxflow" 7 | #include "atcoder/mincostflow" 8 | #include "atcoder/modint" 9 | #include "atcoder/scc" 10 | #include "atcoder/segtree" 11 | #include "atcoder/string" 12 | #include "atcoder/twosat" 13 | -------------------------------------------------------------------------------- /res/library/atcoder/convolution: -------------------------------------------------------------------------------- 1 | #include "atcoder/convolution.hpp" 2 | -------------------------------------------------------------------------------- /res/library/atcoder/dsu: -------------------------------------------------------------------------------- 1 | #include "atcoder/dsu.hpp" 2 | -------------------------------------------------------------------------------- /res/library/atcoder/dsu.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ATCODER_DSU_HPP 2 | #define ATCODER_DSU_HPP 1 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace atcoder { 9 | 10 | // Implement (union by size) + (path compression) 11 | // Reference: 12 | // Zvi Galil and Giuseppe F. Italiano, 13 | // Data structures and algorithms for disjoint set union problems 14 | struct dsu { 15 | public: 16 | dsu() : _n(0) {} 17 | explicit dsu(int n) : _n(n), parent_or_size(n, -1) {} 18 | 19 | int merge(int a, int b) { 20 | assert(0 <= a && a < _n); 21 | assert(0 <= b && b < _n); 22 | int x = leader(a), y = leader(b); 23 | if (x == y) return x; 24 | if (-parent_or_size[x] < -parent_or_size[y]) std::swap(x, y); 25 | parent_or_size[x] += parent_or_size[y]; 26 | parent_or_size[y] = x; 27 | return x; 28 | } 29 | 30 | bool same(int a, int b) { 31 | assert(0 <= a && a < _n); 32 | assert(0 <= b && b < _n); 33 | return leader(a) == leader(b); 34 | } 35 | 36 | int leader(int a) { 37 | assert(0 <= a && a < _n); 38 | if (parent_or_size[a] < 0) return a; 39 | return parent_or_size[a] = leader(parent_or_size[a]); 40 | } 41 | 42 | int size(int a) { 43 | assert(0 <= a && a < _n); 44 | return -parent_or_size[leader(a)]; 45 | } 46 | 47 | std::vector> groups() { 48 | std::vector leader_buf(_n), group_size(_n); 49 | for (int i = 0; i < _n; i++) { 50 | leader_buf[i] = leader(i); 51 | group_size[leader_buf[i]]++; 52 | } 53 | std::vector> result(_n); 54 | for (int i = 0; i < _n; i++) { 55 | result[i].reserve(group_size[i]); 56 | } 57 | for (int i = 0; i < _n; i++) { 58 | result[leader_buf[i]].push_back(i); 59 | } 60 | result.erase( 61 | std::remove_if(result.begin(), result.end(), 62 | [&](const std::vector& v) { return v.empty(); }), 63 | result.end()); 64 | return result; 65 | } 66 | 67 | private: 68 | int _n; 69 | // root node: -1 * component size 70 | // otherwise: parent 71 | std::vector parent_or_size; 72 | }; 73 | 74 | } // namespace atcoder 75 | 76 | #endif // ATCODER_DSU_HPP 77 | -------------------------------------------------------------------------------- /res/library/atcoder/fenwicktree: -------------------------------------------------------------------------------- 1 | #include "atcoder/fenwicktree.hpp" 2 | -------------------------------------------------------------------------------- /res/library/atcoder/fenwicktree.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ATCODER_FENWICKTREE_HPP 2 | #define ATCODER_FENWICKTREE_HPP 1 3 | 4 | #include 5 | #include 6 | 7 | #include "atcoder/internal_type_traits" 8 | 9 | namespace atcoder { 10 | 11 | // Reference: https://en.wikipedia.org/wiki/Fenwick_tree 12 | template struct fenwick_tree { 13 | using U = internal::to_unsigned_t; 14 | 15 | public: 16 | fenwick_tree() : _n(0) {} 17 | explicit fenwick_tree(int n) : _n(n), data(n) {} 18 | 19 | void add(int p, T x) { 20 | assert(0 <= p && p < _n); 21 | p++; 22 | while (p <= _n) { 23 | data[p - 1] += U(x); 24 | p += p & -p; 25 | } 26 | } 27 | 28 | T sum(int l, int r) { 29 | assert(0 <= l && l <= r && r <= _n); 30 | return sum(r) - sum(l); 31 | } 32 | 33 | private: 34 | int _n; 35 | std::vector data; 36 | 37 | U sum(int r) { 38 | U s = 0; 39 | while (r > 0) { 40 | s += data[r - 1]; 41 | r -= r & -r; 42 | } 43 | return s; 44 | } 45 | }; 46 | 47 | } // namespace atcoder 48 | 49 | #endif // ATCODER_FENWICKTREE_HPP 50 | -------------------------------------------------------------------------------- /res/library/atcoder/internal_bit: -------------------------------------------------------------------------------- 1 | #include "atcoder/internal_bit.hpp" 2 | -------------------------------------------------------------------------------- /res/library/atcoder/internal_bit.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ATCODER_INTERNAL_BITOP_HPP 2 | #define ATCODER_INTERNAL_BITOP_HPP 1 3 | 4 | #ifdef _MSC_VER 5 | #include 6 | #endif 7 | 8 | namespace atcoder { 9 | 10 | namespace internal { 11 | 12 | // @param n `0 <= n` 13 | // @return minimum non-negative `x` s.t. `n <= 2**x` 14 | int ceil_pow2(int n) { 15 | int x = 0; 16 | while ((1U << x) < (unsigned int)(n)) x++; 17 | return x; 18 | } 19 | 20 | // @param n `1 <= n` 21 | // @return minimum non-negative `x` s.t. `(n & (1 << x)) != 0` 22 | constexpr int bsf_constexpr(unsigned int n) { 23 | int x = 0; 24 | while (!(n & (1 << x))) x++; 25 | return x; 26 | } 27 | 28 | // @param n `1 <= n` 29 | // @return minimum non-negative `x` s.t. `(n & (1 << x)) != 0` 30 | int bsf(unsigned int n) { 31 | #ifdef _MSC_VER 32 | unsigned long index; 33 | _BitScanForward(&index, n); 34 | return index; 35 | #else 36 | return __builtin_ctz(n); 37 | #endif 38 | } 39 | 40 | } // namespace internal 41 | 42 | } // namespace atcoder 43 | 44 | #endif // ATCODER_INTERNAL_BITOP_HPP 45 | -------------------------------------------------------------------------------- /res/library/atcoder/internal_csr: -------------------------------------------------------------------------------- 1 | #include "atcoder/internal_csr.hpp" 2 | -------------------------------------------------------------------------------- /res/library/atcoder/internal_csr.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ATCODER_INTERNAL_CSR_HPP 2 | #define ATCODER_INTERNAL_CSR_HPP 1 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace atcoder { 9 | namespace internal { 10 | 11 | template struct csr { 12 | std::vector start; 13 | std::vector elist; 14 | explicit csr(int n, const std::vector>& edges) 15 | : start(n + 1), elist(edges.size()) { 16 | for (auto e : edges) { 17 | start[e.first + 1]++; 18 | } 19 | for (int i = 1; i <= n; i++) { 20 | start[i] += start[i - 1]; 21 | } 22 | auto counter = start; 23 | for (auto e : edges) { 24 | elist[counter[e.first]++] = e.second; 25 | } 26 | } 27 | }; 28 | 29 | } // namespace internal 30 | 31 | } // namespace atcoder 32 | 33 | #endif // ATCODER_INTERNAL_CSR_HPP 34 | -------------------------------------------------------------------------------- /res/library/atcoder/internal_math: -------------------------------------------------------------------------------- 1 | #include "atcoder/internal_math.hpp" 2 | -------------------------------------------------------------------------------- /res/library/atcoder/internal_math.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ATCODER_INTERNAL_MATH_HPP 2 | #define ATCODER_INTERNAL_MATH_HPP 1 3 | 4 | #include 5 | 6 | #ifdef _MSC_VER 7 | #include 8 | #endif 9 | 10 | namespace atcoder { 11 | 12 | namespace internal { 13 | 14 | // @param m `1 <= m` 15 | // @return x mod m 16 | constexpr long long safe_mod(long long x, long long m) { 17 | x %= m; 18 | if (x < 0) x += m; 19 | return x; 20 | } 21 | 22 | // Fast modular multiplication by barrett reduction 23 | // Reference: https://en.wikipedia.org/wiki/Barrett_reduction 24 | // NOTE: reconsider after Ice Lake 25 | struct barrett { 26 | unsigned int _m; 27 | unsigned long long im; 28 | 29 | // @param m `1 <= m < 2^31` 30 | explicit barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {} 31 | 32 | // @return m 33 | unsigned int umod() const { return _m; } 34 | 35 | // @param a `0 <= a < m` 36 | // @param b `0 <= b < m` 37 | // @return `a * b % m` 38 | unsigned int mul(unsigned int a, unsigned int b) const { 39 | // [1] m = 1 40 | // a = b = im = 0, so okay 41 | 42 | // [2] m >= 2 43 | // im = ceil(2^64 / m) 44 | // -> im * m = 2^64 + r (0 <= r < m) 45 | // let z = a*b = c*m + d (0 <= c, d < m) 46 | // a*b * im = (c*m + d) * im = c*(im*m) + d*im = c*2^64 + c*r + d*im 47 | // c*r + d*im < m * m + m * im < m * m + 2^64 + m <= 2^64 + m * (m + 1) < 2^64 * 2 48 | // ((ab * im) >> 64) == c or c + 1 49 | unsigned long long z = a; 50 | z *= b; 51 | #ifdef _MSC_VER 52 | unsigned long long x; 53 | _umul128(z, im, &x); 54 | #else 55 | unsigned long long x = 56 | (unsigned long long)(((unsigned __int128)(z)*im) >> 64); 57 | #endif 58 | unsigned int v = (unsigned int)(z - x * _m); 59 | if (_m <= v) v += _m; 60 | return v; 61 | } 62 | }; 63 | 64 | // @param n `0 <= n` 65 | // @param m `1 <= m` 66 | // @return `(x ** n) % m` 67 | constexpr long long pow_mod_constexpr(long long x, long long n, int m) { 68 | if (m == 1) return 0; 69 | unsigned int _m = (unsigned int)(m); 70 | unsigned long long r = 1; 71 | unsigned long long y = safe_mod(x, m); 72 | while (n) { 73 | if (n & 1) r = (r * y) % _m; 74 | y = (y * y) % _m; 75 | n >>= 1; 76 | } 77 | return r; 78 | } 79 | 80 | // Reference: 81 | // M. Forisek and J. Jancina, 82 | // Fast Primality Testing for Integers That Fit into a Machine Word 83 | // @param n `0 <= n` 84 | constexpr bool is_prime_constexpr(int n) { 85 | if (n <= 1) return false; 86 | if (n == 2 || n == 7 || n == 61) return true; 87 | if (n % 2 == 0) return false; 88 | long long d = n - 1; 89 | while (d % 2 == 0) d /= 2; 90 | constexpr long long bases[3] = {2, 7, 61}; 91 | for (long long a : bases) { 92 | long long t = d; 93 | long long y = pow_mod_constexpr(a, t, n); 94 | while (t != n - 1 && y != 1 && y != n - 1) { 95 | y = y * y % n; 96 | t <<= 1; 97 | } 98 | if (y != n - 1 && t % 2 == 0) { 99 | return false; 100 | } 101 | } 102 | return true; 103 | } 104 | template constexpr bool is_prime = is_prime_constexpr(n); 105 | 106 | // @param b `1 <= b` 107 | // @return pair(g, x) s.t. g = gcd(a, b), xa = g (mod b), 0 <= x < b/g 108 | constexpr std::pair inv_gcd(long long a, long long b) { 109 | a = safe_mod(a, b); 110 | if (a == 0) return {b, 0}; 111 | 112 | // Contracts: 113 | // [1] s - m0 * a = 0 (mod b) 114 | // [2] t - m1 * a = 0 (mod b) 115 | // [3] s * |m1| + t * |m0| <= b 116 | long long s = b, t = a; 117 | long long m0 = 0, m1 = 1; 118 | 119 | while (t) { 120 | long long u = s / t; 121 | s -= t * u; 122 | m0 -= m1 * u; // |m1 * u| <= |m1| * s <= b 123 | 124 | // [3]: 125 | // (s - t * u) * |m1| + t * |m0 - m1 * u| 126 | // <= s * |m1| - t * u * |m1| + t * (|m0| + |m1| * u) 127 | // = s * |m1| + t * |m0| <= b 128 | 129 | auto tmp = s; 130 | s = t; 131 | t = tmp; 132 | tmp = m0; 133 | m0 = m1; 134 | m1 = tmp; 135 | } 136 | // by [3]: |m0| <= b/g 137 | // by g != b: |m0| < b/g 138 | if (m0 < 0) m0 += b / s; 139 | return {s, m0}; 140 | } 141 | 142 | // Compile time primitive root 143 | // @param m must be prime 144 | // @return primitive root (and minimum in now) 145 | constexpr int primitive_root_constexpr(int m) { 146 | if (m == 2) return 1; 147 | if (m == 167772161) return 3; 148 | if (m == 469762049) return 3; 149 | if (m == 754974721) return 11; 150 | if (m == 998244353) return 3; 151 | int divs[20] = {}; 152 | divs[0] = 2; 153 | int cnt = 1; 154 | int x = (m - 1) / 2; 155 | while (x % 2 == 0) x /= 2; 156 | for (int i = 3; (long long)(i)*i <= x; i += 2) { 157 | if (x % i == 0) { 158 | divs[cnt++] = i; 159 | while (x % i == 0) { 160 | x /= i; 161 | } 162 | } 163 | } 164 | if (x > 1) { 165 | divs[cnt++] = x; 166 | } 167 | for (int g = 2;; g++) { 168 | bool ok = true; 169 | for (int i = 0; i < cnt; i++) { 170 | if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) { 171 | ok = false; 172 | break; 173 | } 174 | } 175 | if (ok) return g; 176 | } 177 | } 178 | template constexpr int primitive_root = primitive_root_constexpr(m); 179 | 180 | // @param n `n < 2^32` 181 | // @param m `1 <= m < 2^32` 182 | // @return sum_{i=0}^{n-1} floor((ai + b) / m) (mod 2^64) 183 | unsigned long long floor_sum_unsigned(unsigned long long n, 184 | unsigned long long m, 185 | unsigned long long a, 186 | unsigned long long b) { 187 | unsigned long long ans = 0; 188 | while (true) { 189 | if (a >= m) { 190 | ans += n * (n - 1) / 2 * (a / m); 191 | a %= m; 192 | } 193 | if (b >= m) { 194 | ans += n * (b / m); 195 | b %= m; 196 | } 197 | 198 | unsigned long long y_max = a * n + b; 199 | if (y_max < m) break; 200 | // y_max < m * (n + 1) 201 | // floor(y_max / m) <= n 202 | n = (unsigned long long)(y_max / m); 203 | b = (unsigned long long)(y_max % m); 204 | std::swap(m, a); 205 | } 206 | return ans; 207 | } 208 | 209 | } // namespace internal 210 | 211 | } // namespace atcoder 212 | 213 | #endif // ATCODER_INTERNAL_MATH_HPP 214 | -------------------------------------------------------------------------------- /res/library/atcoder/internal_queue: -------------------------------------------------------------------------------- 1 | #include "atcoder/internal_queue.hpp" 2 | -------------------------------------------------------------------------------- /res/library/atcoder/internal_queue.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ATCODER_INTERNAL_QUEUE_HPP 2 | #define ATCODER_INTERNAL_QUEUE_HPP 1 3 | 4 | #include 5 | 6 | namespace atcoder { 7 | 8 | namespace internal { 9 | 10 | template struct simple_queue { 11 | std::vector payload; 12 | int pos = 0; 13 | void reserve(int n) { payload.reserve(n); } 14 | int size() const { return int(payload.size()) - pos; } 15 | bool empty() const { return pos == int(payload.size()); } 16 | void push(const T& t) { payload.push_back(t); } 17 | T& front() { return payload[pos]; } 18 | void clear() { 19 | payload.clear(); 20 | pos = 0; 21 | } 22 | void pop() { pos++; } 23 | }; 24 | 25 | } // namespace internal 26 | 27 | } // namespace atcoder 28 | 29 | #endif // ATCODER_INTERNAL_QUEUE_HPP 30 | -------------------------------------------------------------------------------- /res/library/atcoder/internal_scc: -------------------------------------------------------------------------------- 1 | #include "atcoder/internal_scc.hpp" 2 | -------------------------------------------------------------------------------- /res/library/atcoder/internal_scc.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ATCODER_INTERNAL_SCC_HPP 2 | #define ATCODER_INTERNAL_SCC_HPP 1 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "atcoder/internal_csr" 9 | 10 | namespace atcoder { 11 | namespace internal { 12 | 13 | // Reference: 14 | // R. Tarjan, 15 | // Depth-First Search and Linear Graph Algorithms 16 | struct scc_graph { 17 | public: 18 | explicit scc_graph(int n) : _n(n) {} 19 | 20 | int num_vertices() { return _n; } 21 | 22 | void add_edge(int from, int to) { edges.push_back({from, {to}}); } 23 | 24 | // @return pair of (# of scc, scc id) 25 | std::pair> scc_ids() { 26 | auto g = csr(_n, edges); 27 | int now_ord = 0, group_num = 0; 28 | std::vector visited, low(_n), ord(_n, -1), ids(_n); 29 | visited.reserve(_n); 30 | auto dfs = [&](auto self, int v) -> void { 31 | low[v] = ord[v] = now_ord++; 32 | visited.push_back(v); 33 | for (int i = g.start[v]; i < g.start[v + 1]; i++) { 34 | auto to = g.elist[i].to; 35 | if (ord[to] == -1) { 36 | self(self, to); 37 | low[v] = std::min(low[v], low[to]); 38 | } else { 39 | low[v] = std::min(low[v], ord[to]); 40 | } 41 | } 42 | if (low[v] == ord[v]) { 43 | while (true) { 44 | int u = visited.back(); 45 | visited.pop_back(); 46 | ord[u] = _n; 47 | ids[u] = group_num; 48 | if (u == v) break; 49 | } 50 | group_num++; 51 | } 52 | }; 53 | for (int i = 0; i < _n; i++) { 54 | if (ord[i] == -1) dfs(dfs, i); 55 | } 56 | for (auto& x : ids) { 57 | x = group_num - 1 - x; 58 | } 59 | return {group_num, ids}; 60 | } 61 | 62 | std::vector> scc() { 63 | auto ids = scc_ids(); 64 | int group_num = ids.first; 65 | std::vector counts(group_num); 66 | for (auto x : ids.second) counts[x]++; 67 | std::vector> groups(ids.first); 68 | for (int i = 0; i < group_num; i++) { 69 | groups[i].reserve(counts[i]); 70 | } 71 | for (int i = 0; i < _n; i++) { 72 | groups[ids.second[i]].push_back(i); 73 | } 74 | return groups; 75 | } 76 | 77 | private: 78 | int _n; 79 | struct edge { 80 | int to; 81 | }; 82 | std::vector> edges; 83 | }; 84 | 85 | } // namespace internal 86 | 87 | } // namespace atcoder 88 | 89 | #endif // ATCODER_INTERNAL_SCC_HPP 90 | -------------------------------------------------------------------------------- /res/library/atcoder/internal_type_traits: -------------------------------------------------------------------------------- 1 | #include "atcoder/internal_type_traits.hpp" 2 | -------------------------------------------------------------------------------- /res/library/atcoder/internal_type_traits.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ATCODER_INTERNAL_TYPE_TRAITS_HPP 2 | #define ATCODER_INTERNAL_TYPE_TRAITS_HPP 1 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace atcoder { 9 | 10 | namespace internal { 11 | 12 | #ifndef _MSC_VER 13 | template 14 | using is_signed_int128 = 15 | typename std::conditional::value || 16 | std::is_same::value, 17 | std::true_type, 18 | std::false_type>::type; 19 | 20 | template 21 | using is_unsigned_int128 = 22 | typename std::conditional::value || 23 | std::is_same::value, 24 | std::true_type, 25 | std::false_type>::type; 26 | 27 | template 28 | using make_unsigned_int128 = 29 | typename std::conditional::value, 30 | __uint128_t, 31 | unsigned __int128>; 32 | 33 | template 34 | using is_integral = typename std::conditional::value || 35 | is_signed_int128::value || 36 | is_unsigned_int128::value, 37 | std::true_type, 38 | std::false_type>::type; 39 | 40 | template 41 | using is_signed_int = typename std::conditional<(is_integral::value && 42 | std::is_signed::value) || 43 | is_signed_int128::value, 44 | std::true_type, 45 | std::false_type>::type; 46 | 47 | template 48 | using is_unsigned_int = 49 | typename std::conditional<(is_integral::value && 50 | std::is_unsigned::value) || 51 | is_unsigned_int128::value, 52 | std::true_type, 53 | std::false_type>::type; 54 | 55 | template 56 | using to_unsigned = typename std::conditional< 57 | is_signed_int128::value, 58 | make_unsigned_int128, 59 | typename std::conditional::value, 60 | std::make_unsigned, 61 | std::common_type>::type>::type; 62 | 63 | #else 64 | 65 | template using is_integral = typename std::is_integral; 66 | 67 | template 68 | using is_signed_int = 69 | typename std::conditional::value && std::is_signed::value, 70 | std::true_type, 71 | std::false_type>::type; 72 | 73 | template 74 | using is_unsigned_int = 75 | typename std::conditional::value && 76 | std::is_unsigned::value, 77 | std::true_type, 78 | std::false_type>::type; 79 | 80 | template 81 | using to_unsigned = typename std::conditional::value, 82 | std::make_unsigned, 83 | std::common_type>::type; 84 | 85 | #endif 86 | 87 | template 88 | using is_signed_int_t = std::enable_if_t::value>; 89 | 90 | template 91 | using is_unsigned_int_t = std::enable_if_t::value>; 92 | 93 | template using to_unsigned_t = typename to_unsigned::type; 94 | 95 | } // namespace internal 96 | 97 | } // namespace atcoder 98 | 99 | #endif // ATCODER_INTERNAL_TYPE_TRAITS_HPP 100 | -------------------------------------------------------------------------------- /res/library/atcoder/lazysegtree: -------------------------------------------------------------------------------- 1 | #include "atcoder/lazysegtree.hpp" 2 | -------------------------------------------------------------------------------- /res/library/atcoder/lazysegtree.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ATCODER_LAZYSEGTREE_HPP 2 | #define ATCODER_LAZYSEGTREE_HPP 1 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "atcoder/internal_bit" 10 | 11 | namespace atcoder { 12 | 13 | template 20 | struct lazy_segtree { 21 | public: 22 | lazy_segtree() : lazy_segtree(0) {} 23 | explicit lazy_segtree(int n) : lazy_segtree(std::vector(n, e())) {} 24 | explicit lazy_segtree(const std::vector& v) : _n(int(v.size())) { 25 | log = internal::ceil_pow2(_n); 26 | size = 1 << log; 27 | d = std::vector(2 * size, e()); 28 | lz = std::vector(size, id()); 29 | for (int i = 0; i < _n; i++) d[size + i] = v[i]; 30 | for (int i = size - 1; i >= 1; i--) { 31 | update(i); 32 | } 33 | } 34 | 35 | void set(int p, S x) { 36 | assert(0 <= p && p < _n); 37 | p += size; 38 | for (int i = log; i >= 1; i--) push(p >> i); 39 | d[p] = x; 40 | for (int i = 1; i <= log; i++) update(p >> i); 41 | } 42 | 43 | S get(int p) { 44 | assert(0 <= p && p < _n); 45 | p += size; 46 | for (int i = log; i >= 1; i--) push(p >> i); 47 | return d[p]; 48 | } 49 | 50 | S prod(int l, int r) { 51 | assert(0 <= l && l <= r && r <= _n); 52 | if (l == r) return e(); 53 | 54 | l += size; 55 | r += size; 56 | 57 | for (int i = log; i >= 1; i--) { 58 | if (((l >> i) << i) != l) push(l >> i); 59 | if (((r >> i) << i) != r) push((r - 1) >> i); 60 | } 61 | 62 | S sml = e(), smr = e(); 63 | while (l < r) { 64 | if (l & 1) sml = op(sml, d[l++]); 65 | if (r & 1) smr = op(d[--r], smr); 66 | l >>= 1; 67 | r >>= 1; 68 | } 69 | 70 | return op(sml, smr); 71 | } 72 | 73 | S all_prod() { return d[1]; } 74 | 75 | void apply(int p, F f) { 76 | assert(0 <= p && p < _n); 77 | p += size; 78 | for (int i = log; i >= 1; i--) push(p >> i); 79 | d[p] = mapping(f, d[p]); 80 | for (int i = 1; i <= log; i++) update(p >> i); 81 | } 82 | void apply(int l, int r, F f) { 83 | assert(0 <= l && l <= r && r <= _n); 84 | if (l == r) return; 85 | 86 | l += size; 87 | r += size; 88 | 89 | for (int i = log; i >= 1; i--) { 90 | if (((l >> i) << i) != l) push(l >> i); 91 | if (((r >> i) << i) != r) push((r - 1) >> i); 92 | } 93 | 94 | { 95 | int l2 = l, r2 = r; 96 | while (l < r) { 97 | if (l & 1) all_apply(l++, f); 98 | if (r & 1) all_apply(--r, f); 99 | l >>= 1; 100 | r >>= 1; 101 | } 102 | l = l2; 103 | r = r2; 104 | } 105 | 106 | for (int i = 1; i <= log; i++) { 107 | if (((l >> i) << i) != l) update(l >> i); 108 | if (((r >> i) << i) != r) update((r - 1) >> i); 109 | } 110 | } 111 | 112 | template int max_right(int l) { 113 | return max_right(l, [](S x) { return g(x); }); 114 | } 115 | template int max_right(int l, G g) { 116 | assert(0 <= l && l <= _n); 117 | assert(g(e())); 118 | if (l == _n) return _n; 119 | l += size; 120 | for (int i = log; i >= 1; i--) push(l >> i); 121 | S sm = e(); 122 | do { 123 | while (l % 2 == 0) l >>= 1; 124 | if (!g(op(sm, d[l]))) { 125 | while (l < size) { 126 | push(l); 127 | l = (2 * l); 128 | if (g(op(sm, d[l]))) { 129 | sm = op(sm, d[l]); 130 | l++; 131 | } 132 | } 133 | return l - size; 134 | } 135 | sm = op(sm, d[l]); 136 | l++; 137 | } while ((l & -l) != l); 138 | return _n; 139 | } 140 | 141 | template int min_left(int r) { 142 | return min_left(r, [](S x) { return g(x); }); 143 | } 144 | template int min_left(int r, G g) { 145 | assert(0 <= r && r <= _n); 146 | assert(g(e())); 147 | if (r == 0) return 0; 148 | r += size; 149 | for (int i = log; i >= 1; i--) push((r - 1) >> i); 150 | S sm = e(); 151 | do { 152 | r--; 153 | while (r > 1 && (r % 2)) r >>= 1; 154 | if (!g(op(d[r], sm))) { 155 | while (r < size) { 156 | push(r); 157 | r = (2 * r + 1); 158 | if (g(op(d[r], sm))) { 159 | sm = op(d[r], sm); 160 | r--; 161 | } 162 | } 163 | return r + 1 - size; 164 | } 165 | sm = op(d[r], sm); 166 | } while ((r & -r) != r); 167 | return 0; 168 | } 169 | 170 | private: 171 | int _n, size, log; 172 | std::vector d; 173 | std::vector lz; 174 | 175 | void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); } 176 | void all_apply(int k, F f) { 177 | d[k] = mapping(f, d[k]); 178 | if (k < size) lz[k] = composition(f, lz[k]); 179 | } 180 | void push(int k) { 181 | all_apply(2 * k, lz[k]); 182 | all_apply(2 * k + 1, lz[k]); 183 | lz[k] = id(); 184 | } 185 | }; 186 | 187 | } // namespace atcoder 188 | 189 | #endif // ATCODER_LAZYSEGTREE_HPP 190 | -------------------------------------------------------------------------------- /res/library/atcoder/math: -------------------------------------------------------------------------------- 1 | #include "atcoder/math.hpp" 2 | -------------------------------------------------------------------------------- /res/library/atcoder/math.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ATCODER_MATH_HPP 2 | #define ATCODER_MATH_HPP 1 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "atcoder/internal_math" 10 | 11 | namespace atcoder { 12 | 13 | long long pow_mod(long long x, long long n, int m) { 14 | assert(0 <= n && 1 <= m); 15 | if (m == 1) return 0; 16 | internal::barrett bt((unsigned int)(m)); 17 | unsigned int r = 1, y = (unsigned int)(internal::safe_mod(x, m)); 18 | while (n) { 19 | if (n & 1) r = bt.mul(r, y); 20 | y = bt.mul(y, y); 21 | n >>= 1; 22 | } 23 | return r; 24 | } 25 | 26 | long long inv_mod(long long x, long long m) { 27 | assert(1 <= m); 28 | auto z = internal::inv_gcd(x, m); 29 | assert(z.first == 1); 30 | return z.second; 31 | } 32 | 33 | // (rem, mod) 34 | std::pair crt(const std::vector& r, 35 | const std::vector& m) { 36 | assert(r.size() == m.size()); 37 | int n = int(r.size()); 38 | // Contracts: 0 <= r0 < m0 39 | long long r0 = 0, m0 = 1; 40 | for (int i = 0; i < n; i++) { 41 | assert(1 <= m[i]); 42 | long long r1 = internal::safe_mod(r[i], m[i]), m1 = m[i]; 43 | if (m0 < m1) { 44 | std::swap(r0, r1); 45 | std::swap(m0, m1); 46 | } 47 | if (m0 % m1 == 0) { 48 | if (r0 % m1 != r1) return {0, 0}; 49 | continue; 50 | } 51 | // assume: m0 > m1, lcm(m0, m1) >= 2 * max(m0, m1) 52 | 53 | // (r0, m0), (r1, m1) -> (r2, m2 = lcm(m0, m1)); 54 | // r2 % m0 = r0 55 | // r2 % m1 = r1 56 | // -> (r0 + x*m0) % m1 = r1 57 | // -> x*u0*g = r1-r0 (mod u1*g) (u0*g = m0, u1*g = m1) 58 | // -> x = (r1 - r0) / g * inv(u0) (mod u1) 59 | 60 | // im = inv(u0) (mod u1) (0 <= im < u1) 61 | long long g, im; 62 | std::tie(g, im) = internal::inv_gcd(m0, m1); 63 | 64 | long long u1 = (m1 / g); 65 | // |r1 - r0| < (m0 + m1) <= lcm(m0, m1) 66 | if ((r1 - r0) % g) return {0, 0}; 67 | 68 | // u1 * u1 <= m1 * m1 / g / g <= m0 * m1 / g = lcm(m0, m1) 69 | long long x = (r1 - r0) / g % u1 * im % u1; 70 | 71 | // |r0| + |m0 * x| 72 | // < m0 + m0 * (u1 - 1) 73 | // = m0 + m0 * m1 / g - m0 74 | // = lcm(m0, m1) 75 | r0 += x * m0; 76 | m0 *= u1; // -> lcm(m0, m1) 77 | if (r0 < 0) r0 += m0; 78 | } 79 | return {r0, m0}; 80 | } 81 | 82 | long long floor_sum(long long n, long long m, long long a, long long b) { 83 | assert(0 <= n && n < (1LL << 32)); 84 | assert(1 <= m && m < (1LL << 32)); 85 | unsigned long long ans = 0; 86 | if (a < 0) { 87 | unsigned long long a2 = internal::safe_mod(a, m); 88 | ans -= 1ULL * n * (n - 1) / 2 * ((a2 - a) / m); 89 | a = a2; 90 | } 91 | if (b < 0) { 92 | unsigned long long b2 = internal::safe_mod(b, m); 93 | ans -= 1ULL * n * ((b2 - b) / m); 94 | b = b2; 95 | } 96 | return ans + internal::floor_sum_unsigned(n, m, a, b); 97 | } 98 | 99 | } // namespace atcoder 100 | 101 | #endif // ATCODER_MATH_HPP 102 | -------------------------------------------------------------------------------- /res/library/atcoder/maxflow: -------------------------------------------------------------------------------- 1 | #include "atcoder/maxflow.hpp" 2 | -------------------------------------------------------------------------------- /res/library/atcoder/maxflow.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ATCODER_MAXFLOW_HPP 2 | #define ATCODER_MAXFLOW_HPP 1 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "atcoder/internal_queue" 11 | 12 | namespace atcoder { 13 | 14 | template struct mf_graph { 15 | public: 16 | mf_graph() : _n(0) {} 17 | explicit mf_graph(int n) : _n(n), g(n) {} 18 | 19 | int add_edge(int from, int to, Cap cap) { 20 | assert(0 <= from && from < _n); 21 | assert(0 <= to && to < _n); 22 | assert(0 <= cap); 23 | int m = int(pos.size()); 24 | pos.push_back({from, int(g[from].size())}); 25 | int from_id = int(g[from].size()); 26 | int to_id = int(g[to].size()); 27 | if (from == to) to_id++; 28 | g[from].push_back(_edge{to, to_id, cap}); 29 | g[to].push_back(_edge{from, from_id, 0}); 30 | return m; 31 | } 32 | 33 | struct edge { 34 | int from, to; 35 | Cap cap, flow; 36 | }; 37 | 38 | edge get_edge(int i) { 39 | int m = int(pos.size()); 40 | assert(0 <= i && i < m); 41 | auto _e = g[pos[i].first][pos[i].second]; 42 | auto _re = g[_e.to][_e.rev]; 43 | return edge{pos[i].first, _e.to, _e.cap + _re.cap, _re.cap}; 44 | } 45 | std::vector edges() { 46 | int m = int(pos.size()); 47 | std::vector result; 48 | for (int i = 0; i < m; i++) { 49 | result.push_back(get_edge(i)); 50 | } 51 | return result; 52 | } 53 | void change_edge(int i, Cap new_cap, Cap new_flow) { 54 | int m = int(pos.size()); 55 | assert(0 <= i && i < m); 56 | assert(0 <= new_flow && new_flow <= new_cap); 57 | auto& _e = g[pos[i].first][pos[i].second]; 58 | auto& _re = g[_e.to][_e.rev]; 59 | _e.cap = new_cap - new_flow; 60 | _re.cap = new_flow; 61 | } 62 | 63 | Cap flow(int s, int t) { 64 | return flow(s, t, std::numeric_limits::max()); 65 | } 66 | Cap flow(int s, int t, Cap flow_limit) { 67 | assert(0 <= s && s < _n); 68 | assert(0 <= t && t < _n); 69 | assert(s != t); 70 | 71 | std::vector level(_n), iter(_n); 72 | internal::simple_queue que; 73 | 74 | auto bfs = [&]() { 75 | std::fill(level.begin(), level.end(), -1); 76 | level[s] = 0; 77 | que.clear(); 78 | que.push(s); 79 | while (!que.empty()) { 80 | int v = que.front(); 81 | que.pop(); 82 | for (auto e : g[v]) { 83 | if (e.cap == 0 || level[e.to] >= 0) continue; 84 | level[e.to] = level[v] + 1; 85 | if (e.to == t) return; 86 | que.push(e.to); 87 | } 88 | } 89 | }; 90 | auto dfs = [&](auto self, int v, Cap up) { 91 | if (v == s) return up; 92 | Cap res = 0; 93 | int level_v = level[v]; 94 | for (int& i = iter[v]; i < int(g[v].size()); i++) { 95 | _edge& e = g[v][i]; 96 | if (level_v <= level[e.to] || g[e.to][e.rev].cap == 0) continue; 97 | Cap d = 98 | self(self, e.to, std::min(up - res, g[e.to][e.rev].cap)); 99 | if (d <= 0) continue; 100 | g[v][i].cap += d; 101 | g[e.to][e.rev].cap -= d; 102 | res += d; 103 | if (res == up) return res; 104 | } 105 | level[v] = _n; 106 | return res; 107 | }; 108 | 109 | Cap flow = 0; 110 | while (flow < flow_limit) { 111 | bfs(); 112 | if (level[t] == -1) break; 113 | std::fill(iter.begin(), iter.end(), 0); 114 | Cap f = dfs(dfs, t, flow_limit - flow); 115 | if (!f) break; 116 | flow += f; 117 | } 118 | return flow; 119 | } 120 | 121 | std::vector min_cut(int s) { 122 | std::vector visited(_n); 123 | internal::simple_queue que; 124 | que.push(s); 125 | while (!que.empty()) { 126 | int p = que.front(); 127 | que.pop(); 128 | visited[p] = true; 129 | for (auto e : g[p]) { 130 | if (e.cap && !visited[e.to]) { 131 | visited[e.to] = true; 132 | que.push(e.to); 133 | } 134 | } 135 | } 136 | return visited; 137 | } 138 | 139 | private: 140 | int _n; 141 | struct _edge { 142 | int to, rev; 143 | Cap cap; 144 | }; 145 | std::vector> pos; 146 | std::vector> g; 147 | }; 148 | 149 | } // namespace atcoder 150 | 151 | #endif // ATCODER_MAXFLOW_HPP 152 | -------------------------------------------------------------------------------- /res/library/atcoder/mincostflow: -------------------------------------------------------------------------------- 1 | #include "atcoder/mincostflow.hpp" 2 | -------------------------------------------------------------------------------- /res/library/atcoder/mincostflow.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ATCODER_MINCOSTFLOW_HPP 2 | #define ATCODER_MINCOSTFLOW_HPP 1 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "atcoder/internal_csr" 11 | #include "atcoder/internal_queue" 12 | 13 | namespace atcoder { 14 | 15 | template struct mcf_graph { 16 | public: 17 | mcf_graph() {} 18 | explicit mcf_graph(int n) : _n(n) {} 19 | 20 | int add_edge(int from, int to, Cap cap, Cost cost) { 21 | assert(0 <= from && from < _n); 22 | assert(0 <= to && to < _n); 23 | assert(0 <= cap); 24 | assert(0 <= cost); 25 | int m = int(_edges.size()); 26 | _edges.push_back({from, to, cap, 0, cost}); 27 | return m; 28 | } 29 | 30 | struct edge { 31 | int from, to; 32 | Cap cap, flow; 33 | Cost cost; 34 | }; 35 | 36 | edge get_edge(int i) { 37 | int m = int(_edges.size()); 38 | assert(0 <= i && i < m); 39 | return _edges[i]; 40 | } 41 | std::vector edges() { return _edges; } 42 | 43 | std::pair flow(int s, int t) { 44 | return flow(s, t, std::numeric_limits::max()); 45 | } 46 | std::pair flow(int s, int t, Cap flow_limit) { 47 | return slope(s, t, flow_limit).back(); 48 | } 49 | std::vector> slope(int s, int t) { 50 | return slope(s, t, std::numeric_limits::max()); 51 | } 52 | std::vector> slope(int s, int t, Cap flow_limit) { 53 | assert(0 <= s && s < _n); 54 | assert(0 <= t && t < _n); 55 | assert(s != t); 56 | 57 | int m = int(_edges.size()); 58 | std::vector edge_idx(m); 59 | 60 | auto g = [&]() { 61 | std::vector degree(_n), redge_idx(m); 62 | std::vector> elist; 63 | elist.reserve(2 * m); 64 | for (int i = 0; i < m; i++) { 65 | auto e = _edges[i]; 66 | edge_idx[i] = degree[e.from]++; 67 | redge_idx[i] = degree[e.to]++; 68 | elist.push_back({e.from, {e.to, -1, e.cap - e.flow, e.cost}}); 69 | elist.push_back({e.to, {e.from, -1, e.flow, -e.cost}}); 70 | } 71 | auto _g = internal::csr<_edge>(_n, elist); 72 | for (int i = 0; i < m; i++) { 73 | auto e = _edges[i]; 74 | edge_idx[i] += _g.start[e.from]; 75 | redge_idx[i] += _g.start[e.to]; 76 | _g.elist[edge_idx[i]].rev = redge_idx[i]; 77 | _g.elist[redge_idx[i]].rev = edge_idx[i]; 78 | } 79 | return _g; 80 | }(); 81 | 82 | auto result = slope(g, s, t, flow_limit); 83 | 84 | for (int i = 0; i < m; i++) { 85 | auto e = g.elist[edge_idx[i]]; 86 | _edges[i].flow = _edges[i].cap - e.cap; 87 | } 88 | 89 | return result; 90 | } 91 | 92 | private: 93 | int _n; 94 | std::vector _edges; 95 | 96 | // inside edge 97 | struct _edge { 98 | int to, rev; 99 | Cap cap; 100 | Cost cost; 101 | }; 102 | 103 | std::vector> slope(internal::csr<_edge>& g, 104 | int s, 105 | int t, 106 | Cap flow_limit) { 107 | // variants (C = maxcost): 108 | // -(n-1)C <= dual[s] <= dual[i] <= dual[t] = 0 109 | // reduced cost (= e.cost + dual[e.from] - dual[e.to]) >= 0 for all edge 110 | 111 | // dual_dist[i] = (dual[i], dist[i]) 112 | std::vector> dual_dist(_n); 113 | std::vector prev_e(_n); 114 | std::vector vis(_n); 115 | struct Q { 116 | Cost key; 117 | int to; 118 | bool operator<(Q r) const { return key > r.key; } 119 | }; 120 | std::vector que_min; 121 | std::vector que; 122 | auto dual_ref = [&]() { 123 | for (int i = 0; i < _n; i++) { 124 | dual_dist[i].second = std::numeric_limits::max(); 125 | } 126 | std::fill(vis.begin(), vis.end(), false); 127 | que_min.clear(); 128 | que.clear(); 129 | 130 | // que[0..heap_r) was heapified 131 | size_t heap_r = 0; 132 | 133 | dual_dist[s].second = 0; 134 | que_min.push_back(s); 135 | while (!que_min.empty() || !que.empty()) { 136 | int v; 137 | if (!que_min.empty()) { 138 | v = que_min.back(); 139 | que_min.pop_back(); 140 | } else { 141 | while (heap_r < que.size()) { 142 | heap_r++; 143 | std::push_heap(que.begin(), que.begin() + heap_r); 144 | } 145 | v = que.front().to; 146 | std::pop_heap(que.begin(), que.end()); 147 | que.pop_back(); 148 | heap_r--; 149 | } 150 | if (vis[v]) continue; 151 | vis[v] = true; 152 | if (v == t) break; 153 | // dist[v] = shortest(s, v) + dual[s] - dual[v] 154 | // dist[v] >= 0 (all reduced cost are positive) 155 | // dist[v] <= (n-1)C 156 | Cost dual_v = dual_dist[v].first, dist_v = dual_dist[v].second; 157 | for (int i = g.start[v]; i < g.start[v + 1]; i++) { 158 | auto e = g.elist[i]; 159 | if (!e.cap) continue; 160 | // |-dual[e.to] + dual[v]| <= (n-1)C 161 | // cost <= C - -(n-1)C + 0 = nC 162 | Cost cost = e.cost - dual_dist[e.to].first + dual_v; 163 | if (dual_dist[e.to].second - dist_v > cost) { 164 | Cost dist_to = dist_v + cost; 165 | dual_dist[e.to].second = dist_to; 166 | prev_e[e.to] = e.rev; 167 | if (dist_to == dist_v) { 168 | que_min.push_back(e.to); 169 | } else { 170 | que.push_back(Q{dist_to, e.to}); 171 | } 172 | } 173 | } 174 | } 175 | if (!vis[t]) { 176 | return false; 177 | } 178 | 179 | for (int v = 0; v < _n; v++) { 180 | if (!vis[v]) continue; 181 | // dual[v] = dual[v] - dist[t] + dist[v] 182 | // = dual[v] - (shortest(s, t) + dual[s] - dual[t]) + 183 | // (shortest(s, v) + dual[s] - dual[v]) = - shortest(s, 184 | // t) + dual[t] + shortest(s, v) = shortest(s, v) - 185 | // shortest(s, t) >= 0 - (n-1)C 186 | dual_dist[v].first -= dual_dist[t].second - dual_dist[v].second; 187 | } 188 | return true; 189 | }; 190 | Cap flow = 0; 191 | Cost cost = 0, prev_cost_per_flow = -1; 192 | std::vector> result = {{Cap(0), Cost(0)}}; 193 | while (flow < flow_limit) { 194 | if (!dual_ref()) break; 195 | Cap c = flow_limit - flow; 196 | for (int v = t; v != s; v = g.elist[prev_e[v]].to) { 197 | c = std::min(c, g.elist[g.elist[prev_e[v]].rev].cap); 198 | } 199 | for (int v = t; v != s; v = g.elist[prev_e[v]].to) { 200 | auto& e = g.elist[prev_e[v]]; 201 | e.cap += c; 202 | g.elist[e.rev].cap -= c; 203 | } 204 | Cost d = -dual_dist[s].first; 205 | flow += c; 206 | cost += c * d; 207 | if (prev_cost_per_flow == d) { 208 | result.pop_back(); 209 | } 210 | result.push_back({flow, cost}); 211 | prev_cost_per_flow = d; 212 | } 213 | return result; 214 | } 215 | }; 216 | 217 | } // namespace atcoder 218 | 219 | #endif // ATCODER_MINCOSTFLOW_HPP 220 | -------------------------------------------------------------------------------- /res/library/atcoder/modint: -------------------------------------------------------------------------------- 1 | #include "atcoder/modint.hpp" 2 | -------------------------------------------------------------------------------- /res/library/atcoder/modint.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ATCODER_MODINT_HPP 2 | #define ATCODER_MODINT_HPP 1 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef _MSC_VER 9 | #include 10 | #endif 11 | 12 | #include "atcoder/internal_math" 13 | #include "atcoder/internal_type_traits" 14 | 15 | namespace atcoder { 16 | 17 | namespace internal { 18 | 19 | struct modint_base {}; 20 | struct static_modint_base : modint_base {}; 21 | 22 | template using is_modint = std::is_base_of; 23 | template using is_modint_t = std::enable_if_t::value>; 24 | 25 | } // namespace internal 26 | 27 | template * = nullptr> 28 | struct static_modint : internal::static_modint_base { 29 | using mint = static_modint; 30 | 31 | public: 32 | static constexpr int mod() { return m; } 33 | static mint raw(int v) { 34 | mint x; 35 | x._v = v; 36 | return x; 37 | } 38 | 39 | static_modint() : _v(0) {} 40 | template * = nullptr> 41 | static_modint(T v) { 42 | long long x = (long long)(v % (long long)(umod())); 43 | if (x < 0) x += umod(); 44 | _v = (unsigned int)(x); 45 | } 46 | template * = nullptr> 47 | static_modint(T v) { 48 | _v = (unsigned int)(v % umod()); 49 | } 50 | 51 | unsigned int val() const { return _v; } 52 | 53 | mint& operator++() { 54 | _v++; 55 | if (_v == umod()) _v = 0; 56 | return *this; 57 | } 58 | mint& operator--() { 59 | if (_v == 0) _v = umod(); 60 | _v--; 61 | return *this; 62 | } 63 | mint operator++(int) { 64 | mint result = *this; 65 | ++*this; 66 | return result; 67 | } 68 | mint operator--(int) { 69 | mint result = *this; 70 | --*this; 71 | return result; 72 | } 73 | 74 | mint& operator+=(const mint& rhs) { 75 | _v += rhs._v; 76 | if (_v >= umod()) _v -= umod(); 77 | return *this; 78 | } 79 | mint& operator-=(const mint& rhs) { 80 | _v -= rhs._v; 81 | if (_v >= umod()) _v += umod(); 82 | return *this; 83 | } 84 | mint& operator*=(const mint& rhs) { 85 | unsigned long long z = _v; 86 | z *= rhs._v; 87 | _v = (unsigned int)(z % umod()); 88 | return *this; 89 | } 90 | mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); } 91 | 92 | mint operator+() const { return *this; } 93 | mint operator-() const { return mint() - *this; } 94 | 95 | mint pow(long long n) const { 96 | assert(0 <= n); 97 | mint x = *this, r = 1; 98 | while (n) { 99 | if (n & 1) r *= x; 100 | x *= x; 101 | n >>= 1; 102 | } 103 | return r; 104 | } 105 | mint inv() const { 106 | if (prime) { 107 | assert(_v); 108 | return pow(umod() - 2); 109 | } else { 110 | auto eg = internal::inv_gcd(_v, m); 111 | assert(eg.first == 1); 112 | return eg.second; 113 | } 114 | } 115 | 116 | friend mint operator+(const mint& lhs, const mint& rhs) { 117 | return mint(lhs) += rhs; 118 | } 119 | friend mint operator-(const mint& lhs, const mint& rhs) { 120 | return mint(lhs) -= rhs; 121 | } 122 | friend mint operator*(const mint& lhs, const mint& rhs) { 123 | return mint(lhs) *= rhs; 124 | } 125 | friend mint operator/(const mint& lhs, const mint& rhs) { 126 | return mint(lhs) /= rhs; 127 | } 128 | friend bool operator==(const mint& lhs, const mint& rhs) { 129 | return lhs._v == rhs._v; 130 | } 131 | friend bool operator!=(const mint& lhs, const mint& rhs) { 132 | return lhs._v != rhs._v; 133 | } 134 | 135 | private: 136 | unsigned int _v; 137 | static constexpr unsigned int umod() { return m; } 138 | static constexpr bool prime = internal::is_prime; 139 | }; 140 | 141 | template struct dynamic_modint : internal::modint_base { 142 | using mint = dynamic_modint; 143 | 144 | public: 145 | static int mod() { return (int)(bt.umod()); } 146 | static void set_mod(int m) { 147 | assert(1 <= m); 148 | bt = internal::barrett(m); 149 | } 150 | static mint raw(int v) { 151 | mint x; 152 | x._v = v; 153 | return x; 154 | } 155 | 156 | dynamic_modint() : _v(0) {} 157 | template * = nullptr> 158 | dynamic_modint(T v) { 159 | long long x = (long long)(v % (long long)(mod())); 160 | if (x < 0) x += mod(); 161 | _v = (unsigned int)(x); 162 | } 163 | template * = nullptr> 164 | dynamic_modint(T v) { 165 | _v = (unsigned int)(v % mod()); 166 | } 167 | 168 | unsigned int val() const { return _v; } 169 | 170 | mint& operator++() { 171 | _v++; 172 | if (_v == umod()) _v = 0; 173 | return *this; 174 | } 175 | mint& operator--() { 176 | if (_v == 0) _v = umod(); 177 | _v--; 178 | return *this; 179 | } 180 | mint operator++(int) { 181 | mint result = *this; 182 | ++*this; 183 | return result; 184 | } 185 | mint operator--(int) { 186 | mint result = *this; 187 | --*this; 188 | return result; 189 | } 190 | 191 | mint& operator+=(const mint& rhs) { 192 | _v += rhs._v; 193 | if (_v >= umod()) _v -= umod(); 194 | return *this; 195 | } 196 | mint& operator-=(const mint& rhs) { 197 | _v += mod() - rhs._v; 198 | if (_v >= umod()) _v -= umod(); 199 | return *this; 200 | } 201 | mint& operator*=(const mint& rhs) { 202 | _v = bt.mul(_v, rhs._v); 203 | return *this; 204 | } 205 | mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); } 206 | 207 | mint operator+() const { return *this; } 208 | mint operator-() const { return mint() - *this; } 209 | 210 | mint pow(long long n) const { 211 | assert(0 <= n); 212 | mint x = *this, r = 1; 213 | while (n) { 214 | if (n & 1) r *= x; 215 | x *= x; 216 | n >>= 1; 217 | } 218 | return r; 219 | } 220 | mint inv() const { 221 | auto eg = internal::inv_gcd(_v, mod()); 222 | assert(eg.first == 1); 223 | return eg.second; 224 | } 225 | 226 | friend mint operator+(const mint& lhs, const mint& rhs) { 227 | return mint(lhs) += rhs; 228 | } 229 | friend mint operator-(const mint& lhs, const mint& rhs) { 230 | return mint(lhs) -= rhs; 231 | } 232 | friend mint operator*(const mint& lhs, const mint& rhs) { 233 | return mint(lhs) *= rhs; 234 | } 235 | friend mint operator/(const mint& lhs, const mint& rhs) { 236 | return mint(lhs) /= rhs; 237 | } 238 | friend bool operator==(const mint& lhs, const mint& rhs) { 239 | return lhs._v == rhs._v; 240 | } 241 | friend bool operator!=(const mint& lhs, const mint& rhs) { 242 | return lhs._v != rhs._v; 243 | } 244 | 245 | private: 246 | unsigned int _v; 247 | static internal::barrett bt; 248 | static unsigned int umod() { return bt.umod(); } 249 | }; 250 | template internal::barrett dynamic_modint::bt(998244353); 251 | 252 | using modint998244353 = static_modint<998244353>; 253 | using modint1000000007 = static_modint<1000000007>; 254 | using modint = dynamic_modint<-1>; 255 | 256 | namespace internal { 257 | 258 | template 259 | using is_static_modint = std::is_base_of; 260 | 261 | template 262 | using is_static_modint_t = std::enable_if_t::value>; 263 | 264 | template struct is_dynamic_modint : public std::false_type {}; 265 | template 266 | struct is_dynamic_modint> : public std::true_type {}; 267 | 268 | template 269 | using is_dynamic_modint_t = std::enable_if_t::value>; 270 | 271 | } // namespace internal 272 | 273 | } // namespace atcoder 274 | 275 | #endif // ATCODER_MODINT_HPP 276 | -------------------------------------------------------------------------------- /res/library/atcoder/scc: -------------------------------------------------------------------------------- 1 | #include "atcoder/scc.hpp" 2 | -------------------------------------------------------------------------------- /res/library/atcoder/scc.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ATCODER_SCC_HPP 2 | #define ATCODER_SCC_HPP 1 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "atcoder/internal_scc" 9 | 10 | namespace atcoder { 11 | 12 | struct scc_graph { 13 | public: 14 | scc_graph() : internal(0) {} 15 | explicit scc_graph(int n) : internal(n) {} 16 | 17 | void add_edge(int from, int to) { 18 | int n = internal.num_vertices(); 19 | assert(0 <= from && from < n); 20 | assert(0 <= to && to < n); 21 | internal.add_edge(from, to); 22 | } 23 | 24 | std::vector> scc() { return internal.scc(); } 25 | 26 | private: 27 | internal::scc_graph internal; 28 | }; 29 | 30 | } // namespace atcoder 31 | 32 | #endif // ATCODER_SCC_HPP 33 | -------------------------------------------------------------------------------- /res/library/atcoder/segtree: -------------------------------------------------------------------------------- 1 | #include "atcoder/segtree.hpp" 2 | -------------------------------------------------------------------------------- /res/library/atcoder/segtree.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ATCODER_SEGTREE_HPP 2 | #define ATCODER_SEGTREE_HPP 1 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "atcoder/internal_bit" 9 | 10 | namespace atcoder { 11 | 12 | template struct segtree { 13 | public: 14 | segtree() : segtree(0) {} 15 | explicit segtree(int n) : segtree(std::vector(n, e())) {} 16 | explicit segtree(const std::vector& v) : _n(int(v.size())) { 17 | log = internal::ceil_pow2(_n); 18 | size = 1 << log; 19 | d = std::vector(2 * size, e()); 20 | for (int i = 0; i < _n; i++) d[size + i] = v[i]; 21 | for (int i = size - 1; i >= 1; i--) { 22 | update(i); 23 | } 24 | } 25 | 26 | void set(int p, S x) { 27 | assert(0 <= p && p < _n); 28 | p += size; 29 | d[p] = x; 30 | for (int i = 1; i <= log; i++) update(p >> i); 31 | } 32 | 33 | S get(int p) const { 34 | assert(0 <= p && p < _n); 35 | return d[p + size]; 36 | } 37 | 38 | S prod(int l, int r) const { 39 | assert(0 <= l && l <= r && r <= _n); 40 | S sml = e(), smr = e(); 41 | l += size; 42 | r += size; 43 | 44 | while (l < r) { 45 | if (l & 1) sml = op(sml, d[l++]); 46 | if (r & 1) smr = op(d[--r], smr); 47 | l >>= 1; 48 | r >>= 1; 49 | } 50 | return op(sml, smr); 51 | } 52 | 53 | S all_prod() const { return d[1]; } 54 | 55 | template int max_right(int l) const { 56 | return max_right(l, [](S x) { return f(x); }); 57 | } 58 | template int max_right(int l, F f) const { 59 | assert(0 <= l && l <= _n); 60 | assert(f(e())); 61 | if (l == _n) return _n; 62 | l += size; 63 | S sm = e(); 64 | do { 65 | while (l % 2 == 0) l >>= 1; 66 | if (!f(op(sm, d[l]))) { 67 | while (l < size) { 68 | l = (2 * l); 69 | if (f(op(sm, d[l]))) { 70 | sm = op(sm, d[l]); 71 | l++; 72 | } 73 | } 74 | return l - size; 75 | } 76 | sm = op(sm, d[l]); 77 | l++; 78 | } while ((l & -l) != l); 79 | return _n; 80 | } 81 | 82 | template int min_left(int r) const { 83 | return min_left(r, [](S x) { return f(x); }); 84 | } 85 | template int min_left(int r, F f) const { 86 | assert(0 <= r && r <= _n); 87 | assert(f(e())); 88 | if (r == 0) return 0; 89 | r += size; 90 | S sm = e(); 91 | do { 92 | r--; 93 | while (r > 1 && (r % 2)) r >>= 1; 94 | if (!f(op(d[r], sm))) { 95 | while (r < size) { 96 | r = (2 * r + 1); 97 | if (f(op(d[r], sm))) { 98 | sm = op(d[r], sm); 99 | r--; 100 | } 101 | } 102 | return r + 1 - size; 103 | } 104 | sm = op(d[r], sm); 105 | } while ((r & -r) != r); 106 | return 0; 107 | } 108 | 109 | private: 110 | int _n, size, log; 111 | std::vector d; 112 | 113 | void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); } 114 | }; 115 | 116 | } // namespace atcoder 117 | 118 | #endif // ATCODER_SEGTREE_HPP 119 | -------------------------------------------------------------------------------- /res/library/atcoder/string: -------------------------------------------------------------------------------- 1 | #include "atcoder/string.hpp" 2 | -------------------------------------------------------------------------------- /res/library/atcoder/string.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ATCODER_STRING_HPP 2 | #define ATCODER_STRING_HPP 1 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace atcoder { 11 | 12 | namespace internal { 13 | 14 | std::vector sa_naive(const std::vector& s) { 15 | int n = int(s.size()); 16 | std::vector sa(n); 17 | std::iota(sa.begin(), sa.end(), 0); 18 | std::sort(sa.begin(), sa.end(), [&](int l, int r) { 19 | if (l == r) return false; 20 | while (l < n && r < n) { 21 | if (s[l] != s[r]) return s[l] < s[r]; 22 | l++; 23 | r++; 24 | } 25 | return l == n; 26 | }); 27 | return sa; 28 | } 29 | 30 | std::vector sa_doubling(const std::vector& s) { 31 | int n = int(s.size()); 32 | std::vector sa(n), rnk = s, tmp(n); 33 | std::iota(sa.begin(), sa.end(), 0); 34 | for (int k = 1; k < n; k *= 2) { 35 | auto cmp = [&](int x, int y) { 36 | if (rnk[x] != rnk[y]) return rnk[x] < rnk[y]; 37 | int rx = x + k < n ? rnk[x + k] : -1; 38 | int ry = y + k < n ? rnk[y + k] : -1; 39 | return rx < ry; 40 | }; 41 | std::sort(sa.begin(), sa.end(), cmp); 42 | tmp[sa[0]] = 0; 43 | for (int i = 1; i < n; i++) { 44 | tmp[sa[i]] = tmp[sa[i - 1]] + (cmp(sa[i - 1], sa[i]) ? 1 : 0); 45 | } 46 | std::swap(tmp, rnk); 47 | } 48 | return sa; 49 | } 50 | 51 | // SA-IS, linear-time suffix array construction 52 | // Reference: 53 | // G. Nong, S. Zhang, and W. H. Chan, 54 | // Two Efficient Algorithms for Linear Time Suffix Array Construction 55 | template 56 | std::vector sa_is(const std::vector& s, int upper) { 57 | int n = int(s.size()); 58 | if (n == 0) return {}; 59 | if (n == 1) return {0}; 60 | if (n == 2) { 61 | if (s[0] < s[1]) { 62 | return {0, 1}; 63 | } else { 64 | return {1, 0}; 65 | } 66 | } 67 | if (n < THRESHOLD_NAIVE) { 68 | return sa_naive(s); 69 | } 70 | if (n < THRESHOLD_DOUBLING) { 71 | return sa_doubling(s); 72 | } 73 | 74 | std::vector sa(n); 75 | std::vector ls(n); 76 | for (int i = n - 2; i >= 0; i--) { 77 | ls[i] = (s[i] == s[i + 1]) ? ls[i + 1] : (s[i] < s[i + 1]); 78 | } 79 | std::vector sum_l(upper + 1), sum_s(upper + 1); 80 | for (int i = 0; i < n; i++) { 81 | if (!ls[i]) { 82 | sum_s[s[i]]++; 83 | } else { 84 | sum_l[s[i] + 1]++; 85 | } 86 | } 87 | for (int i = 0; i <= upper; i++) { 88 | sum_s[i] += sum_l[i]; 89 | if (i < upper) sum_l[i + 1] += sum_s[i]; 90 | } 91 | 92 | auto induce = [&](const std::vector& lms) { 93 | std::fill(sa.begin(), sa.end(), -1); 94 | std::vector buf(upper + 1); 95 | std::copy(sum_s.begin(), sum_s.end(), buf.begin()); 96 | for (auto d : lms) { 97 | if (d == n) continue; 98 | sa[buf[s[d]]++] = d; 99 | } 100 | std::copy(sum_l.begin(), sum_l.end(), buf.begin()); 101 | sa[buf[s[n - 1]]++] = n - 1; 102 | for (int i = 0; i < n; i++) { 103 | int v = sa[i]; 104 | if (v >= 1 && !ls[v - 1]) { 105 | sa[buf[s[v - 1]]++] = v - 1; 106 | } 107 | } 108 | std::copy(sum_l.begin(), sum_l.end(), buf.begin()); 109 | for (int i = n - 1; i >= 0; i--) { 110 | int v = sa[i]; 111 | if (v >= 1 && ls[v - 1]) { 112 | sa[--buf[s[v - 1] + 1]] = v - 1; 113 | } 114 | } 115 | }; 116 | 117 | std::vector lms_map(n + 1, -1); 118 | int m = 0; 119 | for (int i = 1; i < n; i++) { 120 | if (!ls[i - 1] && ls[i]) { 121 | lms_map[i] = m++; 122 | } 123 | } 124 | std::vector lms; 125 | lms.reserve(m); 126 | for (int i = 1; i < n; i++) { 127 | if (!ls[i - 1] && ls[i]) { 128 | lms.push_back(i); 129 | } 130 | } 131 | 132 | induce(lms); 133 | 134 | if (m) { 135 | std::vector sorted_lms; 136 | sorted_lms.reserve(m); 137 | for (int v : sa) { 138 | if (lms_map[v] != -1) sorted_lms.push_back(v); 139 | } 140 | std::vector rec_s(m); 141 | int rec_upper = 0; 142 | rec_s[lms_map[sorted_lms[0]]] = 0; 143 | for (int i = 1; i < m; i++) { 144 | int l = sorted_lms[i - 1], r = sorted_lms[i]; 145 | int end_l = (lms_map[l] + 1 < m) ? lms[lms_map[l] + 1] : n; 146 | int end_r = (lms_map[r] + 1 < m) ? lms[lms_map[r] + 1] : n; 147 | bool same = true; 148 | if (end_l - l != end_r - r) { 149 | same = false; 150 | } else { 151 | while (l < end_l) { 152 | if (s[l] != s[r]) { 153 | break; 154 | } 155 | l++; 156 | r++; 157 | } 158 | if (l == n || s[l] != s[r]) same = false; 159 | } 160 | if (!same) rec_upper++; 161 | rec_s[lms_map[sorted_lms[i]]] = rec_upper; 162 | } 163 | 164 | auto rec_sa = 165 | sa_is(rec_s, rec_upper); 166 | 167 | for (int i = 0; i < m; i++) { 168 | sorted_lms[i] = lms[rec_sa[i]]; 169 | } 170 | induce(sorted_lms); 171 | } 172 | return sa; 173 | } 174 | 175 | } // namespace internal 176 | 177 | std::vector suffix_array(const std::vector& s, int upper) { 178 | assert(0 <= upper); 179 | for (int d : s) { 180 | assert(0 <= d && d <= upper); 181 | } 182 | auto sa = internal::sa_is(s, upper); 183 | return sa; 184 | } 185 | 186 | template std::vector suffix_array(const std::vector& s) { 187 | int n = int(s.size()); 188 | std::vector idx(n); 189 | iota(idx.begin(), idx.end(), 0); 190 | sort(idx.begin(), idx.end(), [&](int l, int r) { return s[l] < s[r]; }); 191 | std::vector s2(n); 192 | int now = 0; 193 | for (int i = 0; i < n; i++) { 194 | if (i && s[idx[i - 1]] != s[idx[i]]) now++; 195 | s2[idx[i]] = now; 196 | } 197 | return internal::sa_is(s2, now); 198 | } 199 | 200 | std::vector suffix_array(const std::string& s) { 201 | int n = int(s.size()); 202 | std::vector s2(n); 203 | for (int i = 0; i < n; i++) { 204 | s2[i] = s[i]; 205 | } 206 | return internal::sa_is(s2, 255); 207 | } 208 | 209 | // Reference: 210 | // T. Kasai, G. Lee, H. Arimura, S. Arikawa, and K. Park, 211 | // Linear-Time Longest-Common-Prefix Computation in Suffix Arrays and Its 212 | // Applications 213 | template 214 | std::vector lcp_array(const std::vector& s, 215 | const std::vector& sa) { 216 | int n = int(s.size()); 217 | assert(n >= 1); 218 | std::vector rnk(n); 219 | for (int i = 0; i < n; i++) { 220 | rnk[sa[i]] = i; 221 | } 222 | std::vector lcp(n - 1); 223 | int h = 0; 224 | for (int i = 0; i < n; i++) { 225 | if (h > 0) h--; 226 | if (rnk[i] == 0) continue; 227 | int j = sa[rnk[i] - 1]; 228 | for (; j + h < n && i + h < n; h++) { 229 | if (s[j + h] != s[i + h]) break; 230 | } 231 | lcp[rnk[i] - 1] = h; 232 | } 233 | return lcp; 234 | } 235 | 236 | std::vector lcp_array(const std::string& s, const std::vector& sa) { 237 | int n = int(s.size()); 238 | std::vector s2(n); 239 | for (int i = 0; i < n; i++) { 240 | s2[i] = s[i]; 241 | } 242 | return lcp_array(s2, sa); 243 | } 244 | 245 | // Reference: 246 | // D. Gusfield, 247 | // Algorithms on Strings, Trees, and Sequences: Computer Science and 248 | // Computational Biology 249 | template std::vector z_algorithm(const std::vector& s) { 250 | int n = int(s.size()); 251 | if (n == 0) return {}; 252 | std::vector z(n); 253 | z[0] = 0; 254 | for (int i = 1, j = 0; i < n; i++) { 255 | int& k = z[i]; 256 | k = (j + z[j] <= i) ? 0 : std::min(j + z[j] - i, z[i - j]); 257 | while (i + k < n && s[k] == s[i + k]) k++; 258 | if (j + z[j] < i + z[i]) j = i; 259 | } 260 | z[0] = n; 261 | return z; 262 | } 263 | 264 | std::vector z_algorithm(const std::string& s) { 265 | int n = int(s.size()); 266 | std::vector s2(n); 267 | for (int i = 0; i < n; i++) { 268 | s2[i] = s[i]; 269 | } 270 | return z_algorithm(s2); 271 | } 272 | 273 | } // namespace atcoder 274 | 275 | #endif // ATCODER_STRING_HPP 276 | -------------------------------------------------------------------------------- /res/library/atcoder/twosat: -------------------------------------------------------------------------------- 1 | #include "atcoder/twosat.hpp" 2 | -------------------------------------------------------------------------------- /res/library/atcoder/twosat.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ATCODER_TWOSAT_HPP 2 | #define ATCODER_TWOSAT_HPP 1 3 | 4 | #include 5 | #include 6 | 7 | #include "atcoder/internal_scc" 8 | 9 | namespace atcoder { 10 | 11 | // Reference: 12 | // B. Aspvall, M. Plass, and R. Tarjan, 13 | // A Linear-Time Algorithm for Testing the Truth of Certain Quantified Boolean 14 | // Formulas 15 | struct two_sat { 16 | public: 17 | two_sat() : _n(0), scc(0) {} 18 | explicit two_sat(int n) : _n(n), _answer(n), scc(2 * n) {} 19 | 20 | void add_clause(int i, bool f, int j, bool g) { 21 | assert(0 <= i && i < _n); 22 | assert(0 <= j && j < _n); 23 | scc.add_edge(2 * i + (f ? 0 : 1), 2 * j + (g ? 1 : 0)); 24 | scc.add_edge(2 * j + (g ? 0 : 1), 2 * i + (f ? 1 : 0)); 25 | } 26 | bool satisfiable() { 27 | auto id = scc.scc_ids().second; 28 | for (int i = 0; i < _n; i++) { 29 | if (id[2 * i] == id[2 * i + 1]) return false; 30 | _answer[i] = id[2 * i] < id[2 * i + 1]; 31 | } 32 | return true; 33 | } 34 | std::vector answer() { return _answer; } 35 | 36 | private: 37 | int _n; 38 | std::vector _answer; 39 | internal::scc_graph scc; 40 | }; 41 | 42 | } // namespace atcoder 43 | 44 | #endif // ATCODER_TWOSAT_HPP 45 | -------------------------------------------------------------------------------- /res/library/expander.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import re 4 | import sys 5 | import argparse 6 | from logging import Logger, basicConfig, getLogger 7 | from os import getenv, environ, pathsep 8 | from pathlib import Path 9 | from typing import List, Set, Optional 10 | 11 | 12 | logger = getLogger(__name__) # type: Logger 13 | 14 | 15 | class Expander: 16 | atcoder_include = re.compile(r'#include\s*["<](atcoder/[a-z_]*(|.hpp))[">]\s*') 17 | 18 | include_guard = re.compile(r"#.*ATCODER_[A-Z_]*_HPP") 19 | 20 | def is_ignored_line(self, line) -> bool: 21 | if self.include_guard.match(line): 22 | return True 23 | if line.strip() == "#pragma once": 24 | return True 25 | if line.strip().startswith("//"): 26 | return True 27 | return False 28 | 29 | def __init__(self, lib_paths: List[Path]): 30 | self.lib_paths = lib_paths 31 | 32 | included = set() # type: Set[Path] 33 | 34 | def find_acl(self, acl_name: str) -> Path: 35 | for lib_path in self.lib_paths: 36 | path = lib_path / acl_name 37 | if path.exists(): 38 | return path 39 | logger.error("cannot find: {}".format(acl_name)) 40 | raise FileNotFoundError() 41 | 42 | def expand_acl(self, acl_file_path: Path) -> List[str]: 43 | if acl_file_path in self.included: 44 | logger.info("already included: {}".format(acl_file_path.name)) 45 | return [] 46 | self.included.add(acl_file_path) 47 | logger.info("include: {}".format(acl_file_path.name)) 48 | 49 | acl_source = open(str(acl_file_path)).read() 50 | 51 | result = [] # type: List[str] 52 | for line in acl_source.splitlines(): 53 | if self.is_ignored_line(line): 54 | continue 55 | 56 | m = self.atcoder_include.match(line) 57 | if m: 58 | name = m.group(1) 59 | result.extend(self.expand_acl(self.find_acl(name))) 60 | continue 61 | 62 | result.append(line) 63 | return result 64 | 65 | def expand(self, source: str) -> str: 66 | self.included = set() 67 | result = [] # type: List[str] 68 | for line in source.splitlines(): 69 | m = self.atcoder_include.match(line) 70 | if m: 71 | acl_path = self.find_acl(m.group(1)) 72 | result.extend(self.expand_acl(acl_path)) 73 | continue 74 | 75 | result.append(line) 76 | return "\n".join(result) 77 | 78 | 79 | if __name__ == "__main__": 80 | basicConfig( 81 | format="%(asctime)s [%(levelname)s] %(message)s", 82 | datefmt="%H:%M:%S", 83 | level=getenv("LOG_LEVEL", "INFO"), 84 | ) 85 | parser = argparse.ArgumentParser(description="Expander") 86 | parser.add_argument("source", help="Source File") 87 | parser.add_argument("-c", "--console", action="store_true", help="Print to Console") 88 | parser.add_argument("--lib", help="Path to Atcoder Library") 89 | opts = parser.parse_args() 90 | 91 | lib_paths = [] 92 | if opts.lib: 93 | lib_paths.append(Path(opts.lib)) 94 | if "CPLUS_INCLUDE_PATH" in environ: 95 | lib_paths.extend( 96 | map(Path, filter(None, environ["CPLUS_INCLUDE_PATH"].split(pathsep))) 97 | ) 98 | lib_paths.append(Path.cwd()) 99 | expander = Expander(lib_paths) 100 | source = open(opts.source).read() 101 | output = expander.expand(source) 102 | 103 | if opts.console: 104 | print(output) 105 | else: 106 | with open("combined.cpp", "w") as f: 107 | f.write(output) 108 | -------------------------------------------------------------------------------- /res/svg/AclIntellisense.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/AclIntellisense.png -------------------------------------------------------------------------------- /res/svg/CreateFolder backup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/CreateFolder backup.png -------------------------------------------------------------------------------- /res/svg/CreateFolder.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/CreateFolder.jpg -------------------------------------------------------------------------------- /res/svg/CreateFolder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/CreateFolder.png -------------------------------------------------------------------------------- /res/svg/IconLabels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/IconLabels.png -------------------------------------------------------------------------------- /res/svg/add_TestCase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/add_TestCase.png -------------------------------------------------------------------------------- /res/svg/add_TestCase1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/add_TestCase1.jpeg -------------------------------------------------------------------------------- /res/svg/brackets.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/svg/contestRegistration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/contestRegistration.png -------------------------------------------------------------------------------- /res/svg/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/copy.png -------------------------------------------------------------------------------- /res/svg/createAclCombinedFile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/createAclCombinedFile.png -------------------------------------------------------------------------------- /res/svg/createFile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/createFile.png -------------------------------------------------------------------------------- /res/svg/createStressTestingFiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/createStressTestingFiles.png -------------------------------------------------------------------------------- /res/svg/createStressTestingFiles.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/svg/cross-mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/cross-mark.png -------------------------------------------------------------------------------- /res/svg/filter backup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/filter backup.png -------------------------------------------------------------------------------- /res/svg/filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/filter.png -------------------------------------------------------------------------------- /res/svg/filter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /res/svg/green-tick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/green-tick.png -------------------------------------------------------------------------------- /res/svg/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/logo.png -------------------------------------------------------------------------------- /res/svg/openAclDocumentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/openAclDocumentation.png -------------------------------------------------------------------------------- /res/svg/play_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/play_button.png -------------------------------------------------------------------------------- /res/svg/question_mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/question_mark.png -------------------------------------------------------------------------------- /res/svg/refresh.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 10 | 11 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /res/svg/registerContest.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/registerContest.jpeg -------------------------------------------------------------------------------- /res/svg/registration.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/registration.jpeg -------------------------------------------------------------------------------- /res/svg/registration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/registration.png -------------------------------------------------------------------------------- /res/svg/stressTest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/stressTest.png -------------------------------------------------------------------------------- /res/svg/stressTest.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 10 | 15 | 27 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /res/svg/submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/submit.png -------------------------------------------------------------------------------- /res/svg/submit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /res/svg/upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IEEE-NITK/CodePal/f3536179c2b7dc4eb2eb69dac648c67cda788d68/res/svg/upload.png -------------------------------------------------------------------------------- /src/classes/contest.ts: -------------------------------------------------------------------------------- 1 | const cheerio = require('cheerio'); 2 | const axios = require('axios'); 3 | const fs = require("fs").promises; 4 | import { assert } from 'console'; 5 | 6 | import {ProblemClass} from "./problem"; 7 | 8 | export class ContestClass{ 9 | problems: ProblemClass[] = []; 10 | name: string; 11 | contestID: number; 12 | contestLink: string; 13 | type: string; 14 | startTime: string; 15 | startDate: string; 16 | duration: string; 17 | 18 | constructor(contestID: number, type: string, name:string, startTime: string, startDate: string, duration: string){ 19 | this.problems = []; 20 | this.name = name; 21 | this.type = type; // PAST, RUNNING OR FUTURE 22 | this.contestID = contestID; 23 | this.contestLink = `https://codeforces.com/contest/${this.contestID}`; 24 | this.startTime = startTime; 25 | this.startDate = startDate; 26 | this.duration = duration; 27 | } 28 | 29 | async init(){ 30 | try{ 31 | assert(this.type !== "FUTURE"); 32 | // const rcpcValue = "6164ef00544d3b5266657b2349cea803"; 33 | const { data } = await axios.get(this.contestLink); 34 | 35 | const $ = cheerio.load(data); 36 | 37 | // const contestName = $('.rtable > tbody:nth-child(1) > tr:nth-child(1) > th:nth-child(1) > a:nth-child(1)'); 38 | // this.name = contestName.text(); 39 | 40 | let problemIndices = $('table.problems > tbody > tr > td.id > a'); 41 | let problemNames = $('tr > td > div > div > a'); 42 | 43 | assert(problemIndices.length === problemNames.length); 44 | for(let i = 0; i < problemNames.length; i++){ 45 | let index = $(problemIndices[i]).text().trim(); 46 | let name = $(problemNames[i]).text().trim(); 47 | 48 | let p = new ProblemClass(this.contestID, index, name); 49 | this.problems.push(p); 50 | } 51 | } 52 | catch{ 53 | console.log('Could not find contest. Either the codeforces servers are down or internet connection is not stable'); 54 | } 55 | } 56 | }; -------------------------------------------------------------------------------- /src/classes/problem.ts: -------------------------------------------------------------------------------- 1 | import { SubmissionStatus } from "../utils/consts"; 2 | 3 | export class ProblemClass { 4 | index: string; 5 | contestID: number; 6 | problemID: string; 7 | name: string; 8 | tags: string[]; 9 | rating: number | undefined; 10 | problemsetLink: string; 11 | contestLink: string; 12 | submissionStatus: string; 13 | 14 | constructor (contestID: number, problemIndex: string, problemName:string = '', tags:string[] = [], rating:number = 0) { 15 | this.index = problemIndex; 16 | this.contestID = contestID; 17 | this.problemID = contestID + problemIndex; 18 | this.name = problemName; 19 | this.tags = tags; 20 | this.rating = rating; 21 | this.problemsetLink = `https://codeforces.com/problemset/problem/${contestID}/${problemIndex}`; 22 | this.contestLink = `https://codeforces.com/contest/${contestID}/problem/${problemIndex}`; 23 | this.submissionStatus = SubmissionStatus.unattempted; 24 | } 25 | }; -------------------------------------------------------------------------------- /src/data_providers/contests/contest_data_provider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { ContestTreeItem } from "./contest_tree_item"; 3 | import { fetchContests } from "../../features/contests_list/contests_list"; 4 | import { submissionStatus } from "../../features/contests_list/submission_status"; 5 | import { ContestClass } from "../../classes/contest"; 6 | import { ContestTreeEnum } from "../../utils/consts"; 7 | import { SubmissionStatus } from "../../utils/consts"; 8 | import * as path from 'path'; 9 | 10 | export class ContestsProvider implements vscode.TreeDataProvider { 11 | 12 | private rootPath: string; 13 | 14 | constructor(private workspaceRoot: string) { 15 | this.rootPath = workspaceRoot; 16 | } 17 | private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); 18 | readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event; 19 | 20 | refresh(): void { 21 | this._onDidChangeTreeData.fire(); 22 | } 23 | 24 | reload():void { 25 | this.refresh(); 26 | } 27 | 28 | getTreeItem( 29 | element: ContestTreeItem 30 | ): vscode.TreeItem | Thenable { 31 | return element; 32 | } 33 | 34 | getChildren( 35 | element?: ContestTreeItem 36 | ): vscode.ProviderResult { 37 | if (!element) { 38 | return this.getContestTypes(); 39 | } else if (element.label === ContestTreeEnum.runningContestType) { 40 | return fetchContests(element.label); 41 | } else if (element.label === ContestTreeEnum.futureContestType && !element.contest) { 42 | return fetchContests(element.label); 43 | } else if (element.label === ContestTreeEnum.pastContestType) { 44 | return fetchContests(element.label); 45 | } else { 46 | if(element.contest && element.type === ContestTreeEnum.futureContestType){ 47 | return this.constestStats(element.contest); 48 | } 49 | if (element.contest) { 50 | return this.fetchProblemsOfContest(element.contest); 51 | } 52 | return Promise.resolve([]); 53 | } 54 | } 55 | 56 | async fetchProblemsOfContest( 57 | contest: ContestClass 58 | ): Promise { 59 | if(!contest.problems.length) { 60 | await contest.init(); 61 | } 62 | let submissionList : any = await submissionStatus(contest.contestID); 63 | 64 | let i: number = 0; 65 | contest.problems.forEach((problem) => { 66 | 67 | if (i < submissionList.length) { 68 | let submission = submissionList[i]; 69 | 70 | while (problem.index >= submission.problem.index) { 71 | 72 | if (problem.index === submission.problem.index) { 73 | if (submission.verdict === "OK") { 74 | problem.submissionStatus = SubmissionStatus.accepted; 75 | break; 76 | } else if (problem.submissionStatus !== SubmissionStatus.accepted) { 77 | problem.submissionStatus = SubmissionStatus.failed; 78 | } 79 | } 80 | 81 | i = i + 1; 82 | if (i === submissionList.length) { 83 | break; 84 | } 85 | submission = submissionList[i]; 86 | } 87 | } 88 | }); 89 | 90 | return contest.problems.map((problem) => { 91 | let iconPath: string = ""; 92 | if(problem.submissionStatus !== SubmissionStatus.unattempted) { 93 | iconPath = problem.submissionStatus === SubmissionStatus.accepted 94 | ? path.join(__filename, '..', '..', 'res', 'svg', 'green-tick.png') 95 | : path.join(__filename, '..', '..', 'res', 'svg', 'cross-mark.png'); 96 | } 97 | 98 | return new ContestTreeItem( 99 | problem.name, 100 | "contestproblem", 101 | vscode.TreeItemCollapsibleState.None, 102 | "none", 103 | undefined, 104 | problem, 105 | iconPath 106 | ); 107 | }); 108 | } 109 | getContestTypes(): Thenable { 110 | 111 | return Promise.resolve([ 112 | new ContestTreeItem( 113 | ContestTreeEnum.runningContestType, 114 | ContestTreeEnum.contestTypeContextValue, 115 | vscode.TreeItemCollapsibleState.Collapsed 116 | ), 117 | new ContestTreeItem( 118 | ContestTreeEnum.futureContestType, 119 | ContestTreeEnum.contestTypeContextValue, 120 | vscode.TreeItemCollapsibleState.Collapsed 121 | ), 122 | new ContestTreeItem( 123 | ContestTreeEnum.pastContestType, 124 | ContestTreeEnum.contestTypeContextValue, 125 | vscode.TreeItemCollapsibleState.Collapsed 126 | ), 127 | ]); 128 | } 129 | 130 | constestStats( 131 | contest: ContestClass 132 | ): Thenable { 133 | let timing : string = ""; 134 | let duration : string = ""; 135 | 136 | timing = contest.startDate + ' ' + contest.startTime; 137 | duration = contest.duration; 138 | 139 | return Promise.resolve([ 140 | new ContestTreeItem( 141 | `Timing : ${timing}`, 142 | "Timing", 143 | vscode.TreeItemCollapsibleState.None, 144 | "", 145 | contest, 146 | undefined, 147 | undefined 148 | ), 149 | new ContestTreeItem( 150 | `Duration : ${duration}`, 151 | "Duration", 152 | vscode.TreeItemCollapsibleState.None, 153 | "", 154 | contest, 155 | undefined, 156 | undefined 157 | ), 158 | ]); 159 | } 160 | 161 | } 162 | -------------------------------------------------------------------------------- /src/data_providers/contests/contest_tree_item.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { ContestClass } from "../../classes/contest"; 3 | import { ProblemClass } from "../../classes/problem"; 4 | 5 | export class ContestTreeItem extends vscode.TreeItem { 6 | constructor( 7 | public readonly label: string, 8 | public readonly contextValue: string, 9 | public readonly collapsibleState: vscode.TreeItemCollapsibleState, 10 | public readonly type:string='', 11 | public readonly contest?:ContestClass|undefined, 12 | public readonly problem?:ProblemClass|undefined, 13 | public readonly iconPath?: string, 14 | public readonly command?: vscode.Command 15 | ) { 16 | super(label, collapsibleState); 17 | this.contextValue = contextValue; 18 | this.type=type; 19 | this.contest=contest; 20 | this.command = command; 21 | } 22 | } -------------------------------------------------------------------------------- /src/data_providers/problems/problem_data_provider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { ProblemTreeItem } from "./problem_tree_item"; 3 | 4 | import { ProblemClass } from "../../classes/problem"; 5 | import { RatingsEnum } from "../../utils/consts"; 6 | import { fetchProblems, filterProblems } from "../../features/problems_list/problems_filter"; 7 | 8 | export class ProblemsProvider implements vscode.TreeDataProvider { 9 | private rootPath: string; 10 | private alreadyfetched : boolean; 11 | private fromRating : number; 12 | private toRating : number; 13 | private tags : string[]; 14 | private allProblems : ProblemTreeItem[]; 15 | private statuses : string[]; 16 | 17 | constructor(private workspaceRoot: string) { 18 | this.alreadyfetched = false; 19 | this.fromRating = RatingsEnum.initialFromRating; 20 | this.toRating = RatingsEnum.initialToRating; 21 | this.tags = []; 22 | this.statuses = []; 23 | this.allProblems = []; 24 | this.rootPath = workspaceRoot; 25 | } 26 | 27 | private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); 28 | readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event; 29 | 30 | refresh(newFromRating : number,newToRating : number,newtags : string[], newstatus : string[]): void { 31 | this.fromRating = newFromRating; 32 | this.toRating = newToRating; 33 | this.tags = newtags; 34 | this.statuses = newstatus; 35 | this._onDidChangeTreeData.fire(); 36 | } 37 | 38 | reload():void { 39 | this.alreadyfetched = false; 40 | this.refresh(RatingsEnum.initialFromRating,RatingsEnum.initialToRating,[],[]); 41 | } 42 | 43 | getTreeItem( 44 | element: ProblemTreeItem 45 | ): vscode.TreeItem | Thenable { 46 | return element; 47 | } 48 | 49 | getAllProblems = async() : Promise => { 50 | this.allProblems = await fetchProblems(); 51 | this.alreadyfetched = true; 52 | return this.allProblems; 53 | }; 54 | 55 | getChildren( 56 | element?: ProblemTreeItem 57 | ): vscode.ProviderResult { 58 | if(this.alreadyfetched===false){ 59 | return this.getAllProblems(); 60 | } 61 | if (!element) { 62 | return filterProblems(this.allProblems,this.fromRating,this.toRating,this.tags, this.statuses); 63 | } else if (element.problem) { 64 | return this.problemStats(element.problem); 65 | } 66 | 67 | } 68 | 69 | problemStats( 70 | problem: ProblemClass 71 | ): Thenable { 72 | let tagList : string = ""; 73 | 74 | for(let i = 0; i < problem.tags.length; i+=1) { 75 | if (i === 0) { 76 | tagList += problem.tags[i]; 77 | } else { 78 | tagList += " , " + problem.tags[i]; 79 | } 80 | } 81 | 82 | return Promise.resolve([ 83 | new ProblemTreeItem( 84 | `Tags : ${tagList}`, 85 | "tags", 86 | vscode.TreeItemCollapsibleState.None 87 | ), 88 | ]); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/data_providers/problems/problem_tree_item.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import {ProblemClass} from "../../classes/problem"; 3 | 4 | export class ProblemTreeItem extends vscode.TreeItem { 5 | constructor( 6 | public readonly label: string, 7 | public readonly contextValue: string, 8 | public readonly collapsibleState: vscode.TreeItemCollapsibleState, 9 | public readonly problem?:ProblemClass, 10 | public readonly iconPath?: string, 11 | public readonly command?: vscode.Command 12 | ) { 13 | super(label, collapsibleState); 14 | this.contextValue = contextValue; 15 | this.problem = problem; 16 | this.command = command; 17 | this.iconPath = iconPath; 18 | } 19 | } -------------------------------------------------------------------------------- /src/data_providers/user_profile/profile_data_provider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { fetchUserInfoApi } from "../../features/user_profile/fetch_user_info_api"; 3 | import { 4 | CodepalConfig, 5 | codepalConfigName, 6 | Command, 7 | ProfileTreeEnum, 8 | } from "../../utils/consts"; 9 | import { ProfileTreeItem } from "./profile_tree_item"; 10 | 11 | export class ProfileProvider 12 | implements vscode.TreeDataProvider { 13 | constructor(private workspaceRoot: string) {} 14 | 15 | private _onDidChangeTreeData: vscode.EventEmitter< 16 | ProfileTreeItem | undefined | void 17 | > = new vscode.EventEmitter(); 18 | readonly onDidChangeTreeData: vscode.Event< 19 | ProfileTreeItem | undefined | void 20 | > = this._onDidChangeTreeData.event; 21 | 22 | getTreeItem( 23 | element: ProfileTreeItem 24 | ): vscode.TreeItem | Thenable { 25 | return element; 26 | } 27 | refresh(): void { 28 | this._onDidChangeTreeData.fire(); 29 | } 30 | getChildren( 31 | element?: ProfileTreeItem 32 | ): vscode.ProviderResult { 33 | const codeforcesHandle = vscode.workspace 34 | .getConfiguration(codepalConfigName) 35 | .get(CodepalConfig.codeforcesHandle); 36 | if (codeforcesHandle) { 37 | return fetchUserInfoApi(codeforcesHandle); 38 | } 39 | return [ 40 | new ProfileTreeItem( 41 | `Please enter your handle in settings for a personalized experience`, 42 | ProfileTreeEnum.codeforcesHandleUndefined, 43 | vscode.TreeItemCollapsibleState.None, 44 | ), 45 | new ProfileTreeItem( 46 | "Entering your handle reflects solved and unsolved problems also.", 47 | ProfileTreeEnum.codeforcesHandleUndefined, 48 | vscode.TreeItemCollapsibleState.None 49 | ), 50 | ]; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/data_providers/user_profile/profile_tree_item.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | 3 | export class ProfileTreeItem extends vscode.TreeItem { 4 | constructor( 5 | public readonly label: string, 6 | public readonly contextValue: string, 7 | public readonly collapsibleState: vscode.TreeItemCollapsibleState, 8 | public readonly command?: vscode.Command 9 | ) { 10 | super(label, collapsibleState); 11 | this.contextValue = contextValue; 12 | this.command = command; 13 | } 14 | } -------------------------------------------------------------------------------- /src/features/ACL/createAclCombinedFile.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | const fs = require("fs"); 3 | var path = require('path'); 4 | import { platform } from "os"; 5 | import { 6 | extensionPaths, 7 | OS 8 | } from "../../utils/consts"; 9 | 10 | import { Utils} from "../../utils/utils"; 11 | import { runTests } from "../run_test_cases/run_solution"; 12 | 13 | 14 | 15 | export const createAclCombinedFile = async( 16 | filePath: string 17 | ): Promise =>{ 18 | 19 | const os = platform() === "win32"?OS.windows : OS.linuxMac; 20 | 21 | let solutionFilePath = Utils.pathRefine(filePath, os); 22 | let combinedFilePath = path.dirname(solutionFilePath) + '/combined.cpp'; 23 | 24 | let compilationLanguage = `python3`; 25 | 26 | // TODO: maybe change compilationLanguage to suit different OS 27 | let runCommand = `${compilationLanguage} "${extensionPaths.expanderPyPath}" "${solutionFilePath}" --lib "${extensionPaths.libraryPath}" -c > "${combinedFilePath}"`; 28 | 29 | console.log(runCommand); 30 | 31 | // to see the logic behind runCommand: https://atcoder.github.io/ac-library/production/document_en/appendix.html 32 | 33 | runTests( 34 | runCommand, 35 | '', 36 | '' 37 | ); 38 | 39 | try{ 40 | await vscode.window.showTextDocument(vscode.Uri.file(combinedFilePath), { 41 | preview: false, 42 | preserveFocus: true, 43 | }); 44 | } 45 | catch{ 46 | vscode.window.showErrorMessage('Unable to create combined.cpp file'); 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /src/features/ACL/openAclDocumentation.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | export const openAclDocumentation = () => { 3 | try { 4 | // TODO: add option for en and ja documentation 5 | vscode.env.openExternal(vscode.Uri.parse(`https://atcoder.github.io/ac-library/production/document_en/`, true)); 6 | vscode.window.showInformationMessage("Opened ACL Documentation"); 7 | } catch (err) { 8 | // vscode.window.showErrorMessage(err); 9 | console.log(err); 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /src/features/contest_registration/contest_registration.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { ContestClass } from "../../classes/contest"; 3 | 4 | export const contestRegistration = async (path: ContestClass | undefined) => { 5 | try { 6 | if(path !== undefined){ 7 | vscode.env.openExternal(vscode.Uri.parse(`https://codeforces.com/contestRegistration/${path.contestID}`, true)); 8 | } 9 | vscode.window.showInformationMessage("Contest Registration page opened"); 10 | } catch (err) { 11 | vscode.window.showErrorMessage(err); 12 | } 13 | }; -------------------------------------------------------------------------------- /src/features/contests_list/contests_list.ts: -------------------------------------------------------------------------------- 1 | import fetch from "node-fetch"; 2 | import * as vscode from "vscode"; 3 | import { ContestClass } from "../../classes/contest"; 4 | import { ContestTreeItem } from "../../data_providers/contests/contest_tree_item"; 5 | import { ContestTreeEnum, ContestsPhase, Urls } from "../../utils/consts"; 6 | 7 | 8 | const contestsList = async ( 9 | contestsType: string 10 | ): Promise => { 11 | let arr: ContestClass[] = []; 12 | return fetch(Urls.fetchContestsList) 13 | .then((response: any) => { 14 | if (!response.ok) { 15 | throw new Error(response.error); 16 | } else { 17 | return response.json(); 18 | } 19 | }) 20 | .catch((err: any) => { 21 | return arr; 22 | }) 23 | .then(async (users: { result: string | any[] }) => { 24 | for (let i:number = 0; i < users.result.length; i++) { 25 | let contestID = users.result[i].id; 26 | let sec : number = users.result[i].durationSeconds; 27 | let h : number = Math.floor(sec/3600); 28 | var hour : string = ""; 29 | var minute : string = ""; 30 | var second : string = ""; 31 | 32 | (h >= 1) ? sec = sec - (h*3600) : hour = ""; 33 | (h<10) ? hour = '0' + h.toString() : hour = h.toString(); 34 | let min : number = Math.floor(sec/60); 35 | (min >= 1) ? sec = sec - (min*60) : minute = ""; 36 | (min<10) ? minute = '0' + min.toString() : minute = min.toString(); 37 | (sec< 10) ? second = '0'+ sec.toString() : second = sec.toString(); 38 | 39 | var duration : string = hour + ':' + minute + ':' + second; 40 | var startDate = new Date(users.result[i].startTimeSeconds*1000).toLocaleDateString(); 41 | var startTime = new Date(users.result[i].startTimeSeconds*1000).toLocaleTimeString(); 42 | 43 | let type = ""; 44 | let x = users.result[i].phase; 45 | if (x === ContestsPhase.finished) { 46 | type = ContestTreeEnum.pastContestType; 47 | } 48 | if (x === ContestsPhase.coding) { 49 | type = ContestTreeEnum.runningContestType; 50 | } 51 | if (x === ContestsPhase.before) { 52 | type = ContestTreeEnum.futureContestType; 53 | } 54 | if (type === contestsType) { 55 | let c = new ContestClass(contestID, type, users.result[i].name, startTime, startDate, duration); 56 | arr.push(c); 57 | } 58 | } 59 | if(contestsType === ContestTreeEnum.futureContestType) { 60 | arr.reverse(); 61 | } 62 | return arr; 63 | }); 64 | }; 65 | 66 | export const fetchContests = async (type: string): Promise => { 67 | let contests: ContestClass[] = await contestsList(type); 68 | 69 | const contestsMap = contests.map ( 70 | (contest): ContestTreeItem => { 71 | return new ContestTreeItem ( 72 | `${contest.name}`, 73 | type === ContestTreeEnum.futureContestType?ContestTreeEnum.futureContestLabel:ContestTreeEnum.contestLabel, 74 | (type === ContestTreeEnum.futureContestType) ? vscode.TreeItemCollapsibleState.Expanded : vscode.TreeItemCollapsibleState.Collapsed, 75 | type, 76 | contest 77 | ); 78 | } 79 | ); 80 | const noContestFoundTreeItem = new ContestTreeItem( 81 | 'No Contests Found', 82 | 'empty', 83 | vscode.TreeItemCollapsibleState.None 84 | ); 85 | return contestsMap.length === 0 ? [noContestFoundTreeItem] : contestsMap; 86 | }; -------------------------------------------------------------------------------- /src/features/contests_list/submission_status.ts: -------------------------------------------------------------------------------- 1 | import fetch from "node-fetch"; 2 | import * as vscode from "vscode"; 3 | 4 | import { 5 | CodepalConfig, 6 | codepalConfigName, 7 | SubmissionStatus 8 | } from "../../utils/consts"; 9 | 10 | export const submissionStatus = async (contestId : number): Promise => { 11 | 12 | const codeforcesHandle: String | undefined = vscode.workspace 13 | .getConfiguration(codepalConfigName) 14 | .get(CodepalConfig.codeforcesHandle); 15 | 16 | if(codeforcesHandle === "") { 17 | return []; 18 | } 19 | 20 | let url: string = "https://codeforces.com/api/contest.status?"; 21 | url = `${url}contestId=${contestId}&handle=${codeforcesHandle}`; 22 | // console.log(url); 23 | try { 24 | // fetching the list of submissions of the user 25 | const response = await fetch(url); 26 | if(response.ok) { 27 | const jsonResponse = await response.json(); 28 | if(jsonResponse.status === SubmissionStatus.failed) { 29 | vscode.window.showErrorMessage("Invalid Codeforces handle"); 30 | return undefined; 31 | } 32 | const submissions = jsonResponse.result; 33 | await submissions.sort((a: any, b: any) => { 34 | if (compareIds(a.problem.index, b.problem.index)) { 35 | return -1; 36 | } else { 37 | return 1; 38 | } 39 | }); 40 | 41 | return submissions; 42 | } 43 | 44 | } 45 | catch(error) { 46 | console.log(error); 47 | } 48 | 49 | return []; 50 | }; 51 | 52 | const compareIds = ( 53 | problemIndex1: string, 54 | problemIndex2: string 55 | ): boolean => { 56 | if (problemIndex1 < problemIndex2) { 57 | return true; 58 | } else { 59 | return false; 60 | } 61 | }; -------------------------------------------------------------------------------- /src/features/copy_url/copy_contest_url.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { ContestClass } from "../../classes/contest"; 3 | 4 | export const copyContestURL = async ( 5 | contest: ContestClass | undefined 6 | ): Promise => { 7 | if (contest === undefined) { 8 | return; 9 | } 10 | try { 11 | vscode.env.clipboard.writeText(contest.contestLink); 12 | vscode.window.showInformationMessage("Contest URL copied successfully"); 13 | } 14 | catch (err) { 15 | vscode.window.showErrorMessage("Could not copy contest URL to clipboard.\nUnknown error occurred"); 16 | } 17 | }; -------------------------------------------------------------------------------- /src/features/copy_url/copy_problem_url.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { ProblemClass } from "../../classes/problem"; 3 | 4 | export const copyProblemURL = async ( 5 | problem: ProblemClass | undefined 6 | ): Promise => { 7 | if (problem === undefined) { 8 | return; 9 | } 10 | try { 11 | vscode.env.clipboard.writeText(problem.contestLink); 12 | vscode.window.showInformationMessage("Problem URL copied successfully"); 13 | } 14 | catch (err) { 15 | vscode.window.showErrorMessage("Could not copy problem URL to clipboard.\nUnknown error occurred"); 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /src/features/folder_creation/contest_folder_creation.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { ContestClass } from "../../classes/contest"; 3 | import {promises as fs} from "fs"; 4 | import { createProblemDirectory } from "./problem_folder_creation"; 5 | import { ErrorCodes } from "../../utils/consts"; 6 | 7 | export const createContestDirectory = async ( 8 | contest: ContestClass| undefined, 9 | rootPath: string 10 | ): Promise => { 11 | 12 | if(contest === undefined) { 13 | return; 14 | } 15 | 16 | if(contest.problems.length === 0) { 17 | await contest.init(); 18 | } 19 | 20 | let contestName : string = contest.name; 21 | contestName = contestName.replace(/[^a-zA-Z 0-9.]+/g,''); // replacing special characters to fit naming convention 22 | const folderPath = rootPath + `${contestName}/`; 23 | 24 | try { 25 | await fs.mkdir(folderPath); 26 | 27 | contest.problems.forEach(async (problem) => { 28 | vscode.window.setStatusBarMessage("Creating Contest Folder...",1000); 29 | await createProblemDirectory(problem, folderPath); 30 | }); 31 | vscode.window.showInformationMessage('Contest folder created Successfully'); 32 | } 33 | catch(err) { 34 | if(err.code === ErrorCodes.folderExists) { 35 | vscode.window.showErrorMessage('Contest folder already exists'); 36 | }else if(err.code === ErrorCodes.noAccessPermission) { 37 | vscode.window.showErrorMessage("No access permission.\nPlease open a folder in your workspace."); 38 | }else if(err.code === ErrorCodes.noWritePermission) { 39 | vscode.window.showErrorMessage("No write permission.\nPlease open a folder in your workspace."); 40 | }else { 41 | vscode.window.showErrorMessage("Could not create folder.\nUnknown error occurred"); 42 | } 43 | } 44 | }; -------------------------------------------------------------------------------- /src/features/folder_creation/manual_contest_folder.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { promises as fs } from "fs"; 3 | import { ErrorCodes } from "../../utils/consts"; 4 | import { manualProblemFolderCreation } from "./manual_problem_folder"; 5 | 6 | export const manualContestFolderCreation = async ( 7 | folderPath: string 8 | ): Promise => { 9 | 10 | let contestName: string = await contestNameInput(); 11 | if(contestName === "") { 12 | vscode.window.showErrorMessage("No contest name entered."); 13 | return; 14 | } 15 | contestName = contestName.replace(/[^a-zA-Z 0-9.]+/g,''); // replacing special characters to fit naming convention 16 | 17 | const inputNumberOfProblems: string = await numberInput(); 18 | if(inputNumberOfProblems === "") { 19 | // vscode.window.showErrorMessage("Number of problems not entered."); 20 | return; 21 | } 22 | let numberOfProblems = parseInt(String(inputNumberOfProblems)); 23 | 24 | const contestFolderPath: string = folderPath + `${contestName}/`; 25 | 26 | try { 27 | await fs.mkdir(contestFolderPath); 28 | 29 | for(let problemId = 1; problemId <= numberOfProblems; problemId++) { 30 | vscode.window.setStatusBarMessage("Creating Contest Folder...",1000); 31 | await manualProblemFolderCreation(contestFolderPath, `problem${problemId}`); 32 | } 33 | vscode.window.showInformationMessage('Contest folder created Successfully'); 34 | } 35 | catch(err) { 36 | if(err.code === ErrorCodes.folderExists) { 37 | vscode.window.showErrorMessage("Contest folder already exists"); 38 | }else if(err.code === ErrorCodes.noAccessPermission) { 39 | vscode.window.showErrorMessage("No access permission.\nPlease open a folder in your workspace."); 40 | }else if(err.code === ErrorCodes.noWritePermission) { 41 | vscode.window.showErrorMessage("No write permission.\nPlease open a folder in your workspace."); 42 | }else { 43 | vscode.window.showErrorMessage("Could not create folder.\nUnknown error occurred"); 44 | } 45 | } 46 | }; 47 | 48 | const contestNameInput = async(): Promise => { 49 | 50 | const contestName: string | undefined = await vscode.window.showInputBox({placeHolder: "Enter the name of the contest."}); 51 | 52 | if(typeof(contestName) === "string") { 53 | return contestName; 54 | } 55 | 56 | return ""; 57 | }; 58 | 59 | const numberInput = async(): Promise => { 60 | 61 | const numberOfProblems: string | undefined = await vscode.window.showInputBox({placeHolder: "Enter the number of problems in the contest."}); 62 | 63 | 64 | if(typeof(numberOfProblems) === "string" && isNum(numberOfProblems)) { 65 | return numberOfProblems; 66 | } 67 | else if(typeof(numberOfProblems) === "string" && !isNum(numberOfProblems)) { 68 | vscode.window.showErrorMessage("Invalid input to number of problems."); 69 | return ""; 70 | } 71 | else { 72 | vscode.window.showErrorMessage("Number of problems not entered."); 73 | return ""; 74 | } 75 | 76 | }; 77 | 78 | const isNum = (val:string) => /^\d+$/.test(val); // check if a string has only digits -------------------------------------------------------------------------------- /src/features/folder_creation/manual_problem_folder.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { promises as fs } from "fs"; 3 | import { ErrorCodes } from "../../utils/consts"; 4 | import { getFileExtension, getTemplateCode } from "./problem_folder_creation"; 5 | 6 | export const manualProblemFolderCreation = async ( 7 | folderPath: string, 8 | problemName: string = "" 9 | ): Promise => { 10 | if(problemName === "") { 11 | problemName = await problemNameInput(); 12 | } 13 | if(problemName === "") { 14 | vscode.window.showErrorMessage("No problem name entered."); 15 | return; 16 | } 17 | 18 | problemName = problemName.replace(/[^a-zA-Z 0-9.]+/g,''); 19 | problemName = problemName.replace(/[^a-zA-Z0-9]/g,'_'); 20 | const problemFolderPath = folderPath + `${problemName}/`; 21 | 22 | const fileExtension = getFileExtension(); 23 | 24 | const problemFilePath = 25 | problemFolderPath + `${problemName}.${fileExtension}`; 26 | 27 | const templateCode = await getTemplateCode(); 28 | 29 | try { 30 | await fs.mkdir(problemFolderPath); 31 | 32 | fs.writeFile(problemFilePath, templateCode); // solution file 33 | vscode.window.showTextDocument(vscode.Uri.file(problemFilePath), { 34 | preview: false, 35 | preserveFocus: true, 36 | }); 37 | vscode.window.showInformationMessage("Problem folder created successfully"); 38 | } 39 | catch (err) { 40 | if (err.code === ErrorCodes.folderExists) { 41 | vscode.window.showErrorMessage("Problem folder already exists"); 42 | } else if(err.code === ErrorCodes.noAccessPermission) { 43 | vscode.window.showErrorMessage("No access permission.\nPlease open a folder in your workspace."); 44 | } else if(err.code === ErrorCodes.noWritePermission) { 45 | vscode.window.showErrorMessage("No write permission.\nPlease open a folder in your workspace."); 46 | } else{ 47 | vscode.window.showErrorMessage("Could not create folder.\nUnknown error occurred"); 48 | } 49 | } 50 | 51 | 52 | }; 53 | 54 | const problemNameInput = async(): Promise => { 55 | 56 | const problemName: string | undefined = await vscode.window.showInputBox({placeHolder: "Enter the name of the problem."}); 57 | 58 | if(typeof(problemName) === "string") { 59 | return problemName; 60 | } 61 | 62 | return ""; 63 | }; 64 | -------------------------------------------------------------------------------- /src/features/folder_creation/problem_folder_creation.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { ProblemClass } from "../../classes/problem"; 3 | import { promises as fs } from "fs"; 4 | import { readFileSync as fs_readFileSync } from "fs"; 5 | import { fetchTestCases } from "./test_cases_fetch"; 6 | import { CodepalConfig, codepalConfigName, CompilationLanguages, ErrorCodes } from "../../utils/consts"; 7 | 8 | let templateCode = ""; // will hold the code that is stored in the path given in settings 9 | 10 | export const getTemplateCode = async () => { 11 | const templatePath = vscode.workspace 12 | .getConfiguration(codepalConfigName) 13 | .get(CodepalConfig.codeTemplatePath); 14 | let data = ""; 15 | try { 16 | if (templatePath) { 17 | data = fs_readFileSync(templatePath, "ascii").toString(); 18 | } 19 | } catch (err) { 20 | if (err.code === ErrorCodes.notFound) { 21 | vscode.window.showErrorMessage("Template path specied does not exist."); 22 | } else { 23 | vscode.window.showErrorMessage("Error reading template code."); 24 | } 25 | } 26 | 27 | return data; 28 | }; 29 | 30 | export const getFileExtension = (): string => { 31 | 32 | const compilationLanguage = vscode.workspace 33 | .getConfiguration(codepalConfigName) 34 | .get(CodepalConfig.compilationLanguage); 35 | 36 | let fileExtension: string; 37 | switch(compilationLanguage) { 38 | case CompilationLanguages.gcc: 39 | fileExtension = 'c'; 40 | break; 41 | 42 | case CompilationLanguages.cpp: 43 | fileExtension = 'cpp'; 44 | break; 45 | 46 | case CompilationLanguages.python: 47 | case CompilationLanguages.python2: 48 | case CompilationLanguages.python3: 49 | fileExtension = 'py'; 50 | break; 51 | 52 | case CompilationLanguages.java: 53 | fileExtension = 'java'; 54 | break; 55 | 56 | case CompilationLanguages.kotlin: 57 | fileExtension = 'kt'; 58 | break; 59 | case CompilationLanguages.haskell: 60 | fileExtension = 'hs'; 61 | break; 62 | default: 63 | vscode.window.showErrorMessage("Language used is not supported"); 64 | throw Error(); 65 | } 66 | 67 | return fileExtension; 68 | }; 69 | 70 | export const createProblemDirectory = async ( 71 | problem: ProblemClass | undefined, 72 | folderPath: string 73 | ): Promise => { 74 | if (problem === undefined) { 75 | return; 76 | } 77 | let problemName : string = problem.name; 78 | problemName = problemName.replace(/[^a-zA-Z 0-9.]+/g,''); 79 | problemName = problemName.replace(/[^a-zA-Z0-9]/g,'_'); 80 | const problemFolderPath = folderPath + `${problem.index}_${problemName}/`; 81 | 82 | const fileExtension = getFileExtension(); 83 | 84 | const problemFilePath = 85 | problemFolderPath + `${problem.index}_${problemName}.${fileExtension}`; 86 | 87 | templateCode = await getTemplateCode(); 88 | 89 | try { 90 | await fs.mkdir(problemFolderPath); 91 | // creating .json 92 | fs.writeFile( 93 | problemFolderPath + ".problem.json", 94 | JSON.stringify({ 95 | contestID: problem.contestID, 96 | index: problem.index, 97 | }) 98 | ); 99 | fs.writeFile(problemFilePath, templateCode); // solution file 100 | 101 | await fetchTestCases(problem, problemFolderPath); // Fetch tests cases into the problem folder 102 | 103 | vscode.window.showTextDocument(vscode.Uri.file(problemFilePath), { 104 | preview: false, 105 | preserveFocus: true, 106 | }); 107 | vscode.window.showInformationMessage("Problem folder created successfully"); 108 | } 109 | catch (err) { 110 | if (err.code === ErrorCodes.folderExists) { 111 | vscode.window.showErrorMessage("Problem folder already exists."); 112 | } else if(err.code === ErrorCodes.noAccessPermission) { 113 | vscode.window.showErrorMessage("No access permission.\nPlease open a folder in your workspace."); 114 | } else if(err.code === ErrorCodes.noWritePermission) { 115 | vscode.window.showErrorMessage("No write permission.\nPlease open a folder in your workspace."); 116 | } else{ 117 | vscode.window.showErrorMessage("Could not create folder.\nUnknown error occurred"); 118 | } 119 | } 120 | }; 121 | -------------------------------------------------------------------------------- /src/features/folder_creation/test_cases_fetch.ts: -------------------------------------------------------------------------------- 1 | const cheerio = require('cheerio'); 2 | const axios = require('axios'); 3 | const fs = require("fs").promises; 4 | import * as vscode from "vscode"; 5 | import { ProblemClass } from '../../classes/problem'; 6 | 7 | const getInputOutput = async (problem: ProblemClass) => { 8 | try { 9 | const { data } = await axios.get( 10 | `https://codeforces.com/contest/${problem.contestID}/problem/${problem.index}` 11 | ); 12 | const $ = cheerio.load(data); 13 | const postTitleInput = $('div > div.input > pre'); 14 | const postTitleOutput = $('div > div.output > pre'); 15 | 16 | let input: string[] = []; 17 | let output: string[] = []; 18 | 19 | postTitleInput.each((i: Number, element: any) => { 20 | let testBlock: string = ""; 21 | 22 | if (element.children.length > 1){ // there is mutli-test highlighting enabled 23 | element.children.forEach((testLine: any) => { 24 | testBlock += $(testLine).html() + '\n'; 25 | });; 26 | } 27 | else{ 28 | testBlock = $(element).html().replace(/
/g, '\n'); 29 | } 30 | 31 | input.push(testBlock); 32 | }); 33 | postTitleOutput.each((i: Number, element: string) => { 34 | output.push($(element).html().replace(/
/g, '\n')); 35 | }); 36 | 37 | return {input,output}; 38 | 39 | } 40 | catch (error) { 41 | throw error; 42 | } 43 | }; 44 | 45 | 46 | export const fetchTestCases = async ( 47 | problem: ProblemClass, 48 | folderPath: string 49 | ): Promise => { 50 | 51 | const problemFolderPath = folderPath + `Tests/`; 52 | 53 | try{ 54 | await fs.mkdir(problemFolderPath); 55 | getInputOutput(problem) 56 | .then((data) => { 57 | for(let i=0; i { 67 | for(let i=0; i => { 7 | if (contest === undefined) { 8 | return; 9 | } 10 | try { 11 | vscode.env.openExternal(vscode.Uri.parse(contest.contestLink, true)); 12 | vscode.window.showInformationMessage("Opened contest page"); 13 | } 14 | catch (err) { 15 | vscode.window.showErrorMessage("Could not open contest page.\nUnknown error occurred. Try copying contest URL."); 16 | } 17 | }; -------------------------------------------------------------------------------- /src/features/open_problem_statement/open_problem_from_problem_list.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { ProblemClass } from "../../classes/problem"; 3 | 4 | export const openProblemURL = async ( 5 | problem: ProblemClass | undefined 6 | ): Promise => { 7 | if (problem === undefined) { 8 | return; 9 | } 10 | try { 11 | vscode.env.openExternal(vscode.Uri.parse(problem.contestLink, true)); 12 | vscode.window.showInformationMessage("Opened problem statement"); 13 | } 14 | catch (err) { 15 | vscode.window.showErrorMessage("Could not open problem URL.\nUnknown error occurred. Try copying the URL instead."); 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /src/features/open_problem_statement/open_problem_statement.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import {platform} from "os"; 3 | import * as fs from "fs"; 4 | import {Utils} from "../../utils/utils"; 5 | import { OS } from "../../utils/consts"; 6 | export const openProblemStatement = (path: string) => { 7 | try { 8 | path = Utils.pathRefine(path, platform() === "win32"?OS.windows : OS.linuxMac); 9 | console.log(path); 10 | if (vscode.window.activeTextEditor) { 11 | path = vscode.window.activeTextEditor.document.uri.fsPath; 12 | path = path.replace(/\\/g, '/'); 13 | } 14 | 15 | const jsonPath = path.substr(0, path.lastIndexOf("/")) + `/.problem.json`; 16 | const jsonData = JSON.parse(fs.readFileSync(jsonPath).toString()); 17 | vscode.env.openExternal(vscode.Uri.parse(`https://codeforces.com/contest/${jsonData.contestID}/problem/${jsonData.index}`, true)); 18 | vscode.window.showInformationMessage("Opened problem statement"); 19 | } catch (err) { 20 | vscode.window.showErrorMessage(err); 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /src/features/problems_list/problems_filter.ts: -------------------------------------------------------------------------------- 1 | import fetch from "node-fetch"; 2 | import * as vscode from "vscode"; 3 | import { ProblemClass } from "../../classes/problem"; 4 | import { ProblemTreeItem } from "../../data_providers/problems/problem_tree_item"; 5 | import { updateSubmissionStatus } from "./submission_status"; 6 | import { Urls, tagsByOR, ProblemTreeEnum, SubmissionStatus} from "../../utils/consts"; 7 | import * as path from 'path'; 8 | 9 | const problemsList = async ( 10 | ): Promise => { 11 | 12 | try { 13 | // Fetching the problems using the codeforces problemset API call 14 | const response = await fetch(Urls.fetchProblemSet); 15 | if(response.ok) { 16 | const jsonResponse = await response.json(); 17 | let problems: ProblemClass[] = []; 18 | 19 | // res is the json response obtained from the API call 20 | jsonResponse.result.problems.forEach((element: any) => { 21 | const p = new ProblemClass (element.contestId, element.index, element.name, element.tags, element.rating); 22 | problems.push(p); 23 | }); 24 | return problems; 25 | } 26 | } 27 | catch(error) {} 28 | 29 | return []; 30 | }; 31 | 32 | export const fetchProblems = async (): Promise => { 33 | let problems: ProblemClass[] = await problemsList(); 34 | problems = await updateSubmissionStatus(problems); 35 | return problems.map ( 36 | (problem: ProblemClass): ProblemTreeItem => { 37 | let problemLabel: string = `${problem.name} (${(problem.rating === 0 ? "Not yet defined" : problem.rating)})`; 38 | let iconPath: string = ""; 39 | if(problem.submissionStatus !== SubmissionStatus.unattempted) { 40 | iconPath = problem.submissionStatus === SubmissionStatus.accepted 41 | ? path.join(__filename, '..', '..', 'res', 'svg', 'green-tick.png') 42 | : path.join(__filename, '..', '..', 'res', 'svg', 'cross-mark.png'); 43 | } 44 | 45 | return new ProblemTreeItem ( 46 | problemLabel, 47 | ProblemTreeEnum.problemContextValue, 48 | vscode.TreeItemCollapsibleState.Collapsed, 49 | problem, 50 | iconPath 51 | ); 52 | } 53 | ); 54 | }; 55 | 56 | // returns true if the problem is within the given rating range 57 | const validRating = ( 58 | problem: ProblemClass | undefined, 59 | fromRating: number, 60 | toRating: number): boolean =>{ 61 | if(problem === undefined || problem.rating === undefined){ 62 | return false; 63 | } 64 | 65 | if(fromRating <= problem.rating && problem.rating <= toRating){ 66 | return true; 67 | } 68 | else{ 69 | return false; 70 | } 71 | }; 72 | 73 | // returns the true if the problem has all the tags needed or atleast one depending on tagsByOR 74 | const validTags = ( 75 | problem: ProblemClass | undefined, 76 | tags:string[]): boolean =>{ // 77 | if(problem === undefined || problem.tags === undefined){ 78 | return false; 79 | } 80 | 81 | if(tags.includes(tagsByOR)){ // union of all tags 82 | if(tags.length === 1 || tags.some(tag => problem.tags.includes(tag))){ 83 | return true; 84 | } 85 | else{ 86 | return false; 87 | } 88 | } 89 | 90 | else{ // intersection of all tags 91 | if(tags.length === 0 || tags.every(tag => problem.tags.includes(tag))){ 92 | return true; 93 | } 94 | else{ 95 | return false; 96 | } 97 | } 98 | }; 99 | 100 | // returns the true if the problem status is the required one 101 | const validStatus = ( 102 | problem: ProblemClass | undefined, 103 | status:string[]): boolean =>{ // 104 | if(problem === undefined || problem.tags === undefined){ 105 | return false; 106 | } 107 | 108 | if(status.length === 0 || status.includes(problem.submissionStatus)){ 109 | return true; 110 | } 111 | else{ 112 | return false; 113 | } 114 | }; 115 | 116 | // filter the problems from already fetched list 117 | export const filterProblems = ( 118 | problems : ProblemTreeItem[], 119 | fromRating : number, 120 | toRating : number, 121 | tags : string[], 122 | statuses : string[] 123 | ) : ProblemTreeItem[] => { 124 | 125 | 126 | let filteredProblems : ProblemTreeItem[] = []; 127 | problems.forEach(function(problem : ProblemTreeItem) : void{ 128 | let currentProblem : ProblemClass | undefined = problem.problem; 129 | 130 | 131 | if( currentProblem !== undefined && 132 | validRating(currentProblem,fromRating,toRating) === true && 133 | validTags(currentProblem,tags) === true && validStatus(currentProblem, statuses)) { 134 | 135 | filteredProblems.push(problem); 136 | } 137 | }); 138 | 139 | // if the combination of filter results in no problem then display "No problem found" 140 | if(filteredProblems.length === 0){ 141 | filteredProblems.push(new ProblemTreeItem ( 142 | `No problem found`, 143 | "empty", 144 | vscode.TreeItemCollapsibleState.None, 145 | )); 146 | } 147 | return filteredProblems; 148 | }; 149 | -------------------------------------------------------------------------------- /src/features/problems_list/problems_filter_input.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { ProblemsProvider } from "../../data_providers/problems/problem_data_provider"; 3 | import { allTags, statusOfProblem, RatingsEnum } from "../../utils/consts"; 4 | 5 | const isNum = (val:string) => /^\d+$/.test(val); // check if a string has only digits 6 | 7 | export const problemsFilterInput = async (problemProvider: ProblemsProvider):Promise =>{ 8 | 9 | let fromRating = await vscode.window.showInputBox({placeHolder:"Enter the rating's lower limit. Leave blank for defaulting to 0."}); 10 | let toRating = await vscode.window.showInputBox({placeHolder:"Enter the rating's upper limit. Leave blank for defaulting to 4000."}); 11 | let tags : string[] = []; // read tags here with quick input and assign to the variable 12 | let status: string[] = []; 13 | 14 | if(typeof(fromRating)==="string" && typeof(toRating)==="string"){ 15 | 16 | if(toRating==="" || !isNum(toRating)){ 17 | toRating = RatingsEnum.initialToRating.toString(); // invalid input so defaulting to max rating 18 | } 19 | if(fromRating==="" || !isNum(fromRating)){ 20 | fromRating = RatingsEnum.initialFromRating.toString(); // invalid input so defaulting to min rating 21 | } 22 | 23 | const quickPick = vscode.window.createQuickPick(); // using quickPick to take multiple input 24 | quickPick.items = allTags.map(label => ({ label })); 25 | quickPick.canSelectMany = true; // enables choosing multiple tags 26 | 27 | quickPick.onDidAccept(() => { 28 | 29 | quickPick.selectedItems.forEach(item => { 30 | tags.push(item.label); // pushing selected tags into array 31 | }); 32 | 33 | const quickPicks = vscode.window.createQuickPick(); // using quickPick to take multiple input 34 | quickPicks.items = statusOfProblem.map(label => ({ label })); 35 | quickPicks.canSelectMany = true; // enables choosing multiple tags 36 | 37 | quickPicks.onDidAccept(() => { 38 | 39 | quickPicks.selectedItems.forEach(items => { 40 | status.push(items.label); // pushing selected tags into array 41 | }); 42 | 43 | quickPicks.hide(); 44 | console.log(status); 45 | 46 | problemProvider.refresh(parseInt(String(fromRating)),parseInt(String(toRating)),tags, status); 47 | }); 48 | 49 | quickPicks.onDidHide(() => quickPicks.dispose()); 50 | quickPicks.show(); 51 | 52 | quickPick.hide(); 53 | 54 | //problemProvider.refresh(parseInt(String(fromRating)),parseInt(String(toRating)),tags, status); 55 | }); 56 | 57 | quickPick.onDidHide(() => quickPick.dispose()); 58 | quickPick.show(); 59 | } 60 | }; -------------------------------------------------------------------------------- /src/features/problems_list/submission_status.ts: -------------------------------------------------------------------------------- 1 | import fetch from "node-fetch"; 2 | import * as vscode from "vscode"; 3 | import { ProblemClass } from "../../classes/problem"; 4 | 5 | import { 6 | CodepalConfig, 7 | codepalConfigName, 8 | SubmissionStatus 9 | } from "../../utils/consts"; 10 | 11 | export const updateSubmissionStatus = async ( 12 | problems: ProblemClass[] 13 | ): Promise => { 14 | 15 | const codeforcesHandle: String | undefined = vscode.workspace 16 | .getConfiguration(codepalConfigName) 17 | .get(CodepalConfig.codeforcesHandle); 18 | 19 | if(codeforcesHandle === "") { 20 | return problems; 21 | } 22 | 23 | let url: string = "https://codeforces.com/api/user.status?"; 24 | url = `${url}handle=${codeforcesHandle}`; 25 | // console.log(url); 26 | try { 27 | // fetching the list of submissions of the user 28 | const response = await fetch(url); 29 | if(response.ok) { 30 | const jsonResponse = await response.json(); 31 | if(jsonResponse.status === SubmissionStatus.failed) { 32 | vscode.window.showErrorMessage("Invalid Codeforces handle"); 33 | return problems; 34 | } 35 | const submissions = jsonResponse.result; 36 | await submissions.sort((a: any, b: any) => { 37 | if (compareIds(a.contestId, a.problem.index, b.contestId, b.problem.index)) { 38 | return 1; 39 | } else { 40 | return -1; 41 | } 42 | }); 43 | 44 | // console.log(submissions.length); 45 | // console.log(problems.length); 46 | let problemIdx: number = 0; // Iterator for the list of problem objects 47 | let submissionIdx: number = 0; // Iterator for the list of submission objects 48 | while(submissionIdx < submissions.length && problemIdx < problems.length) { 49 | // console.log(submissions[i].contestId, submissions[i].problem.index); 50 | const submission: any = submissions[submissionIdx]; 51 | // console.log(`${submission.problem.name} ${submission.contestId} ${submission.problem.index}`); 52 | while(problemIdx < problems.length && compareIds(submission.contestId, submission.problem.index, problems[problemIdx].contestID, problems[problemIdx].index)) { 53 | problemIdx++; 54 | } 55 | let resolvedProblemIdx: number = problemIdx; 56 | if(submission.problem.name !== problems[problemIdx].name) { 57 | let tempIdx: number = problemIdx + 1; 58 | let problemFound: boolean = false; 59 | while(tempIdx < problems.length && tempIdx <= (problemIdx + 15) ) 60 | { 61 | if(problems[tempIdx].name === submission.problem.name) { 62 | resolvedProblemIdx = tempIdx; 63 | problemFound = true; 64 | break; 65 | } 66 | tempIdx++; 67 | } 68 | // console.log(problemFound); 69 | if(!problemFound) { 70 | submissionIdx++; 71 | continue; 72 | } 73 | } 74 | // console.log(problemIdx); 75 | if(submission.verdict === SubmissionStatus.accepted) { 76 | problems[resolvedProblemIdx].submissionStatus = SubmissionStatus.accepted; 77 | } else if(submission.verdict !== SubmissionStatus.accepted && problems[resolvedProblemIdx].submissionStatus === SubmissionStatus.unattempted) { 78 | problems[resolvedProblemIdx].submissionStatus = SubmissionStatus.failed; 79 | } 80 | 81 | submissionIdx++; 82 | } 83 | 84 | return problems; 85 | } 86 | } 87 | catch(error) { 88 | console.log(error); 89 | } 90 | return problems; 91 | }; 92 | 93 | const compareIds = ( 94 | contestId1:number, 95 | problemIndex1: string, 96 | contestId2: number, 97 | problemIndex2: string 98 | ): boolean => { 99 | if (contestId1 < contestId2) { 100 | return true; 101 | } else if (contestId1 === contestId2) { 102 | if (problemIndex1 < problemIndex2) { 103 | return true; 104 | } else { 105 | return false; 106 | } 107 | } else { 108 | return false; 109 | } 110 | }; -------------------------------------------------------------------------------- /src/features/run_test_cases/add_test_cases.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | const fs = require("fs"); 3 | import { platform } from "os"; 4 | import { Utils } from "../../utils/utils"; 5 | import { Command, OS } from "../../utils/consts"; 6 | 7 | export const addTestCases = async function (filePath: string): Promise { 8 | // Code for adding test cases 9 | const os = platform() === "win32"?OS.windows : OS.linuxMac; 10 | let path = Utils.pathRefine(filePath, os); 11 | 12 | if (vscode.window.activeTextEditor) { 13 | path = vscode.window.activeTextEditor.document.uri.fsPath; 14 | path = path.replace(/\\/g, '/'); 15 | } 16 | const lastIndexOfSlash: number = path.lastIndexOf("/"); 17 | const problemFolderPath: string = path.slice(0, lastIndexOfSlash + 1); 18 | 19 | const testsFolderPath: string = `${problemFolderPath}Tests/`; 20 | 21 | if (!fs.existsSync(testsFolderPath)) { 22 | fs.mkdir(testsFolderPath, function (e: any) { 23 | if (!e || (e && e.code === "EEXIST")) {} 24 | }); 25 | } 26 | 27 | let i: number = 1; 28 | 29 | let inputFilePath: string = `${testsFolderPath}input_${i}.txt`; 30 | 31 | while (fs.existsSync(inputFilePath)) { 32 | i++; 33 | inputFilePath = `${testsFolderPath}input_${i}.txt`; 34 | } 35 | 36 | const addedInputFilePath = `${testsFolderPath}input_${i}.txt`; 37 | fs.writeFile(addedInputFilePath, "", function (err: any, result: any) { 38 | if (err) {} 39 | }); 40 | 41 | const addedOutputFilePath = `${testsFolderPath}output_${i}.txt`; 42 | fs.writeFile(addedOutputFilePath, "", function (err: any, result: any) { 43 | if (err) { 44 | } 45 | }); 46 | 47 | vscode.commands.executeCommand(Command.setEditorLayout, { 48 | orientation: 0, 49 | groups: [ 50 | { groups: [{}], size: 1 }, 51 | { groups: [{}, {}], size: 0.5 }, 52 | ], 53 | }); 54 | 55 | vscode.window.showInformationMessage( 56 | `Input and Output files created successfully. Please enter the input and expected output in the input${i}.txt and output${i}.txt respectively` 57 | ); 58 | 59 | vscode.commands.executeCommand( 60 | Command.vscodeOpen, 61 | vscode.Uri.file(addedOutputFilePath), 62 | vscode.ViewColumn.Three 63 | ); 64 | 65 | vscode.commands.executeCommand( 66 | Command.vscodeOpen, 67 | vscode.Uri.file(addedInputFilePath), 68 | vscode.ViewColumn.Two 69 | ); 70 | }; 71 | -------------------------------------------------------------------------------- /src/features/run_test_cases/compile_solution.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | const fs = require("fs"); 3 | import { exec } from "child_process"; 4 | import { reportError } from "./report_error"; 5 | import { platform } from "os"; 6 | import { 7 | codepalConfigName, 8 | CodepalConfig, 9 | CompilationFlags, 10 | CompilationLanguages, 11 | extensionPaths 12 | } from "../../utils/consts"; 13 | 14 | export const compileFile = async ( 15 | solutionFilePath: string, 16 | testsFolderPath: string, 17 | outputFileName: string = 'a' 18 | ): Promise => { 19 | if (fs.existsSync(`${testsFolderPath}result.txt`)) { 20 | fs.unlink(`${testsFolderPath}result.txt`, (err: any) => { 21 | console.log(err); 22 | }); 23 | } 24 | if (fs.existsSync(`${testsFolderPath}error.txt`)) { 25 | fs.unlink(`${testsFolderPath}error.txt`, (err: any) => { 26 | console.log(err); 27 | }); 28 | } 29 | 30 | const compilationLanguage = vscode.workspace 31 | .getConfiguration(codepalConfigName) 32 | .get(CodepalConfig.compilationLanguage); 33 | 34 | if ( 35 | compilationLanguage === CompilationLanguages.python || 36 | compilationLanguage === CompilationLanguages.python2 || 37 | compilationLanguage === CompilationLanguages.python3 38 | ) { 39 | return new Promise((resolve, reject) => { 40 | resolve(""); 41 | }); 42 | } 43 | 44 | let aclSupportEnabled:boolean = vscode.workspace 45 | .getConfiguration(codepalConfigName) 46 | .get(CodepalConfig.enableAclSupport, false); 47 | 48 | let compileCommand: string; 49 | let compilationFlags: String | undefined; 50 | switch (compilationLanguage) { 51 | case CompilationLanguages.cpp: 52 | compilationFlags = vscode.workspace 53 | .getConfiguration(codepalConfigName) 54 | .get(CompilationFlags.cpp); 55 | 56 | if(aclSupportEnabled === true){ 57 | compilationFlags += ` -I "${extensionPaths.libraryPath}"`; 58 | } 59 | 60 | if(platform() === "win32"){ 61 | compileCommand = `g++ -o "${testsFolderPath}${outputFileName}.exe" "${solutionFilePath}" ${compilationFlags}`; 62 | } 63 | else{ 64 | compileCommand = `g++ -o "${testsFolderPath}${outputFileName}.out" "${solutionFilePath}" ${compilationFlags}`; 65 | } 66 | break; 67 | 68 | case CompilationLanguages.gcc: 69 | compilationFlags = vscode.workspace 70 | .getConfiguration(codepalConfigName) 71 | .get(CompilationFlags.gcc); 72 | 73 | if(platform() === "win32"){ 74 | compileCommand = `gcc -o "${testsFolderPath}${outputFileName}.exe" "${solutionFilePath}" ${compilationFlags}`; 75 | } 76 | else{ 77 | compileCommand = `gcc -o "${testsFolderPath}${outputFileName}.out" "${solutionFilePath}" ${compilationFlags}`; 78 | } 79 | break; 80 | 81 | case CompilationLanguages.java: 82 | compilationFlags = vscode.workspace 83 | .getConfiguration(codepalConfigName) 84 | .get(CompilationFlags.java); 85 | compileCommand = `javac "${solutionFilePath}" ${compilationFlags}`; 86 | break; 87 | 88 | case CompilationLanguages.kotlin: 89 | compilationFlags = vscode.workspace 90 | .getConfiguration(codepalConfigName) 91 | .get(CompilationFlags.kotlin); 92 | compileCommand = `kotlinc "${solutionFilePath}" -include-runtime -d "${testsFolderPath}${outputFileName}.jar" ${compilationFlags}`; 93 | break; 94 | case CompilationLanguages.haskell: 95 | compilationFlags = vscode.workspace 96 | .getConfiguration(codepalConfigName) 97 | .get(CompilationFlags.haskell); 98 | if(platform() === "win32"){ 99 | compileCommand = `ghc -o "${testsFolderPath}${outputFileName}.exe" "${solutionFilePath}" ${compilationFlags}`; 100 | } 101 | else{ 102 | compileCommand = `ghc -o "${testsFolderPath}${outputFileName}.out" "${solutionFilePath}" ${compilationFlags}`; 103 | } 104 | break; 105 | 106 | default: 107 | vscode.window.showErrorMessage("Language used is not supported"); 108 | throw Error(); 109 | } 110 | 111 | try { 112 | return new Promise(async (resolve, reject) => { 113 | exec(compileCommand, async (error: any, stdout: any, stderr: any) => { 114 | if (error) { 115 | await reportError(error.message, "Compilation", testsFolderPath); 116 | reject(error.message); 117 | return; 118 | } 119 | if (stderr) { 120 | await reportError(stderr, "Compilation", testsFolderPath); 121 | reject(stderr); 122 | return; 123 | } 124 | vscode.window.setStatusBarMessage("Compilation Done",2000); 125 | resolve(stdout); 126 | }); 127 | }); 128 | } catch (err) { 129 | console.log(err); 130 | } 131 | }; 132 | -------------------------------------------------------------------------------- /src/features/run_test_cases/report_error.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | const fs = require("fs"); 3 | 4 | export const reportError = async ( 5 | error: string, 6 | errorType: string, 7 | testsFolderPath: string 8 | ): Promise => { 9 | vscode.window.showErrorMessage( 10 | `${errorType} Error!!!` 11 | ); 12 | const errorFilePath: string = `${testsFolderPath}error.txt`; 13 | fs.writeFileSync(errorFilePath, error, (err: any) => { 14 | if (err) { 15 | vscode.window.showErrorMessage("Could not display error message."); 16 | } 17 | }); 18 | vscode.window.showTextDocument(vscode.Uri.file(errorFilePath), { 19 | preview: false, 20 | viewColumn: vscode.ViewColumn.Beside, 21 | preserveFocus: true, 22 | }); 23 | }; -------------------------------------------------------------------------------- /src/features/run_test_cases/run_solution.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | const fs = require("fs"); 3 | import { exec } from "child_process"; 4 | import { reportError } from "./report_error"; 5 | import { Errors, OS, tle } from "../../utils/consts"; 6 | 7 | import { 8 | CodepalConfig, 9 | codepalConfigName, 10 | CompilationFlags, 11 | CompilationLanguages, 12 | } from "../../utils/consts"; 13 | 14 | export const runTestsWithTimeout = async ( 15 | solutionFilePath: string, 16 | inputFilePath: string, 17 | codeOutputFilePath: string, 18 | testsFolderPath: string, 19 | stderrFilePath: string, 20 | os: number, 21 | executableFileName: string = 'a', 22 | commandLineArguments: string = '', 23 | ): Promise => { 24 | let timeoutHandle: NodeJS.Timeout; 25 | // Declaring a promise that rejects after 6s 26 | const timeoutPromise = new Promise((resolve, reject) => { 27 | timeoutHandle = setTimeout(() => reject(Errors.timeLimitExceeded), 6000); 28 | }); 29 | 30 | let runCommand: string; 31 | let executable: string; 32 | 33 | const compilationLanguage = vscode.workspace 34 | .getConfiguration(codepalConfigName) 35 | .get(CodepalConfig.compilationLanguage); 36 | 37 | switch (compilationLanguage) { 38 | case CompilationLanguages.gcc: 39 | case CompilationLanguages.cpp: 40 | case CompilationLanguages.haskell: 41 | if (os === OS.linuxMac) { 42 | // Command for linux 43 | executable = `${executableFileName}.out`; 44 | } else if (os === OS.windows) { 45 | // Command for windows 46 | executable = `${executableFileName}.exe`; 47 | } else { 48 | vscode.window.showErrorMessage("Operating System not supported."); 49 | return; 50 | } 51 | runCommand = `"${testsFolderPath}${executable}" ${commandLineArguments} < "${inputFilePath}" > "${codeOutputFilePath}"`; 52 | break; 53 | 54 | case CompilationLanguages.python: 55 | case CompilationLanguages.python2: 56 | case CompilationLanguages.python3: 57 | const compilationFlags = vscode.workspace 58 | .getConfiguration(codepalConfigName) 59 | .get(CompilationFlags.python); 60 | executable = (os === OS.windows) 61 | ? `python.exe` 62 | : `${compilationLanguage}`; 63 | 64 | runCommand = `${compilationLanguage} "${solutionFilePath}" ${commandLineArguments} ${compilationFlags} < "${inputFilePath}" > "${codeOutputFilePath}"`; 65 | break; 66 | 67 | case CompilationLanguages.java: 68 | executable = solutionFilePath.slice( 69 | solutionFilePath.lastIndexOf("/") + 1, 70 | solutionFilePath.lastIndexOf(".") 71 | ); 72 | const javaClassPath: string = solutionFilePath.slice( 73 | 0, 74 | solutionFilePath.lastIndexOf("/") 75 | ); 76 | runCommand = `java -cp "${javaClassPath}" ${executable} ${commandLineArguments} < "${inputFilePath}" > "${codeOutputFilePath}"`; 77 | executable = (os === OS.windows) 78 | ? "java.exe" 79 | : "java"; 80 | break; 81 | 82 | case CompilationLanguages.kotlin: 83 | // const kotlinClassPath: string = solutionFilePath.slice( 84 | // 0, 85 | // solutionFilePath.lastIndexOf("/") 86 | // ); 87 | // console.log(kotlinClassPath); 88 | runCommand = `java -jar "${testsFolderPath}${executableFileName}.jar" < "${inputFilePath}" > "${codeOutputFilePath}"`; 89 | executable = (os === OS.windows) 90 | ? "java.exe" 91 | : "java"; 92 | break; 93 | 94 | default: 95 | vscode.window.showErrorMessage("Language used is not supported"); 96 | throw Error(); 97 | } 98 | 99 | return Promise.race([ 100 | runTests(runCommand, testsFolderPath, stderrFilePath), 101 | timeoutPromise, 102 | ]) 103 | .then((result) => { 104 | clearTimeout(timeoutHandle); 105 | return result; 106 | }) 107 | .catch(async (error) => { 108 | if (error === Errors.timeLimitExceeded) { 109 | tle.tleFlag = true; 110 | vscode.window.showErrorMessage("Time limit exceeded!!"); 111 | let killCommand: string; 112 | killCommand = (os === OS.windows) 113 | ? `taskkill /F /IM ${executable}` 114 | : `pkill -9 ${executable}`; 115 | // Kill the executing process 116 | exec( 117 | killCommand, 118 | (error: any, stdout: any, stderr: any) => { 119 | if (error) { 120 | console.log( 121 | `Could not kill timed out process.\nError: ${error.message}` 122 | ); 123 | } 124 | if (stderr) { 125 | console.log( 126 | `Could not kill timed out process.\nstderr: ${stderr}` 127 | ); 128 | } 129 | } 130 | ); 131 | return Errors.timeLimitExceeded; 132 | } 133 | return Errors.runTimeError; 134 | }); 135 | }; 136 | 137 | export const runTests = async ( 138 | runCommand: string, 139 | testsFolderPath: string, 140 | stderrFilePath: string 141 | ): Promise => { 142 | try { 143 | return new Promise(async (resolve, reject) => { 144 | exec(runCommand, async (error: any, stdout: any, stderr: any) => { 145 | if (error) { 146 | if(tle.tleFlag) { 147 | return; 148 | } 149 | console.log(`Runtime Error: ${error}`); 150 | await reportError(error.message, "Run Time", testsFolderPath); 151 | reject(error.message); 152 | return; 153 | } 154 | if (stderr) { 155 | console.log(`stderr: ${stderr}`); 156 | fs.writeFileSync(stderrFilePath, stderr, (err: any) => { 157 | if (err) { 158 | vscode.window.showErrorMessage("Could not write stderr."); 159 | } 160 | }); 161 | } else if (fs.existsSync(stderrFilePath)) { 162 | fs.unlinkSync(stderrFilePath, (err: any) => { 163 | console.log(err); 164 | }); 165 | } 166 | 167 | resolve(stdout); 168 | }); 169 | }); 170 | } catch (err) { 171 | console.log("Run time error: " + err); 172 | } 173 | }; 174 | -------------------------------------------------------------------------------- /src/features/run_test_cases/run_test_cases.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | const fs = require("fs"); 3 | import { Utils} from "../../utils/utils"; 4 | import { compileFile } from "./compile_solution"; 5 | import { runTestsWithTimeout } from "./run_solution"; 6 | import { platform } from "os"; 7 | import { OS, Errors, tle } from "../../utils/consts"; 8 | 9 | export const runTestCases = async function (filePath: string): Promise { 10 | // Code for running test cases and returning verdict 11 | const os = platform() === "win32"?OS.windows : OS.linuxMac; 12 | let path = Utils.pathRefine(filePath, os); 13 | 14 | if (vscode.window.activeTextEditor) { 15 | path = vscode.window.activeTextEditor.document.uri.fsPath; 16 | path = path.replace(/\\/g, '/'); 17 | } 18 | 19 | if (!fs.existsSync(path)) { 20 | vscode.window.showErrorMessage("Problem solution file not found."); 21 | return; 22 | } 23 | 24 | const lastIndexOfSlash: number = path.lastIndexOf("/"); 25 | const problemFolderPath: string = path.slice(0, lastIndexOfSlash + 1); 26 | 27 | const testsFolderPath = problemFolderPath + "Tests/"; 28 | 29 | if (!fs.existsSync(testsFolderPath)) { 30 | vscode.window.showErrorMessage("Tests not found. Please add a test case."); 31 | return; 32 | } 33 | 34 | try { 35 | await compileFile(path, testsFolderPath); 36 | } catch (err) { 37 | console.log(err); 38 | return; 39 | } 40 | 41 | const resultFilePath: string = `${testsFolderPath}result.txt`; 42 | 43 | let i: number = 1; 44 | let passed: boolean = true; 45 | tle.tleFlag = false; 46 | while (true) { 47 | const inputFilePath: string = `${testsFolderPath}input_${i}.txt`; 48 | 49 | if (!fs.existsSync(inputFilePath)) { 50 | break; 51 | } 52 | const outputFilePath: string = `${testsFolderPath}output_${i}.txt`; 53 | const codeOutputFilePath: string = `${testsFolderPath}code_output_${i}.txt`; 54 | const stderrFilePath: string = `${testsFolderPath}stderr_${i}.txt`; 55 | 56 | try { 57 | 58 | let runResult = await runTestsWithTimeout ( 59 | path, 60 | inputFilePath, 61 | codeOutputFilePath, 62 | testsFolderPath, 63 | stderrFilePath, 64 | os, 65 | 'a', 66 | '1' 67 | ); 68 | 69 | let input: string = await readFile(inputFilePath); 70 | let expectedOutput: string = await readFile(outputFilePath); 71 | let codeOutput: string = await readFile(codeOutputFilePath); 72 | 73 | let result : string = ""; 74 | let testResult: boolean; 75 | if(runResult === Errors.timeLimitExceeded || runResult === Errors.runTimeError) { 76 | result = result + `Test ${i} ${runResult}\n\n`; 77 | testResult = false; 78 | } 79 | else { 80 | testResult = await compareOutputs( 81 | outputFilePath, 82 | codeOutputFilePath 83 | ); 84 | 85 | if (testResult === true) { 86 | result = result + `Test ${i} Passed\n\n`; 87 | } 88 | else { 89 | result = result + `Test ${i} Failed\n\n`; 90 | } 91 | } 92 | 93 | result = result + `Input ${i}: \n${input}\n\nExpected Output : \n${expectedOutput}\n\nObtained Output : \n${codeOutput}\n\n`; 94 | if (fs.existsSync(stderrFilePath)) { 95 | let stderr: string = await readFile(stderrFilePath); 96 | result = `${result}Standard Error : \n${stderr}\n\n`; 97 | } 98 | 99 | result = result + "________________________________________________________\n\n"; 100 | fs.appendFileSync(resultFilePath, result, (err: any) => { 101 | if (err) { 102 | vscode.window.showErrorMessage("Could not write result."); 103 | } 104 | }); 105 | 106 | if (!testResult) { 107 | vscode.window.showTextDocument(vscode.Uri.file(resultFilePath), { 108 | preview: false, 109 | viewColumn: vscode.ViewColumn.Beside, 110 | preserveFocus: true, 111 | }); 112 | if(runResult === Errors.timeLimitExceeded || runResult === Errors.runTimeError) { 113 | return; 114 | } 115 | if (passed === true) { 116 | vscode.window.showErrorMessage( 117 | `Test ${i} failed` 118 | ); 119 | } 120 | passed = false; 121 | } 122 | } catch (err) { 123 | // Runtime errors also get logged here 124 | passed = false; 125 | return; 126 | } 127 | 128 | i++; 129 | } 130 | 131 | if (passed === true) { 132 | const click: 133 | | string 134 | | undefined 135 | = await vscode.window.showInformationMessage( 136 | `All test cases passed.`, 137 | "Show Results" 138 | ); 139 | if (click === "Show Results") { 140 | vscode.window.showTextDocument(vscode.Uri.file(resultFilePath), { 141 | preview: false, 142 | viewColumn: vscode.ViewColumn.Beside, 143 | preserveFocus: true, 144 | }); 145 | } 146 | } 147 | }; 148 | 149 | export const compareOutputs = async ( 150 | outputFilePath: string, 151 | codeOutputFilePath: string 152 | ): Promise => { 153 | // Code to compare the expected output and the obtained output 154 | 155 | let expectedOutput: string = await readFile(outputFilePath); 156 | 157 | let obtainedOutput: string = await readFile(codeOutputFilePath); 158 | 159 | expectedOutput = refine(expectedOutput); 160 | obtainedOutput = refine(obtainedOutput); 161 | if (expectedOutput === obtainedOutput) { 162 | return true; 163 | } else { 164 | return false; 165 | } 166 | }; 167 | 168 | const refine = (content: string): string => { 169 | content = content.trim(); 170 | content = content.replace(/\r/g, ""); 171 | content = content.replace(/ \n/g, "\n"); 172 | 173 | return content; 174 | }; 175 | 176 | export const readFile = (filePath: string): Promise => { 177 | return new Promise((resolve, reject) => { 178 | fs.readFile(filePath, "utf8", (error: any, fileContent: string) => { 179 | if (error !== null) { 180 | reject(error); 181 | return; 182 | } 183 | 184 | resolve(fileContent); 185 | }); 186 | }); 187 | }; 188 | -------------------------------------------------------------------------------- /src/features/stress_test/compile_all_files.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | const fs = require("fs"); 3 | import { compileFile } from "../run_test_cases/compile_solution"; 4 | 5 | export const compileAllFiles = async ( 6 | testsFolderPath: string, 7 | solnPath: string, 8 | brutePath: string, 9 | genPath: string 10 | ):Promise => { 11 | 12 | if (!fs.existsSync(solnPath)) { 13 | vscode.window.showErrorMessage("Problem solution file not found. Please try again."); 14 | return false; 15 | } 16 | 17 | if (!fs.existsSync(testsFolderPath)) { 18 | vscode.window.showErrorMessage("Stress Tests folder not found. Create Stress Testing files."); 19 | return false; 20 | } 21 | 22 | if (!fs.existsSync(brutePath)) { 23 | vscode.window.showErrorMessage("Brute force solution file not found. Create Stress Testing files."); 24 | return false; 25 | } 26 | if (!fs.existsSync(genPath)) { 27 | vscode.window.showErrorMessage("Generator file not found. Create Stress Testing files."); 28 | return false; 29 | } 30 | 31 | try { 32 | await compileFile(solnPath, testsFolderPath, 'soln'); 33 | } catch (err) { 34 | console.log(err); 35 | return false; 36 | } 37 | 38 | try { 39 | await compileFile(brutePath, testsFolderPath, 'brute'); 40 | } catch (err) { 41 | console.log(err); 42 | return false; 43 | } 44 | 45 | try { 46 | await compileFile(genPath, testsFolderPath, 'gen'); 47 | } catch (err) { 48 | console.log(err); 49 | return false; 50 | } 51 | 52 | return true; 53 | }; 54 | -------------------------------------------------------------------------------- /src/features/stress_test/createStressTestingFiles.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | const fs = require("fs"); 3 | import { Utils} from "../../utils/utils"; 4 | import { platform } from "os"; 5 | import { OS, generatorTemplate, CompilationLanguages, CodepalConfig, codepalConfigName } from "../../utils/consts"; 6 | import { getTemplateCode } from "../folder_creation/problem_folder_creation"; 7 | import { readFileSync as fs_readFileSync } from "fs"; 8 | 9 | export const getGenTemplateCode = async () => { 10 | const templatePath = vscode.workspace 11 | .getConfiguration(codepalConfigName) 12 | .get(CodepalConfig.generatorTemplatePath); 13 | let data = ""; 14 | try { 15 | if (templatePath) { 16 | data = fs_readFileSync(templatePath, "ascii").toString(); 17 | } 18 | } catch (e) { 19 | vscode.window.showErrorMessage("Error fetching generator template. Please make sure path is valid."); 20 | } 21 | 22 | return data; 23 | }; 24 | 25 | export const createStressTestingFiles = async (filePath: string):Promise => { 26 | const os = platform() === "win32"?OS.windows : OS.linuxMac; 27 | let path = Utils.pathRefine(filePath, os); 28 | 29 | const lastIndexOfSlash: number = path.lastIndexOf("/"); 30 | const problemFolderPath: string = path.slice(0, lastIndexOfSlash + 1); 31 | const testsFolderPath = problemFolderPath + "stress_tests/"; 32 | 33 | const compilationLanguage = vscode.workspace 34 | .getConfiguration(codepalConfigName) 35 | .get(CodepalConfig.compilationLanguage); 36 | 37 | 38 | let fileExtension: string; 39 | let genTemplateCode:string = await getGenTemplateCode(); 40 | 41 | switch(compilationLanguage) { 42 | case CompilationLanguages.gcc: 43 | fileExtension = 'c'; 44 | genTemplateCode = generatorTemplate.c; 45 | break; 46 | 47 | case CompilationLanguages.cpp: 48 | fileExtension = 'cpp'; 49 | genTemplateCode = generatorTemplate.cpp; 50 | break; 51 | 52 | case CompilationLanguages.python: 53 | case CompilationLanguages.python2: 54 | case CompilationLanguages.python3: 55 | fileExtension = 'py'; 56 | 57 | if(compilationLanguage === CompilationLanguages.python){ 58 | genTemplateCode = generatorTemplate.python; 59 | } 60 | else if(compilationLanguage === CompilationLanguages.python2){ 61 | genTemplateCode = generatorTemplate.python2; 62 | } else { 63 | genTemplateCode = generatorTemplate.python3; 64 | } 65 | break; 66 | 67 | case CompilationLanguages.java: 68 | fileExtension = 'java'; 69 | genTemplateCode = generatorTemplate.java; 70 | break; 71 | 72 | case CompilationLanguages.kotlin: 73 | fileExtension = 'kt'; 74 | genTemplateCode = generatorTemplate.kotlin; 75 | break; 76 | 77 | default: 78 | vscode.window.showErrorMessage("Language used is not supported"); 79 | throw Error(); 80 | } 81 | 82 | const brutePath = problemFolderPath + 'brute.' + fileExtension; 83 | 84 | const genPath = problemFolderPath + 'gen.' + fileExtension; 85 | 86 | const emptyInputFilePath = testsFolderPath + 'empty.txt'; 87 | // TODO: I think making gen cpp file is best as we can give command line arguments 88 | 89 | if (!fs.existsSync(testsFolderPath)) { 90 | fs.mkdir(testsFolderPath, function (e: any) { 91 | if (!e || (e && e.code === "EEXIST")) {} 92 | }); 93 | } 94 | 95 | // creating brute.cpp if it doesnt exist 96 | let templateCode:string = await getTemplateCode(); 97 | if(!fs.existsSync(brutePath)) { 98 | fs.writeFile(brutePath, templateCode, function (err: any, result: any) { 99 | if (err) { 100 | vscode.window.showErrorMessage('Error creating brute file'); 101 | } 102 | }); 103 | } 104 | 105 | // if the user has setup their own generator template then that is used 106 | let userGenTemplate:string = await getGenTemplateCode(); 107 | 108 | if(userGenTemplate !== ''){ 109 | genTemplateCode = userGenTemplate; 110 | } 111 | 112 | //this happens when an unknown coding language is used, I think 113 | if(genTemplateCode === ''){ 114 | genTemplateCode = templateCode; 115 | } 116 | 117 | // creating gen.cpp if it doesnt exist 118 | if(!fs.existsSync(genPath)) { 119 | fs.writeFile(genPath, genTemplateCode, function (err: any, result: any) { 120 | if (err) { 121 | vscode.window.showErrorMessage('Error creating gen file'); 122 | } 123 | }); 124 | } 125 | 126 | // empty input file to feed into generator 127 | if(!fs.existsSync(emptyInputFilePath)) { 128 | fs.writeFile(emptyInputFilePath, '', function (err: any, result: any) { 129 | if (err) { 130 | vscode.window.showErrorMessage('Error creating empty input file'); 131 | } 132 | }); 133 | } 134 | 135 | await vscode.window.showTextDocument(vscode.Uri.file(brutePath), { 136 | preview: false, 137 | preserveFocus: true, 138 | }); 139 | vscode.window.showTextDocument(vscode.Uri.file(genPath), { 140 | preview: false, 141 | preserveFocus: true, 142 | }); 143 | }; -------------------------------------------------------------------------------- /src/features/stress_test/stress_test.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | const fs = require("fs"); 3 | import { Utils} from "../../utils/utils"; 4 | import { platform } from "os"; 5 | import { maxLimitOfTestCases, minLimitOfTestCases, OS, CompilationLanguages, timeLimit} from "../../utils/consts"; 6 | import { compileAllFiles } from "./compile_all_files"; 7 | import { compareOutputs, readFile } from "../run_test_cases/run_test_cases"; 8 | import { runTestsWithTimeout } from "../run_test_cases/run_solution"; 9 | import { CodepalConfig, codepalConfigName, stressTestingFlag } from "../../utils/consts"; 10 | 11 | let numOfTestCases : number; 12 | let testsFolderPath : string; 13 | let solnOutputFilePath : string; 14 | let solnStderrFilePath : string; 15 | let brutePath : string; 16 | let bruteOutputFilePath : string; 17 | let bruteStderrFilePath : string; 18 | let genPath : string; 19 | let emptyInputFilePath : string; 20 | let generatedInputFilePath: string; 21 | let genStderrFilePath : string; 22 | 23 | const assignValuesToPath = async (solnPath: string):Promise => { 24 | numOfTestCases = vscode.workspace 25 | .getConfiguration(codepalConfigName) 26 | .get(CodepalConfig.numberOfStressTestingTestCases, 100); 27 | 28 | let fileExtension: string; 29 | 30 | const compilationLanguage = vscode.workspace 31 | .getConfiguration(codepalConfigName) 32 | .get(CodepalConfig.compilationLanguage); 33 | 34 | switch(compilationLanguage) { 35 | case CompilationLanguages.gcc: 36 | fileExtension = 'c'; 37 | break; 38 | 39 | case CompilationLanguages.cpp: 40 | fileExtension = 'cpp'; 41 | break; 42 | 43 | case CompilationLanguages.python: 44 | case CompilationLanguages.python2: 45 | case CompilationLanguages.python3: 46 | fileExtension = 'py'; 47 | break; 48 | 49 | case CompilationLanguages.java: 50 | fileExtension = 'java'; 51 | break; 52 | 53 | case CompilationLanguages.kotlin: 54 | fileExtension = 'kt'; 55 | break; 56 | 57 | default: 58 | vscode.window.showErrorMessage("Language used is not supported"); 59 | throw Error(); 60 | } 61 | 62 | const lastIndexOfSlash: number = solnPath.lastIndexOf("/"); 63 | const problemFolderPath: string = solnPath.slice(0, lastIndexOfSlash + 1); 64 | 65 | testsFolderPath = problemFolderPath + "stress_tests/"; 66 | 67 | solnOutputFilePath = testsFolderPath + 'soln.txt'; 68 | solnStderrFilePath = testsFolderPath + 'soln_stderr.txt'; 69 | 70 | brutePath = problemFolderPath + 'brute.' + fileExtension; 71 | bruteOutputFilePath = testsFolderPath + 'brute.txt'; 72 | bruteStderrFilePath = testsFolderPath + 'brute_stderr.txt'; 73 | 74 | genPath = problemFolderPath + 'gen.' + fileExtension; 75 | emptyInputFilePath = testsFolderPath + 'empty.txt'; 76 | generatedInputFilePath = `${testsFolderPath}gen.txt`; 77 | genStderrFilePath = `${testsFolderPath}gen_stderr.txt`; 78 | }; 79 | 80 | export const stressTest = async (filePath: string):Promise => { 81 | const os = platform() === "win32"?OS.windows : OS.linuxMac; 82 | 83 | let solnPath = Utils.pathRefine(filePath, os); 84 | 85 | if (vscode.window.activeTextEditor) { 86 | solnPath = vscode.window.activeTextEditor.document.uri.fsPath; 87 | solnPath = solnPath.replace(/\\/g, '/'); 88 | } 89 | 90 | await assignValuesToPath(solnPath); 91 | 92 | let successfulCompilation: boolean = await compileAllFiles(testsFolderPath, solnPath, brutePath, genPath); 93 | 94 | if(!successfulCompilation){ 95 | vscode.window.showErrorMessage('Unable to stress test.'); 96 | return; 97 | } 98 | 99 | if(numOfTestCases >= maxLimitOfTestCases){ 100 | numOfTestCases = maxLimitOfTestCases; 101 | } 102 | if(numOfTestCases <= minLimitOfTestCases){ 103 | numOfTestCases = minLimitOfTestCases; 104 | } 105 | 106 | let keyBinding:string = ''; 107 | if(platform() === "darwin"){ // Mac OS 108 | keyBinding = "Cmd+Shift+z"; 109 | } 110 | else{ // Windows or Linux 111 | keyBinding = "Ctrl+Shift+z"; 112 | } 113 | 114 | const resultFilePath: string = `${testsFolderPath}result.txt`; 115 | let i: number = 1; 116 | let passed: boolean = true; 117 | 118 | while (i <= numOfTestCases) { 119 | if(stressTestingFlag.stop === true){ 120 | break; 121 | } 122 | const commandLineArguments: string = `${i}`; 123 | 124 | vscode.window.setStatusBarMessage(`Running test case ${i}. Press ${keyBinding} to force stop Stress Testing`,timeLimit); 125 | 126 | try { 127 | 128 | let runResultGen = await runTestsWithTimeout ( 129 | genPath, 130 | emptyInputFilePath, 131 | generatedInputFilePath, 132 | testsFolderPath, 133 | genStderrFilePath, 134 | os, 135 | 'gen', 136 | commandLineArguments 137 | ); 138 | let runResultBrute = await runTestsWithTimeout ( 139 | brutePath, 140 | generatedInputFilePath, 141 | bruteOutputFilePath, 142 | testsFolderPath, 143 | bruteStderrFilePath, 144 | os, 145 | 'brute' 146 | ); 147 | let runResultSoln = await runTestsWithTimeout ( 148 | solnPath, 149 | generatedInputFilePath, 150 | solnOutputFilePath, 151 | testsFolderPath, 152 | solnStderrFilePath, 153 | os, 154 | 'soln' 155 | ); 156 | 157 | if (runResultGen === "Run time error" || runResultBrute === "Run time error" || runResultSoln === "Run time error") { 158 | return; 159 | } 160 | 161 | let testResult: boolean = await compareOutputs( 162 | bruteOutputFilePath, 163 | solnOutputFilePath 164 | ); 165 | 166 | let input: string = await readFile(generatedInputFilePath); 167 | let expectedOutput: string = await readFile(bruteOutputFilePath); 168 | let codeOutput: string = await readFile(solnOutputFilePath); 169 | let result : string = ""; 170 | if (testResult===true) { 171 | result = result + `Test ${i} Passed\n\n`; 172 | } 173 | else { 174 | result = result + `Test ${i} Failed\n\n`; 175 | } 176 | result = result + `Input ${i}: \n${input}\n\nBrute Force Output: \n${expectedOutput}\n\nObtained Output: \n${codeOutput}\n\n`; 177 | 178 | result = result + "________________________________________________________\n\n"; 179 | fs.writeFileSync(resultFilePath, result, (err: any) => { 180 | if (err) { 181 | vscode.window.showErrorMessage("Could not write result."); 182 | } 183 | }); 184 | 185 | if (!testResult) { 186 | vscode.window.showTextDocument(vscode.Uri.file(resultFilePath), { 187 | preview: false, 188 | viewColumn: vscode.ViewColumn.Beside, 189 | preserveFocus: true, 190 | }); 191 | 192 | passed = false; 193 | break; 194 | } 195 | } catch (err) { 196 | // Runtime errors also get logged here 197 | passed = false; 198 | return; 199 | } 200 | 201 | i++; 202 | } 203 | 204 | if(stressTestingFlag.stop === true){ 205 | vscode.window.showErrorMessage('Stress Testing interrupted'); 206 | stressTestingFlag.stop = false; 207 | } 208 | else if (passed === true) { 209 | vscode.window.showInformationMessage( 210 | `Solution matches with brute force for ${numOfTestCases} test cases.`, 211 | ); 212 | } 213 | else{ 214 | vscode.window.showInformationMessage( 215 | `In testcase ${i}, solution differs from brute force` 216 | ); 217 | } 218 | 219 | vscode.window.setStatusBarMessage('Stress Testing Done', timeLimit); 220 | }; 221 | -------------------------------------------------------------------------------- /src/features/submit_problem/submit_problem.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { platform } from "os"; 3 | import * as fs from "fs"; 4 | import { Utils } from "../../utils/utils"; 5 | import { OS } from "../../utils/consts"; 6 | 7 | export const submitProblem = async (path: string) => { 8 | try { 9 | path = Utils.pathRefine(path, platform() === "win32"?OS.windows : OS.linuxMac); 10 | 11 | if (vscode.window.activeTextEditor) { 12 | path = vscode.window.activeTextEditor.document.uri.fsPath; 13 | path = path.replace(/\\/g, '/'); 14 | } 15 | // ************ copying code to the clipboard ********************** 16 | const code = fs.readFileSync(path).toString(); 17 | vscode.env.clipboard.writeText(code); 18 | //****************************************************************** 19 | const jsonPath = path.substr(0, path.lastIndexOf("/")) + `/.problem.json`; 20 | const jsonData = JSON.parse(fs.readFileSync(jsonPath).toString()); 21 | vscode.env.openExternal(vscode.Uri.parse(`https://codeforces.com/contest/${jsonData.contestID}/submit/${jsonData.index}`, true)); 22 | vscode.window.showInformationMessage("Submit problem page opened"); 23 | } catch (err) { 24 | vscode.window.showErrorMessage(err); 25 | } 26 | }; -------------------------------------------------------------------------------- /src/features/user_profile/fetch_user_info_api.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import fetch from "node-fetch"; 3 | import { ProfileTreeItem } from "../../data_providers/user_profile/profile_tree_item"; 4 | import { ProfileTreeEnum } from "../../utils/consts"; 5 | export const fetchUserInfoApi = async ( 6 | codeforcesHandle: string 7 | ): Promise => { 8 | let arr: ProfileTreeItem[] = []; 9 | arr.push( 10 | new ProfileTreeItem( 11 | `Handle: ` + codeforcesHandle, 12 | ProfileTreeEnum.codeforcesHandleExists, 13 | vscode.TreeItemCollapsibleState.None 14 | ) 15 | ); 16 | try { 17 | arr.push(...(await getInfo(codeforcesHandle))); 18 | } catch {} 19 | return arr; 20 | }; 21 | const getTreeItem = (label: string): ProfileTreeItem => { 22 | return new ProfileTreeItem( 23 | label, 24 | "userInfo", 25 | vscode.TreeItemCollapsibleState.None 26 | ); 27 | }; 28 | const getInfo = async ( 29 | codeforcesHandle: string 30 | ): Promise => { 31 | const arr: ProfileTreeItem[] = []; 32 | const response = await fetch( 33 | `https://codeforces.com/api/user.info?handles=${codeforcesHandle}` 34 | ); 35 | if (response.ok) { 36 | const jsonResponse = await response.json(); 37 | const userObj = jsonResponse.result[0]; 38 | if (userObj.firstName || userObj.lastName) { 39 | arr.push( 40 | getTreeItem(`Name: ${userObj.firstName} ${userObj.lastName}`) 41 | ); 42 | } 43 | arr.push(getTreeItem(`Rating: ${userObj.rating}`)); 44 | arr.push(getTreeItem(`maxRating: ${userObj.maxRating}`)); 45 | arr.push(getTreeItem(`contribution: ${userObj.contribution}`)); 46 | arr.push(getTreeItem(`Rank: ${userObj.rank}`)); 47 | arr.push(getTreeItem(`maxRank: ${userObj.maxRank}`)); 48 | arr.push(getTreeItem(`Friend of: ${userObj.friendOfCount} Users`)); 49 | } 50 | return arr; 51 | }; 52 | -------------------------------------------------------------------------------- /src/features/user_profile/get_user_handle.ts: -------------------------------------------------------------------------------- 1 | import { platform } from "os"; 2 | import * as vscode from "vscode"; 3 | import * as fs from "fs"; 4 | import { ProfileProvider } from "../../data_providers/user_profile/profile_data_provider"; 5 | import { CodepalConfig, codepalConfigName, OS } from "../../utils/consts"; 6 | import path = require("path"); 7 | export const getUserHandle = async (profileProvider: ProfileProvider) => { 8 | let userHandle = await vscode.window.showInputBox({ 9 | placeHolder: "Enter your user handle", 10 | }); 11 | if (userHandle) { 12 | const os = platform() === "win32" ? OS.windows : OS.linuxMac; 13 | if (os === OS.linuxMac) { 14 | const rootPath = vscode.workspace.workspaceFolders 15 | ? vscode.workspace.workspaceFolders[0].uri.fsPath + "/" 16 | : "/"; 17 | if (rootPath !== "/") { 18 | try { 19 | if (!fs.existsSync(path.join(rootPath, ".vscode"))) { 20 | try { 21 | await fs.promises.mkdir( 22 | path.join(rootPath, ".vscode") 23 | ); 24 | } catch (e) { 25 | console.log("error inside"); 26 | } 27 | } 28 | const settingsPath = path.join( 29 | rootPath, 30 | ".vscode", 31 | "settings.json" 32 | ); 33 | console.log(settingsPath); 34 | if (!fs.existsSync(settingsPath)) { 35 | await fs.promises.writeFile( 36 | settingsPath, 37 | JSON.stringify({}) 38 | ); 39 | console.log("written settings"); 40 | } 41 | console.log("123"); 42 | const jsonData =await JSON.parse( 43 | fs.readFileSync(settingsPath).toString() 44 | ); 45 | console.log(jsonData); 46 | jsonData[ 47 | `${codepalConfigName}.${CodepalConfig.codeforcesHandle}` 48 | ] = userHandle; 49 | console.log(JSON.stringify(jsonData)); 50 | await fs.promises.writeFile( 51 | settingsPath, 52 | JSON.stringify(jsonData) 53 | ); 54 | 55 | console.log("1234"); 56 | } catch (e) { 57 | console.log(`error ${e}`); 58 | } 59 | } 60 | } 61 | profileProvider.refresh(); 62 | } 63 | }; 64 | -------------------------------------------------------------------------------- /src/test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import { runTests } from 'vscode-test'; 4 | 5 | async function main() { 6 | try { 7 | // The folder containing the Extension Manifest package.json 8 | // Passed to `--extensionDevelopmentPath` 9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 10 | 11 | // The path to test runner 12 | // Passed to --extensionTestsPath 13 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 14 | 15 | // Download VS Code, unzip it and run the integration test 16 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 17 | } catch (err) { 18 | console.error('Failed to run tests'); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | main(); 24 | -------------------------------------------------------------------------------- /src/test/suite/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | 3 | // You can import and use all API from the 'vscode' module 4 | // as well as import your extension to test it 5 | import * as vscode from 'vscode'; 6 | // import * as myExtension from '../../extension'; 7 | 8 | suite('Extension Test Suite', () => { 9 | vscode.window.showInformationMessage('Start all tests.'); 10 | 11 | test('Sample test', () => { 12 | assert.equal(-1, [1, 2, 3].indexOf(5)); 13 | assert.equal(-1, [1, 2, 3].indexOf(0)); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as Mocha from 'mocha'; 3 | import * as glob from 'glob'; 4 | 5 | export function run(): Promise { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: 'tdd', 9 | color: true 10 | }); 11 | 12 | const testsRoot = path.resolve(__dirname, '..'); 13 | 14 | return new Promise((c, e) => { 15 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 16 | if (err) { 17 | return e(err); 18 | } 19 | 20 | // Add files to the test suite 21 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 22 | 23 | try { 24 | // Run the mocha test 25 | mocha.run(failures => { 26 | if (failures > 0) { 27 | e(new Error(`${failures} tests failed.`)); 28 | } else { 29 | c(); 30 | } 31 | }); 32 | } catch (err) { 33 | console.error(err); 34 | e(err); 35 | } 36 | }); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /src/utils/consts.ts: -------------------------------------------------------------------------------- 1 | export const enum Command { 2 | helloWorld = "codepal.helloWorld", 3 | setEditorLayout = "vscode.setEditorLayout", 4 | vscodeOpen = "vscode.open", 5 | reloadProblems = "codepal.reloadProblems", 6 | reloadContests = "codepal.reloadContests", 7 | copyContestURL = "codepal.copyContestURL", 8 | createContestDirectory = "codepal.createContestDirectory", 9 | registerContest = "codepal.registerContest", 10 | copyProblemURL = "codepal.copyProblemURL", 11 | copyContestProblemURL = "codepal.copyContestProblemURL", 12 | openContest = "codepal.openContest", 13 | openProblemURL = "codepal.openProblemURL", 14 | openContestProblem = "codepal.openContestProblem", 15 | createProblemDirectory = "codepal.createProblemDirectory", 16 | createContestProblemDirectory = "codepal.createContestProblemDirectory", 17 | runTestCases = "codepal.runTestCases", 18 | openProblemStatement = "codepal.openProblemStatement", 19 | submitProblem = "codepal.submitProblem", 20 | addTestCases = "codepal.addTestCases", 21 | getProblemFilters = "codepal.getProblemFilters", 22 | stressTest = "codepal.stressTest", 23 | createStressTestingFiles = "codepal.createStressTestingFiles", 24 | stopStressTesting = "codepal.stopStressTesting", 25 | manualProblemFolderCreation = "codepal.manualProblemFolderCreation", 26 | manualContestFolderCreation = "codepal.manualContestFolderCreation", 27 | openAclDocumentation = "codepal.openAclDocumentation", 28 | creatAclCombinedFile = "codepal.createAclCombinedFile" 29 | } 30 | export const codepalConfigName = "codepal"; 31 | export const enum CodepalConfig { 32 | compilationLanguage = "compilationLanguage", 33 | codeTemplatePath = "codeTemplatePath", 34 | generatorTemplatePath = "generatorTemplatePath", 35 | codeforcesHandle = "codeforcesHandle", 36 | numberOfStressTestingTestCases = "numberOfStressTestingTestCases", 37 | enableAclSupport = "enableAclSupport", 38 | enableAclDocumentationButton = "enableAclDocumentationButton" 39 | } 40 | export const enum TreeViewIDs { 41 | contests = "codepalContests", 42 | problems = "codepalProblems", 43 | profile = 'codepalProfile' 44 | } 45 | export const enum SubmissionStatus { 46 | unattempted = "unattempted", 47 | accepted = "OK", 48 | failed = "FAILED" 49 | } 50 | export const enum CompilationLanguages { 51 | cpp = "g++", 52 | gcc = "gcc", 53 | java = "java", 54 | python = "python", 55 | python2 = "python2", 56 | python3 = "python3", 57 | kotlin = "kotlin", 58 | haskell = "haskell" 59 | 60 | } 61 | export const enum CompilationFlags { 62 | cpp = "g++ CompilationFlags", 63 | gcc = "gccCompilationFlags", 64 | java = "javaCompilationFlags", 65 | python = "pythonCompilationFlags", 66 | kotlin = "kotlinCompilationFlags", 67 | haskell = "haskellCompilationFlags", 68 | } 69 | export const enum ContestsPhase { 70 | finished = "FINISHED", 71 | coding = "CODING", 72 | before = "BEFORE", 73 | } 74 | export const enum ContestTreeEnum { 75 | runningContestType = "Running", 76 | futureContestType = "Future", 77 | pastContestType = "Past", 78 | contestLabel = "contest", 79 | futureContestLabel = "FutureContest", 80 | contestProblemType = "ContestProblem", 81 | contestTypeContextValue = "ContestType", 82 | } 83 | export const enum ProblemTreeEnum { 84 | problemContextValue = "problem", 85 | } 86 | export const enum ProfileTreeEnum { 87 | codeforcesHandleUndefined = "codeforcesHandleUndefined", 88 | codeforcesHandleExists = "codeforcesHandleExists" 89 | } 90 | export enum RatingsEnum { 91 | initialFromRating = 0, 92 | initialToRating = 4000, 93 | } 94 | export enum Urls { 95 | fetchContestsList = "https://codeforces.com/api/contest.list?gym=false", 96 | fetchProblemSet = "https://codeforces.com/api/problemset.problems", 97 | userInfo = "https://codeforces.com/api/user.info?handles" 98 | } 99 | 100 | export enum OS { 101 | linuxMac, 102 | windows 103 | } 104 | export const enum ErrorCodes { 105 | fileExists = "EEXIST", 106 | folderExists = "EEXIST", 107 | notFound = "ENOENT", 108 | noAccessPermission = "EACCES", 109 | noWritePermission = "EROFS" 110 | } 111 | export const enum Errors { 112 | timeLimitExceeded = "Time limit exceeded", 113 | runTimeError = "Run time error" 114 | } 115 | export const tagsByOR: string = "*combine tags by OR"; 116 | export const allTags: string[] = [ 117 | tagsByOR, 118 | "2-sat", 119 | "binary search", 120 | "bitmasks", 121 | "brute force", 122 | "chinese remainder theorem", 123 | "combinatorics", 124 | "constructive algorithms", 125 | "data structures", 126 | "dfs and similar", 127 | "divide and conquer", 128 | "dp", 129 | "dsu", 130 | "expression parsing", 131 | "fft", 132 | "flows", 133 | "games", 134 | "geometry", 135 | "graph matchings", 136 | "graphs", 137 | "greedy", 138 | "hashing", 139 | "implementation", 140 | "interactive", 141 | "math", 142 | "matrices", 143 | "meet-in-the-middle", 144 | "number theory", 145 | "probabilities", 146 | "schedules", 147 | "shortest paths", 148 | "sortings", 149 | "string suffix structures", 150 | "strings", 151 | "ternary search", 152 | "trees", 153 | "two pointers", 154 | ]; 155 | 156 | export const statusOfProblem: string[] = [ 157 | "unattempted", 158 | "OK", 159 | "FAILED", 160 | ]; 161 | 162 | export const generatorTemplate = { 163 | cpp: 164 | `#include 165 | 166 | using namespace std; 167 | 168 | signed main(signed argc, char* argv[]){ 169 | ios_base::sync_with_stdio(false); 170 | cin.tie(NULL); 171 | srand(atoi(argv[1])); 172 | 173 | // generate test cases with same format as given in problem 174 | 175 | return 0; 176 | }`, 177 | 178 | c: 179 | `#include 180 | #include 181 | 182 | int main(signed argc, char* argv[]){ 183 | srand(atoi(argv[1])); 184 | 185 | // generate test cases with same format as given in problem 186 | 187 | return 0; 188 | } 189 | `, 190 | 191 | python: 192 | `import sys, random 193 | 194 | random.seed(int(sys.argv[1])) 195 | 196 | # generate test cases with same format as given in problem 197 | 198 | `, 199 | 200 | python2: 201 | `import sys, random 202 | 203 | random.seed(int(sys.argv[1])) 204 | 205 | # generate test cases with same format as given in problem 206 | 207 | `, 208 | 209 | python3: 210 | `import sys, random 211 | 212 | random.seed(int(sys.argv[1])) 213 | 214 | # generate test cases with same format as given in problem 215 | 216 | `, 217 | 218 | java: 219 | `import java.util.*; 220 | public class gen { 221 | public static void main(String[] args) 222 | { 223 | Random r = new Random(); 224 | r.setSeed(Integer.parseInt(args[0])); 225 | // generate test cases with same format as given in problem 226 | 227 | } 228 | } 229 | `, 230 | kotlin: 231 | `import java.util.* 232 | 233 | val random = Random() 234 | 235 | fun rand(from: Int, to: Int) : Int { 236 | return random.nextInt(to - from) + from 237 | } 238 | fun main(){ 239 | var r = rand(1, 100); 240 | } 241 | ` 242 | }; 243 | 244 | export let stressTestingFlag = { 245 | stop: false as boolean 246 | }; 247 | 248 | export let extensionPaths = { 249 | path: '' as String, 250 | libraryPath: '' as String, 251 | expanderPyPath: '' as String 252 | }; 253 | 254 | export let tle = { 255 | tleFlag: false as boolean 256 | }; 257 | 258 | export const maxLimitOfTestCases = 10000; 259 | export const minLimitOfTestCases = 10; 260 | export const timeLimit = 6000; // 6000 milliseconds 261 | -------------------------------------------------------------------------------- /src/utils/utils.ts: -------------------------------------------------------------------------------- 1 | import { OS } from "./consts"; 2 | 3 | export class Utils{ 4 | static pathRefine = (filePath: string, os: number): string => { 5 | let path = String(filePath); 6 | path = path.replace(/\%20/g, ' '); 7 | path = path.replace(/\%21/g, '!'); 8 | path = path.replace(/\%28/g, '('); 9 | path = path.replace(/\%29/g, ')'); 10 | path = path.replace(/\%23/g, '#'); 11 | path = path.replace(/\%27/g, '\''); 12 | path = path.replace(/\%2C/g, ','); 13 | path = path.replace(/\%3A/g, ':'); 14 | path = path.replace(/\%2B/g, '+'); 15 | path = path.replace(/\%3D/g, '='); 16 | if(os === OS.windows) { 17 | // For Windows 18 | path = path.slice(8); 19 | } 20 | else if(os === OS.linuxMac) { 21 | // For Linux 22 | path = path.slice(7); 23 | } 24 | 25 | return path; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "strict": true /* enable all strict type-checking options */ 12 | /* Additional Checks */ 13 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 14 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 15 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 16 | }, 17 | "exclude": [ 18 | "node_modules", 19 | ".vscode-test" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /vsc-extension-quickstart.md: -------------------------------------------------------------------------------- 1 | # Welcome to your VS Code Extension 2 | 3 | ## What's in the folder 4 | 5 | * This folder contains all of the files necessary for your extension. 6 | * `package.json` - this is the manifest file in which you declare your extension and command. 7 | * The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesn’t yet need to load the plugin. 8 | * `src/extension.ts` - this is the main file where you will provide the implementation of your command. 9 | * The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`. 10 | * We pass the function containing the implementation of the command as the second parameter to `registerCommand`. 11 | 12 | ## Get up and running straight away 13 | 14 | * Press `F5` to open a new window with your extension loaded. 15 | * Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`. 16 | * Set breakpoints in your code inside `src/extension.ts` to debug your extension. 17 | * Find output from your extension in the debug console. 18 | 19 | ## Make changes 20 | 21 | * You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`. 22 | * You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. 23 | 24 | 25 | ## Explore the API 26 | 27 | * You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`. 28 | 29 | ## Run tests 30 | 31 | * Open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Extension Tests`. 32 | * Press `F5` to run the tests in a new window with your extension loaded. 33 | * See the output of the test result in the debug console. 34 | * Make changes to `src/test/suite/extension.test.ts` or create new test files inside the `test/suite` folder. 35 | * The provided test runner will only consider files matching the name pattern `**.test.ts`. 36 | * You can create folders inside the `test` folder to structure your tests any way you want. 37 | 38 | ## Go further 39 | 40 | * Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension). 41 | * [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VSCode extension marketplace. 42 | * Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration). 43 | --------------------------------------------------------------------------------