├── .dockerignore ├── .github ├── dependabot.yml └── workflows │ └── build-k8s.yaml ├── .gitignore ├── .yarn └── releases │ └── yarn-3.2.2.cjs ├── .yarnrc.yml ├── CODEOWNERS ├── Dockerfile ├── LICENSE ├── add_debug.py ├── bootstrap ├── bootstrap.zip ├── config-dark.json └── config.json ├── client ├── client.coffee ├── client.js ├── components │ ├── Achieves.coffee │ ├── Achieves.css │ ├── AllComments.coffee │ ├── AllSubmits.coffee │ ├── ApproveFindMistake.coffee │ ├── BestSubmits.coffee │ ├── BestSubmits.css │ ├── BlogPosts.coffee │ ├── CfStatus.coffee │ ├── CfStatus.css │ ├── Checkins.coffee │ ├── CommentList.coffee │ ├── ConnectedNotifications.coffee │ ├── Contest.coffee │ ├── ContributeByWeekCalendar.coffee │ ├── ContributeByWeekCalendar.css │ ├── Dashboard.coffee │ ├── DefaultHelmet.coffee │ ├── EditUser.coffee │ ├── EditUser.css │ ├── EditUserForAdmin.coffee │ ├── EditablePage.coffee │ ├── Editor.coffee │ ├── Editor.css │ ├── EvocaPaymentSuccess.coffee │ ├── FieldGroup.coffee │ ├── FindMistake.coffee │ ├── FindMistake.css │ ├── FindMistakeList.coffee │ ├── FullNews.coffee │ ├── FullUser.coffee │ ├── FullUser.css │ ├── GotoProvider.coffee │ ├── Invoice.coffee │ ├── Invoice.css │ ├── LangCorrector.tsx │ ├── LangSwitch.coffee │ ├── Level.coffee │ ├── Level.css │ ├── Loader.coffee │ ├── Login.coffee │ ├── Material.coffee │ ├── News.coffee │ ├── Payment.coffee │ ├── PaymentSuccess.coffee │ ├── Problem.coffee │ ├── Register.coffee │ ├── RegisteredUsers.coffee │ ├── Result.coffee │ ├── Result.css │ ├── Review.coffee │ ├── ReviewResult.coffee │ ├── ReviewResult.css │ ├── Root.coffee │ ├── Root.css │ ├── Sceleton.coffee │ ├── Sceleton.css │ ├── ScrollToTop.coffee │ ├── ShadowedSwitch.coffee │ ├── ShadowedSwitch.css │ ├── SolvedByWeek.coffee │ ├── SolvedByWeek.css │ ├── Submit.coffee │ ├── Submit.css │ ├── SubmitForm.coffee │ ├── SubmitList.coffee │ ├── SubmitList.css │ ├── SubmitListTable.coffee │ ├── SubmitListTable.css │ ├── TShirts.tsx │ ├── Table.coffee │ ├── Table.css │ ├── TableRow.coffee │ ├── TableRow.css │ ├── ThemeCss.coffee │ ├── ThemeSwitch.coffee │ ├── TopPanel.coffee │ ├── TopPanel.css │ ├── Tree.coffee │ ├── Tree.css │ ├── UserBadge.coffee │ ├── UserName.coffee │ ├── UserName.css │ ├── UserTableHeader.coffee │ ├── UsersWithAchieve.coffee │ ├── YaMetrikaHit.coffee │ └── global.css ├── lang │ └── lang.coffee ├── lib │ ├── BrowserNotifications.coffee │ ├── ConnectedComponent.coffee │ ├── WebsocketsSet.coffee │ ├── achieves.coffee │ ├── addTotal.coffee │ ├── adminCapabilities.ts │ ├── awaitAll.coffee │ ├── callApi.coffee │ ├── correctUrl.test.ts │ ├── correctUrl.ts │ ├── findMistake.coffee │ ├── graduateYearToClass.coffee │ ├── groups.coffee │ ├── isContestRequired.coffee │ ├── isPaid.coffee │ ├── languages.coffee │ ├── level.test.ts │ ├── level.ts │ ├── needDeactivatedWarning.coffee │ ├── outcomeToText.coffee │ ├── requiredProblemsByLevelMinor.ts │ ├── stripLabel.ts │ ├── toUtf8.coffee │ ├── withLang.coffee │ ├── withMyResults.coffee │ ├── withMyUser.coffee │ └── withTheme.coffee ├── mathJaxObserver.coffee ├── pages │ ├── AchievesPage.coffee │ ├── AllCommentsPage.coffee │ ├── AllSubmitsPage.coffee │ ├── ApproveFindMistakePage.coffee │ ├── CheckinsPage.coffee │ ├── DashboardPage.coffee │ ├── EditUserPage.coffee │ ├── FindMistakeListPage.coffee │ ├── FindMistakePage.coffee │ ├── FindMistakeProblemListPage.coffee │ ├── FullNewsPage.coffee │ ├── FullUserPage.coffee │ ├── LoginPage.coffee │ ├── MaterialPage.coffee │ ├── PaymentPage.coffee │ ├── PaymentSuccessPage.coffee │ ├── RegisterPage.coffee │ ├── RegisteredUsersPage.coffee │ ├── ReviewPage.coffee │ ├── ReviewResultPage.coffee │ ├── RootPage.coffee │ ├── SolvedByWeekPage.coffee │ ├── SubmitPage.coffee │ ├── TablePage.coffee │ ├── UserBadgePage.coffee │ └── UsersWithAchievePage.coffee ├── redux │ ├── actions.coffee │ ├── getters.coffee │ ├── reducers.coffee │ └── store.coffee ├── routes.coffee └── testSystems │ ├── Codeforces.coffee │ ├── Ejudge.coffee │ ├── Informatics.coffee │ ├── TestSystem.coffee │ └── TestSystemRegistry.coffee ├── highlight └── highlight.zip ├── jest.config.js ├── k8s ├── app-network-networkpolicy.yaml ├── cert-manager-prod.yaml ├── data-persistentvolumeclaim.yaml ├── db-deployment.yaml ├── db-service.yaml ├── ije-role-binding.yaml ├── ije-service-account.yaml ├── ingress-config.yaml ├── ingress-nginx-controller.yaml ├── ingress-no-tls.yaml ├── ingress.yaml ├── mgob-dep.yaml ├── nodejs-deployment.yaml ├── nodejs-service.yaml ├── readme.txt ├── role-binding.yaml └── service-account.yaml ├── logo ├── algoprog-2022.png ├── algoprog.svg ├── emoji_blog.png ├── emoji_main.png ├── emoji_notes.png ├── favicon.ico ├── favicon.png ├── favicon_blog.ico ├── favicon_blog.png ├── favicon_notes.ico ├── favicon_notes.png ├── head-20191006.png ├── head-20191027.png ├── head-20191208.png ├── head-20200216.png ├── head-20200719.png ├── head-20210724.png ├── head-20210725-1.png ├── head-20210725-2.png ├── head-20210725-3.png ├── head-20210727.png ├── head-20210728.png ├── head-20210729.png ├── logo-1920-1080-2024.png ├── logo-1920-1080.png ├── logo-1920-1200.png ├── logo_a.png ├── logo_big.png ├── logo_h.png └── topsort │ ├── graph_colored_h.2.pdf │ ├── graph_colored_v.2.pdf │ ├── topsort-v.png │ ├── topsort-v.svg │ └── topsort.jpg ├── mongo.cmd ├── mongo.sh ├── package.json ├── public ├── about-1-levels-en.png ├── about-1-levels.png ├── about-2-submit-en.png ├── about-2-submit.png ├── about-3-results-en.png ├── about-3-results.png ├── about-4-comments-en.png ├── about-4-comments.png ├── about-5-ac-en.png ├── about-5-ac.png ├── about-6-ig-en.png ├── about-6-ig.png ├── about-7-best-en.png ├── about-7-best.png ├── additional_dark.css ├── bootstrap.min.css ├── bootstrapdark.min.css ├── choco-light.png ├── choco-strut.png ├── choco.png ├── darklight.css ├── favicon.ico ├── highlight.css ├── highlight.pack.js ├── ib.odt ├── ib.pdf ├── main.css ├── mastercard.svg ├── mastercard_visa.svg ├── mir_en.svg ├── mir_ru.svg ├── oferta.docx ├── oferta.pdf ├── privacy.odt ├── privacy.pdf ├── qiwi.svg ├── raion_archive.pdf ├── robots.txt ├── sbp.svg ├── testsystems.css ├── tinkoff.png └── visa.svg ├── scripts ├── 2021_01_05_move_users.py ├── 2021_01_17_move_users_back.py ├── 2022_05_02_get_submits.py ├── 2022_07_10_translate_topics.py ├── rating.py └── upload_statements.py ├── server ├── api │ ├── dashboard.coffee │ ├── register.coffee │ ├── setOutcome.coffee │ └── setupApi.coffee ├── calculations │ ├── calculateAchieves.coffee │ ├── calculateCalendar.coffee │ ├── calculateCfRating.coffee │ ├── calculateChocos.coffee │ ├── calculateLevel.ts │ ├── calculateRatingEtc.ts │ ├── ratingConstants.coffee │ ├── updateResults.coffee │ └── updateTableResults.coffee ├── cmrh.conf.js ├── cron │ ├── cron.coffee │ ├── downloadBlog.coffee │ ├── downloadSubmits.coffee │ ├── sendMetrics.coffee │ ├── submitSubmits.coffee │ └── updateCf.coffee ├── findMistake │ └── processForFindMistake.coffee ├── hashes │ ├── calculateHashes.coffee │ └── findSimilarSubmits.coffee ├── informatics │ └── InformaticsUser.coffee ├── lib │ ├── browserWrapper.ts │ ├── cbrf.ts │ ├── download.ts │ ├── normalizeCode.coffee │ ├── npd.coffee │ ├── otpGetter.ts │ ├── receipts.ts │ ├── setDirty.coffee │ ├── sleep.coffee │ ├── telegramBot.coffee │ ├── translate.coffee │ └── translateProblems.coffee ├── log.coffee ├── log.ts ├── materials │ ├── data-en │ │ ├── level_about.coffee │ │ ├── mainLevels.coffee │ │ ├── news.coffee │ │ ├── root.coffee │ │ └── tables.coffee │ ├── data │ │ ├── level_11D.coffee │ │ ├── level_1D.coffee │ │ ├── level_3D.coffee │ │ ├── level_5D.coffee │ │ ├── level_7D.coffee │ │ ├── level_9D.coffee │ │ ├── level_about.coffee │ │ ├── level_nnoi.coffee │ │ ├── level_nnoi2016.coffee │ │ ├── level_nnoi2018.coffee │ │ ├── level_nnoi2019.coffee │ │ ├── level_nnoi2020.coffee │ │ ├── level_nnoi2021.coffee │ │ ├── level_nnoi2022.coffee │ │ ├── level_nnoi2023.coffee │ │ ├── level_reg.coffee │ │ ├── level_reg2009.coffee │ │ ├── level_reg2010.coffee │ │ ├── level_reg2011.coffee │ │ ├── level_reg2012.coffee │ │ ├── level_reg2013.coffee │ │ ├── level_reg2014.coffee │ │ ├── level_reg2015.coffee │ │ ├── level_reg2016.coffee │ │ ├── level_reg2017.coffee │ │ ├── level_reg2018.coffee │ │ ├── level_reg2019.coffee │ │ ├── level_reg2020.coffee │ │ ├── level_reg2021.coffee │ │ ├── level_reg2022.coffee │ │ ├── level_reg2023.coffee │ │ ├── level_reg2024.coffee │ │ ├── level_roi.coffee │ │ ├── level_roi2004.coffee │ │ ├── level_roi2005.coffee │ │ ├── level_roi2006.coffee │ │ ├── level_roi2007.coffee │ │ ├── level_roi2008.coffee │ │ ├── level_roi2009.coffee │ │ ├── level_roi2010.coffee │ │ ├── level_roi2011.coffee │ │ ├── level_roi2012.coffee │ │ ├── level_roi2013.coffee │ │ ├── level_roi2014.coffee │ │ ├── level_roi2015.coffee │ │ ├── level_roi2016.coffee │ │ ├── level_roi2017.coffee │ │ ├── level_roi2018.coffee │ │ ├── level_roi2019.coffee │ │ ├── level_roi2021.coffee │ │ ├── level_roi2022.coffee │ │ ├── level_roi2023.coffee │ │ ├── level_sch.coffee │ │ ├── level_sch2021.coffee │ │ ├── mainLevels.coffee │ │ ├── news.coffee │ │ ├── root.coffee │ │ ├── tables.coffee │ │ └── topics │ │ │ ├── 2sat.coffee │ │ │ ├── _template.coffee │ │ │ ├── advanced_numbers.coffee │ │ │ ├── advanced_scanline.coffee │ │ │ ├── aho_corasick.coffee │ │ │ ├── arithmeticalOperations.coffee │ │ │ ├── arrays.coffee │ │ │ ├── backtrack.coffee │ │ │ ├── bfs.coffee │ │ │ ├── bfs_01.coffee │ │ │ ├── binary_trees_and_trie.coffee │ │ │ ├── binsearch.coffee │ │ │ ├── bit_operations.coffee │ │ │ ├── cartesian_tree.coffee │ │ │ ├── cartesian_tree_implicit.coffee │ │ │ ├── codeforces.coffee │ │ │ ├── combinatorics.coffee │ │ │ ├── complexity.coffee │ │ │ ├── count_sort.coffee │ │ │ ├── cpp.coffee │ │ │ ├── debugging.coffee │ │ │ ├── dfs_advanced.coffee │ │ │ ├── dfs_simple.coffee │ │ │ ├── dijkstra.coffee │ │ │ ├── dijkstra_with_heap.coffee │ │ │ ├── divide_and_conquer.coffee │ │ │ ├── dp_advanced.coffee │ │ │ ├── dp_bayans.coffee │ │ │ ├── dp_hard.coffee │ │ │ ├── dp_middle.coffee │ │ │ ├── dp_sbory.coffee │ │ │ ├── dp_simple.coffee │ │ │ ├── dsu.coffee │ │ │ ├── events_sort.coffee │ │ │ ├── fenwick.coffee │ │ │ ├── floats.coffee │ │ │ ├── flows.coffee │ │ │ ├── floyd_and_fb.coffee │ │ │ ├── games_cyclic.coffee │ │ │ ├── games_simple.coffee │ │ │ ├── gcd.coffee │ │ │ ├── geometry_advanced.coffee │ │ │ ├── geometry_middle.coffee │ │ │ ├── geometry_simple.coffee │ │ │ ├── graphs_simple.coffee │ │ │ ├── greedy_advanced.coffee │ │ │ ├── greedy_simple.coffee │ │ │ ├── grundy.coffee │ │ │ ├── hash.coffee │ │ │ ├── heap.coffee │ │ │ ├── hld.coffee │ │ │ ├── ifs.coffee │ │ │ ├── inclusion_exclusion.coffee │ │ │ ├── kmp.coffee │ │ │ ├── lca.coffee │ │ │ ├── linked_lists.coffee │ │ │ ├── long_arithmetics.coffee │ │ │ ├── loops.coffee │ │ │ ├── mass_operations.coffee │ │ │ ├── matching.coffee │ │ │ ├── matrices.coffee │ │ │ ├── maxmatching.coffee │ │ │ ├── mincost_maxflow.coffee │ │ │ ├── numeral_systems.coffee │ │ │ ├── persistency.coffee │ │ │ ├── prefixSums.coffee │ │ │ ├── primes.coffee │ │ │ ├── pythonAdditional.coffee │ │ │ ├── recursion.coffee │ │ │ ├── segment_tree.coffee │ │ │ ├── sorting.coffee │ │ │ ├── sparse_tables.coffee │ │ │ ├── sqrt_decomposition.coffee │ │ │ ├── stack.coffee │ │ │ ├── stl.coffee │ │ │ ├── strings.coffee │ │ │ ├── suffixes.coffee │ │ │ ├── technical.coffee │ │ │ ├── tertiary_search.coffee │ │ │ ├── testing_advanced.coffee │ │ │ ├── two_pointers.coffee │ │ │ └── z_function.coffee │ ├── downloadMaterials.coffee │ └── lib │ │ ├── MaterialList.coffee │ │ ├── contest.coffee │ │ ├── epigraph.coffee │ │ ├── label.coffee │ │ ├── labelLink.coffee │ │ ├── level.coffee │ │ ├── link.coffee │ │ ├── main.coffee │ │ ├── news.coffee │ │ ├── newsItem.coffee │ │ ├── page.coffee │ │ ├── problem.coffee │ │ ├── simpleLevel.coffee │ │ ├── table.coffee │ │ ├── topic.coffee │ │ └── util.coffee ├── metrics │ ├── graphite.coffee │ └── metrics.coffee ├── models │ ├── AdminAction.ts │ ├── BlogPost.coffee │ ├── Calendar.coffee │ ├── Checkin.coffee │ ├── Config.coffee │ ├── FindMistake.coffee │ ├── Hash.coffee │ ├── Material.coffee │ ├── Payment.coffee │ ├── SubmitComment.coffee │ ├── SubmitProcess.coffee │ ├── TableResults.coffee │ ├── UserPrivate.coffee │ ├── cfResult.coffee │ ├── problem.coffee │ ├── registeredUser.coffee │ ├── result.coffee │ ├── submit.coffee │ ├── table.coffee │ └── user.coffee ├── mongo │ ├── MongooseCallbackManager.coffee │ └── mongo.coffee ├── passport.coffee ├── server.coffee ├── ssr │ └── renderOnServer.coffee └── testSystems │ ├── Codeforces.coffee │ ├── Ejudge.coffee │ ├── Informatics.coffee │ ├── TestSystem.coffee │ ├── TestSystemRegistry.coffee │ ├── codeforces │ ├── CodeforcesSubmitDownloader.coffee │ └── aes.min.js │ ├── ejudge │ └── EjudgeSubmitDownloader.coffee │ └── informatics │ └── InformaticsSubmitDownloader.coffee ├── todo.txt ├── tsconfig.json ├── webpack.config.js └── yarn.lock /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | /data 4 | log 5 | *.orig 6 | t 7 | scripts/standings 8 | .git 9 | .gitignore 10 | Dockerfile 11 | .dockerignore 12 | k8s 13 | .github 14 | .yarn/* 15 | !.yarn/patches 16 | !.yarn/plugins 17 | !.yarn/releases 18 | !.yarn/sdks 19 | !.yarn/versions 20 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Maintain dependencies for GitHub Actions 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "daily" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | /data 4 | log 5 | v2 6 | *.orig 7 | run_bearer.sh 8 | t 9 | scripts/start.sh 10 | scripts/log* 11 | scripts/standings 12 | *~ 13 | k8s/*secret* 14 | k8s/ingress-apply.sh 15 | k8s/apply-ingress.sh 16 | .pnp.* 17 | .yarn/* 18 | !.yarn/patches 19 | !.yarn/plugins 20 | !.yarn/releases 21 | !.yarn/sdks 22 | !.yarn/versions -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | yarnPath: .yarn/releases/yarn-3.2.2.cjs 4 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @petr-kalinin 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:16 2 | 3 | RUN apt-get update \ 4 | && apt-get install -y wget gnupg \ 5 | && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \ 6 | && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \ 7 | && apt-get update \ 8 | && apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \ 9 | --no-install-recommends \ 10 | && rm -rf /var/lib/apt/lists/* 11 | 12 | RUN mkdir -p /home/node/app/node_modules && \ 13 | mkdir -p /home/node/app/.yarn/releases && \ 14 | chown -R node:node /home/node/app 15 | 16 | WORKDIR /home/node/app 17 | 18 | COPY package*.json ./ 19 | COPY yarn.lock ./ 20 | COPY .yarnrc.yml ./ 21 | COPY .yarn/releases/* ./.yarn/releases 22 | 23 | USER node 24 | 25 | RUN yarn install 26 | 27 | COPY --chown=node:node . . 28 | 29 | ENV NODE_ENV production 30 | 31 | RUN yarn run build 32 | 33 | EXPOSE 3000 34 | 35 | CMD [ "yarn", "run", "start:server" ] -------------------------------------------------------------------------------- /add_debug.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | count = 0 4 | def marker(line): 5 | global count 6 | result = "" 7 | for i in line: 8 | if i != " ": 9 | break 10 | result += " " 11 | s = "_".join([str(count)] * 1000) 12 | result += "_debug_marker = {{qwe: '{}'}}\n".format(s) 13 | count += 1 14 | return result 15 | 16 | def convert(file): 17 | with open(file, encoding="cp866") as f: 18 | lines = f.readlines() 19 | result = "" 20 | for line in lines: 21 | #if "await" in line and "noawait" not in line: 22 | # result += marker(line) 23 | if "_debug_marker" not in line: 24 | result += line 25 | with open(file, "w", encoding="cp866") as f: 26 | f.write(result) 27 | 28 | 29 | data = os.walk(".") 30 | for d in data: 31 | dirname = d[0] 32 | for f in d[2]: 33 | file = os.path.join(dirname, f) 34 | if not os.path.splitext(file)[1] == ".coffee": 35 | continue 36 | convert(file) 37 | 38 | 39 | # MaterialsDownloader 40 | # tableSchema 41 | -------------------------------------------------------------------------------- /bootstrap/bootstrap.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/bootstrap/bootstrap.zip -------------------------------------------------------------------------------- /client/client.js: -------------------------------------------------------------------------------- 1 | import './css/sample.css' 2 | -------------------------------------------------------------------------------- /client/components/Achieves.css: -------------------------------------------------------------------------------- 1 | .achieve { 2 | display: inline-block; 3 | font-size: 70%; 4 | margin: 2px; 5 | padding: 2px; 6 | border-radius: 4px; 7 | color: black; 8 | } 9 | 10 | .achieve.big { 11 | font-size: 200%; 12 | margin: 10px; 13 | padding: 10px; 14 | border-radius: 20px; 15 | } 16 | 17 | .achieves { 18 | display: inline-block; 19 | } -------------------------------------------------------------------------------- /client/components/BestSubmits.css: -------------------------------------------------------------------------------- 1 | .submit + .submit { 2 | padding-top: 15px; 3 | border-top: 1px solid grey; 4 | margin-top: 15px; 5 | } 6 | .modal { 7 | width: 90% !important; 8 | } 9 | -------------------------------------------------------------------------------- /client/components/CfStatus.css: -------------------------------------------------------------------------------- 1 | .color { 2 | font-weight: bold; 3 | } 4 | 5 | .progress { 6 | font-weight: bold; 7 | } 8 | -------------------------------------------------------------------------------- /client/components/ConnectedNotifications.coffee: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import {connect} from 'react-redux'; 4 | 5 | import Notifications from 'react-notification-system-redux'; 6 | 7 | class ConnectedNotifications extends React.Component 8 | render: () -> 9 | 10 | 11 | export default connect( 12 | (state) -> ({ notifications: state.notifications }) 13 | )(ConnectedNotifications); 14 | -------------------------------------------------------------------------------- /client/components/ContributeByWeekCalendar.css: -------------------------------------------------------------------------------- 1 | .clearfix::after { 2 | content: ""; 3 | clear: both; 4 | display: table; 5 | } 6 | 7 | .outerDiv { 8 | overflow: auto; 9 | } 10 | 11 | .innerDiv { 12 | } 13 | -------------------------------------------------------------------------------- /client/components/DefaultHelmet.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import {Helmet} from 'react-helmet' 4 | 5 | import {LangRaw} from '../lang/lang' 6 | import withLang from '../lib/withLang' 7 | 8 | DefaultHelmet = (props) -> 9 | 10 | 11 | 12 | export default withLang(DefaultHelmet) 13 | -------------------------------------------------------------------------------- /client/components/EditUser.css: -------------------------------------------------------------------------------- 1 | .form { 2 | margin: 0px; 3 | padding: 0px; 4 | margin-bottom: 5px; 5 | } 6 | .divInput{ 7 | width: 300px; 8 | } 9 | 10 | .youHaveProblem{ 11 | width: 100%; 12 | margin-bottom: 1px; 13 | } 14 | .inp{ 15 | width:100%; 16 | } 17 | .error{ 18 | border:1px solid #a94442; 19 | } -------------------------------------------------------------------------------- /client/components/Editor.css: -------------------------------------------------------------------------------- 1 | .editor { 2 | border: 1px solid black; 3 | margin-top: 1ex; 4 | } 5 | -------------------------------------------------------------------------------- /client/components/EvocaPaymentSuccess.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | import { withRouter } from 'react-router' 3 | 4 | import Grid from 'react-bootstrap/lib/Grid' 5 | 6 | import Lang from '../lang/lang' 7 | 8 | import ConnectedComponent from '../lib/ConnectedComponent' 9 | import withMyUser from '../lib/withMyUser' 10 | 11 | getOrderId = (location) -> 12 | return (new URLSearchParams(location.search)).get("orderId") || "" 13 | 14 | 15 | class EvocaPaymentSuccess extends React.Component 16 | constructor: (props) -> 17 | super(props) 18 | 19 | render: () -> 20 | 21 | {if @props.status.status 22 | <> 23 | {Lang("payment_successful_message")} 24 | 25 | 26 | else 27 | <> 28 | {Lang("payment_error")} 29 | 30 | } 31 | 32 | 33 | options = 34 | urls: (props) -> 35 | if props?.myUser?._id 36 | return 37 | status: "evocaStatus/" + getOrderId(props.location) 38 | recentReceipt: "recentReceipt/#{props.myUser._id}" 39 | return {} 40 | 41 | timeout: 20 * 1000 42 | 43 | export default withRouter(withMyUser(ConnectedComponent(EvocaPaymentSuccess, options))) -------------------------------------------------------------------------------- /client/components/FieldGroup.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import FormGroup from 'react-bootstrap/lib/FormGroup' 4 | import FormControl from 'react-bootstrap/lib/FormControl' 5 | import ControlLabel from 'react-bootstrap/lib/ControlLabel' 6 | import HelpBlock from 'react-bootstrap/lib/HelpBlock' 7 | import Alert from 'react-bootstrap/lib/Alert' 8 | 9 | export default FieldGroup = ({ id, label, help, setField, state, validationState, error, props... }) => 10 | onChange = (e) => 11 | setField(id, e.target.value) 12 | value = if "value" of props then props.value else state[id] 13 | 14 | {label && {label}} 15 | {if props.type == "radio" 16 | props.children 17 | else 18 | `` 19 | } 20 | {help && {help}} 21 | {error && {error}} 22 | 23 | -------------------------------------------------------------------------------- /client/components/FindMistake.css: -------------------------------------------------------------------------------- 1 | .top { 2 | display: flex; 3 | justify-content: space-between; 4 | } 5 | -------------------------------------------------------------------------------- /client/components/FullNews.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | import Lang from '../lang/lang' 3 | 4 | export default News = (props) -> 5 |
6 |

{Lang("news")}

7 | { 8 | res = [] 9 | a = (el) -> res.push(el) 10 | for m, i in props.news.materials 11 | a
12 |

{m.title}

13 |
14 |
15 | res 16 | } 17 |
18 | -------------------------------------------------------------------------------- /client/components/FullUser.css: -------------------------------------------------------------------------------- 1 | .chocos_table { 2 | margin-bottom:15px; 3 | } 4 | .chocos_td { 5 | padding-right: 10px; 6 | } 7 | -------------------------------------------------------------------------------- /client/components/GotoProvider.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { withRouter } from 'react-router' 4 | 5 | class GotoProvider extends React.Component 6 | componentDidMount: (prevProps) -> 7 | window.goto = (url) => 8 | (e) => 9 | if e 10 | e.preventDefault() 11 | @props.history.push(url) 12 | return false 13 | 14 | render: -> 15 | this.props.children 16 | 17 | export default withRouter(GotoProvider) 18 | -------------------------------------------------------------------------------- /client/components/Invoice.css: -------------------------------------------------------------------------------- 1 | #ip_data { 2 | 3 | } 4 | #invoice_data_md { 5 | text-align: right; 6 | } 7 | #header { 8 | padding-top: 1ex; 9 | padding-bottom: 1ex; 10 | } 11 | #table { 12 | 13 | } 14 | #total { 15 | 16 | } 17 | #signature { 18 | 19 | } -------------------------------------------------------------------------------- /client/components/LangCorrector.tsx: -------------------------------------------------------------------------------- 1 | import React = require('react') 2 | 3 | import { withRouter, Redirect } from 'react-router' 4 | 5 | import correctUrl from '../lib/correctUrl' 6 | // @ts-ignore 7 | import withLang from '../lib/withLang' 8 | 9 | // @ts-ignore 10 | import {LangRaw} from '../lang/lang' 11 | 12 | 13 | function LangCorrector(props) { 14 | var label = LangRaw("material_suffix", props.lang) 15 | const url = props.location.pathname 16 | const newUrl = correctUrl(url, label) 17 | if (url != newUrl) 18 | return 19 | else 20 | return props.children 21 | } 22 | 23 | export default withLang(withRouter(LangCorrector)) -------------------------------------------------------------------------------- /client/components/LangSwitch.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { connect } from 'react-redux' 4 | import Button from 'react-bootstrap/lib/Button' 5 | import withLang from '../lib/withLang' 6 | import * as actions from '../redux/actions' 7 | 8 | import callApi from '../lib/callApi' 9 | 10 | export LangSwitch = (props) -> 11 | setInterfaceLanguage = (lang) -> 12 | () -> 13 | props.switchLang(lang) 14 | await callApi "setLang/#{lang}", {} 15 | 16 | return if props.lang == "ru" 17 | 20 | else 21 | 24 | 25 | mapStateToProps = (state) -> 26 | return 27 | lang: state.lang 28 | 29 | mapDispatchToProps = (dispatch, ownProps) -> 30 | return 31 | switchLang: (newLang) -> 32 | dispatch(actions.switchLang(newLang)) 33 | 34 | export default connect(mapStateToProps, mapDispatchToProps)(LangSwitch) -------------------------------------------------------------------------------- /client/components/Level.css: -------------------------------------------------------------------------------- 1 | .epigraph { 2 | width:100%; 3 | text-align:right; 4 | margin-bottom:2ex; 5 | font-style: italic; 6 | white-space: pre-line; 7 | } 8 | .problemList { 9 | margin-top: 1ex; 10 | margin-bottom: 1ex; 11 | } 12 | .bigText { 13 | font-size: 16px; 14 | } -------------------------------------------------------------------------------- /client/components/Loader.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | import withTheme from '../lib/withTheme' 3 | import { CometSpinLoader } from 'react-css-loaders'; 4 | 5 | Loader = (props) -> 6 | return if props.theme == "dark" 7 |
8 | 9 |
10 | else 11 |
12 | 13 |
14 | 15 | export default withTheme(Loader) -------------------------------------------------------------------------------- /client/components/Material.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import Problem from './Problem' 4 | import Level from './Level' 5 | import Contest from './Contest' 6 | 7 | Page = (props) -> 8 |
9 |
10 | 11 | MaterialProper = (props) -> 12 | if props.material?.type == 'page' 13 | `` 14 | else if props.material?.type == 'level' 15 | `` 16 | else if props.material?.type == 'simpleLevel' 17 | `` 18 | else if props.material?.type == 'contest' 19 | `` 20 | else if props.material?.type == 'epigraph' 21 | `` 22 | else if props.material?.type == 'problem' 23 | `` 24 | else if props.material?.type == 'topic' 25 | `` 26 | else 27 |
Unknown material type
28 | 29 | export default Material = (props) -> 30 |
31 | 32 |
33 | -------------------------------------------------------------------------------- /client/components/News.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import Panel from 'react-bootstrap/lib/Panel' 4 | import PanelGroup from 'react-bootstrap/lib/PanelGroup' 5 | 6 | import Lang, {LangRaw} from '../lang/lang' 7 | 8 | import ConnectedComponent from '../lib/ConnectedComponent' 9 | import withLang from '../lib/withLang' 10 | 11 | News = (props) -> 12 |
13 |

{Lang("news")}

14 | 15 | { 16 | res = [] 17 | a = (el) -> res.push(el) 18 | for m, i in props.news?.materials || [] 19 | a 20 | 21 | {m.title} 22 | 23 | 24 |
25 | 26 | 27 | res 28 | } 29 | 30 |
31 | 32 | options = 33 | urls: (props) -> 34 | news: "material/news" + LangRaw("material_suffix", props.lang) 35 | 36 | export default withLang(ConnectedComponent(News, options)) 37 | -------------------------------------------------------------------------------- /client/components/PaymentSuccess.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import Grid from 'react-bootstrap/lib/Grid' 4 | 5 | import Lang from '../lang/lang' 6 | 7 | class PaymentSuccess extends React.Component 8 | constructor: (props) -> 9 | super(props) 10 | 11 | render: () -> 12 | 13 | {Lang("payment_successful_message")} 14 | 15 | 16 | export default PaymentSuccess -------------------------------------------------------------------------------- /client/components/Problem.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | deepcopy = require('deepcopy') 3 | 4 | import getTestSystem from '../testSystems/TestSystemRegistry' 5 | 6 | import withLang from '../lib/withLang' 7 | 8 | import SubmitList from './SubmitList' 9 | import EditablePage from './EditablePage' 10 | 11 | problemId = (props) -> 12 | props.material._id.substring(1) 13 | 14 | stripLabel = (material) -> 15 | idx = material._id.indexOf("!") 16 | if idx != -1 17 | material = deepcopy(material) 18 | material._id = material._id.substring(0, idx) 19 | return material 20 | 21 | export default Problem = withLang (props) -> 22 | testSystem = getTestSystem(props.material.testSystemData.system) 23 | materialStripped = stripLabel(props.material) 24 |
25 | 26 | {testSystem.problemLink(materialStripped, props.lang)} 27 | {``} 28 |
29 | -------------------------------------------------------------------------------- /client/components/Result.css: -------------------------------------------------------------------------------- 1 | .td { 2 | padding-left : 5px; 3 | padding-right : 5px; 4 | } 5 | 6 | -------------------------------------------------------------------------------- /client/components/ReviewResult.css: -------------------------------------------------------------------------------- 1 | .stars { 2 | font-size: 200%; 3 | padding-top: 5px; 4 | padding-bottom: 5px; 5 | cursor: pointer; 6 | } 7 | .paid { 8 | background: #ccffcc; 9 | } 10 | .unpaid { 11 | background: #ffffcc; 12 | } 13 | .muchUnpaid { 14 | background: #ffcccc 15 | } 16 | .nonpaid { 17 | background: white; 18 | } 19 | .actionButtons { 20 | position: sticky; 21 | bottom: 10px; 22 | z-index: 100; 23 | } -------------------------------------------------------------------------------- /client/components/Root.css: -------------------------------------------------------------------------------- 1 | @media (min-width: 767px) { 2 | .mainHeader { 3 | font-size: 150%; 4 | } 5 | } 6 | .item { 7 | text-align: center; 8 | padding-top : 1ex; 9 | padding-bottom: 1ex; 10 | font-size: 150%; 11 | } 12 | .number { 13 | font-family: Menlo, Monaco, Consolas, "Courier New", monospace; 14 | font-size: 200%; 15 | } 16 | .text { 17 | padding-top: 2ex; 18 | } 19 | .whoami a { 20 | font-size: 150%; 21 | padding: 0.5ex !important; 22 | } 23 | .whatitis { 24 | padding-top: 2ex; 25 | padding-bottom: 1ex; 26 | } 27 | .img { 28 | box-shadow: 0 0 5px black; 29 | width: 190px; 30 | } 31 | @media (min-width: 767px) { 32 | .howitworks_row { 33 | display: flex; 34 | align-items: center; 35 | width: 100%; 36 | } 37 | .howitworks_row div { 38 | padding: 10px; 39 | } 40 | .reverse { 41 | flex-direction: row-reverse; 42 | } 43 | .howitworks_text { 44 | flex: 1; 45 | font-size: 21px; 46 | } 47 | } 48 | @media (max-width: 766px) { 49 | .howitworks_row div { 50 | padding: 10px; 51 | width: 100%; 52 | } 53 | .howitworks_img { 54 | text-align: center; 55 | } 56 | .howitworks_text { 57 | flex: 1; 58 | font-size: 16px; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /client/components/Sceleton.css: -------------------------------------------------------------------------------- 1 | .footer { 2 | width: 100%; 3 | background-color: #f5f5f5; 4 | padding-top: 10px; 5 | padding-bottom: 10px; 6 | } 7 | .footer_dark { 8 | width: 100%; 9 | background-color: #1f1f1f; 10 | padding-top: 10px; 11 | padding-bottom: 10px; 12 | } 13 | .right { 14 | text-align: right; 15 | } 16 | .wrapper { 17 | display: flex; 18 | min-height: 100%; 19 | flex-direction: column; 20 | } 21 | .main { 22 | flex: 1; 23 | padding-bottom: 10px; 24 | } 25 | .en_warning { 26 | position: sticky; 27 | top: 50px; 28 | z-index: 100; 29 | } -------------------------------------------------------------------------------- /client/components/ScrollToTop.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { withRouter } from 'react-router' 4 | 5 | class ScrollToTop extends React.Component 6 | componentDidUpdate: (prevProps) -> 7 | if @props.location != prevProps.location 8 | window.scrollTo(0, 0) 9 | 10 | render: -> 11 | this.props.children 12 | 13 | export default withRouter(ScrollToTop) 14 | -------------------------------------------------------------------------------- /client/components/ShadowedSwitch.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | import styles from './ShadowedSwitch.css' 3 | 4 | export default ShadowedSwitch = (props) -> 5 | 6 | {props.children} 7 | 8 | -------------------------------------------------------------------------------- /client/components/ShadowedSwitch.css: -------------------------------------------------------------------------------- 1 | .on { 2 | cursor: hand; 3 | text-shadow: 0 0 5px red; 4 | } 5 | .off { 6 | cursor: hand; 7 | } 8 | -------------------------------------------------------------------------------- /client/components/SolvedByWeek.css: -------------------------------------------------------------------------------- 1 | .textAdd { 2 | font-size: 10; 3 | } 4 | .solvedByWeek:fullscreen { 5 | padding-left: 10px; 6 | } 7 | .solvedByWeek:-webkit-full-screen { 8 | padding-left: 10px; 9 | } 10 | .solvedByWeekDark:fullscreen { 11 | padding-left: 10px; 12 | } 13 | .solvedByWeekDark:-webkit-full-screen { 14 | padding-left: 10px; 15 | } 16 | .solvedByWeek { 17 | background: white; 18 | } 19 | .solvedByWeekDark { 20 | background: #182121; 21 | } -------------------------------------------------------------------------------- /client/components/Submit.css: -------------------------------------------------------------------------------- 1 | .toggling { 2 | cursor: hand; 3 | } 4 | .pre { 5 | overflow: scroll; 6 | } 7 | .td { 8 | /* strange hack */ 9 | max-width: 10px; 10 | } 11 | .stickyHeader { 12 | position: sticky; 13 | top: 0px; 14 | z-index: 100; 15 | } 16 | 17 | #diffEditor {} 18 | 19 | .ok { 20 | background: #b9ffb9 !important; 21 | } 22 | .wa { 23 | background: #ffb9b9 !important; 24 | } 25 | .tl { 26 | background: #b9b9ff !important; 27 | } -------------------------------------------------------------------------------- /client/components/SubmitList.css: -------------------------------------------------------------------------------- 1 | .modal { 2 | width: 90% !important; 3 | } 4 | -------------------------------------------------------------------------------- /client/components/SubmitListTable.css: -------------------------------------------------------------------------------- 1 | .active td { 2 | font-weight: bold; 3 | } 4 | .outerDiv table { 5 | margin-bottom: 5px !important; 6 | } 7 | -------------------------------------------------------------------------------- /client/components/Table.css: -------------------------------------------------------------------------------- 1 | .example { 2 | padding-left:5px; 3 | padding-right:5px; 4 | margin-bottom:5px; 5 | } 6 | -------------------------------------------------------------------------------- /client/components/TableRow.css: -------------------------------------------------------------------------------- 1 | .res { 2 | font-family: monospace; 3 | text-align: center; 4 | position: relative; 5 | overflow: hidden; 6 | } 7 | 8 | .full { 9 | background: #00dd00; 10 | } 11 | .done { 12 | background: #009900; 13 | } 14 | .started { 15 | background: #cccccc; 16 | } 17 | .none { 18 | } 19 | .subtableHeader { 20 | white-space: normal; 21 | } 22 | .subFindMistakes { 23 | font-size: 0.8ex; 24 | position: absolute; 25 | right: 0px; 26 | bottom: 0px; 27 | } -------------------------------------------------------------------------------- /client/components/ThemeCss.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | import Cookies from 'universal-cookie' 3 | import withTheme from '../lib/withTheme' 4 | 5 | ThemeCss = (props) -> 6 | cookies = new Cookies 7 | cookies.set('theme', props.theme) 8 | return if props.theme == "dark" 9 |
10 | 11 | 12 | 13 |
14 | else 15 | 16 | 17 | export default withTheme(ThemeCss) -------------------------------------------------------------------------------- /client/components/ThemeSwitch.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | FontAwesome = require('react-fontawesome') 3 | 4 | import { connect } from 'react-redux' 5 | import Button from 'react-bootstrap/lib/Button' 6 | 7 | import{LangRaw} from '../lang/lang' 8 | import withLang from '../lib/withLang' 9 | import withTheme from '../lib/withTheme' 10 | import * as actions from '../redux/actions' 11 | 12 | export ThemeSwitch = withLang (props) -> 13 | return if props.theme == "dark" 14 | 17 | else 18 | 21 | 22 | mapStateToProps = (state) -> 23 | return 24 | theme: state.theme 25 | 26 | mapDispatchToProps = (dispatch, ownProps) -> 27 | return 28 | switchTheme: (newTheme) -> dispatch(actions.switchTheme(newTheme)) 29 | 30 | export default connect(mapStateToProps, mapDispatchToProps)(ThemeSwitch) -------------------------------------------------------------------------------- /client/components/TopPanel.css: -------------------------------------------------------------------------------- 1 | .separator { 2 | padding-right: 2em; 3 | } 4 | .adminhash { 5 | padding-right: 0.5em; 6 | } 7 | .warning { 8 | cursor: hand; 9 | } 10 | -------------------------------------------------------------------------------- /client/components/Tree.css: -------------------------------------------------------------------------------- 1 | .levelNav { 2 | margin-top: 0px !important; 3 | } 4 | .levelNav a { 5 | padding-top: 0px !important; 6 | padding-bottom: 0px !important; 7 | padding-right: 0px !important; 8 | } 9 | .navitem a { 10 | color: black !important; 11 | } 12 | .navitemDark a { 13 | color: #F8F6D9 !important; 14 | } 15 | .tree { 16 | padding-top: 2ex; 17 | } 18 | .levelRow { 19 | display: flex; 20 | } 21 | .levelName { 22 | flex: 1; 23 | margin-top: 2px; 24 | margin-bottom: 2px; 25 | } 26 | .colorBox { 27 | display: flex; 28 | justify-content: center; 29 | align-items: center; 30 | } 31 | .colorBox_inner { 32 | } 33 | .full { 34 | background-color: #acf090; 35 | color: #3c763d; 36 | } 37 | .done { 38 | background-color: #dff0d8; 39 | color: #3c763d; 40 | } 41 | .started { 42 | background-color: #cccccc; 43 | } 44 | .ignored { 45 | background-color: #c4e3f3; 46 | color: #31708f; 47 | } 48 | .wa { 49 | background-color: #ebcccc; 50 | color: #a94442; 51 | } 52 | .ok { 53 | background-color: #fcf8e3; 54 | color: #8a6d3b; 55 | font-size: 40%; 56 | } 57 | .null { 58 | } 59 | -------------------------------------------------------------------------------- /client/components/UserName.css: -------------------------------------------------------------------------------- 1 | .name { 2 | font-weight: bold; 3 | } 4 | -------------------------------------------------------------------------------- /client/components/UsersWithAchieve.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import {BigAchieves} from './Achieves' 4 | import UserName from './UserName' 5 | 6 | import {LangRawAny} from '../lang/lang' 7 | 8 | import ACHIEVES from '../lib/achieves' 9 | import withLang from '../lib/withLang' 10 | 11 | export default UsersWithAchieve = withLang (props) -> 12 |
13 | 14 |

{LangRawAny(ACHIEVES[props.achieve].title, props.lang, props.achieve)}

15 | {props.users.map((user) -> 16 |
17 | )} 18 |
19 | -------------------------------------------------------------------------------- /client/components/YaMetrikaHit.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { withRouter } from 'react-router' 4 | 5 | class YaMetrikaHit extends React.Component 6 | componentDidUpdate: (prevProps) -> 7 | if @props.location != prevProps.location and window.yaCounter45895896 8 | window.yaCounter45895896.hit?(@props.location.pathname) 9 | 10 | render: -> 11 | this.props.children 12 | 13 | export default withRouter(YaMetrikaHit) 14 | -------------------------------------------------------------------------------- /client/components/global.css: -------------------------------------------------------------------------------- 1 | .mainTable_div { 2 | overflow: auto; 3 | } 4 | .mainTable { 5 | border-left:1px solid black; 6 | border-top:1px solid black; 7 | margin-bottom: 10px; 8 | white-space: nowrap; 9 | border-collapse: separate; 10 | } 11 | .mainTable_td { 12 | border-bottom:1px solid black; 13 | border-right:1px solid black; 14 | padding: 3px; 15 | text-align: center; 16 | min-width: 3ex; 17 | } 18 | .mainTable_th { 19 | border-bottom:1px solid black; 20 | border-right:1px solid black; 21 | position: sticky; 22 | left: 0; 23 | background: white; 24 | } 25 | .mainTable_user { 26 | text-align: left; 27 | z-index: 1; 28 | } 29 | .border { 30 | background:black; 31 | padding:0px; 32 | border-right:3px solid black; 33 | border-bottom:1px solid black; 34 | min-width: 0px; 35 | } 36 | .ac { 37 | background: #44ff44; 38 | } 39 | .darkac { 40 | background: #00cf00; 41 | } 42 | .ok { 43 | background: #ffff00; 44 | } 45 | .darkok { 46 | background: #d1d100; 47 | } 48 | .wa { 49 | background: #ff4444; 50 | } 51 | .ig { 52 | background: #aaaaff; 53 | } 54 | .dq, .dq_text { 55 | background: black !important; 56 | } 57 | .dq_text { 58 | color: white; 59 | } 60 | -------------------------------------------------------------------------------- /client/lib/BrowserNotifications.coffee: -------------------------------------------------------------------------------- 1 | export requestPermission = () -> 2 | window.Notification?.requestPermission(); 3 | 4 | export notify = (tag, title, body, url) -> 5 | if not window.Notification 6 | return 7 | if window.Notification.permission != "granted" 8 | return 9 | notification = new window.Notification(title, {tag, body}) 10 | notification.onclick = (event) -> 11 | window.goto(url)() 12 | -------------------------------------------------------------------------------- /client/lib/WebsocketsSet.coffee: -------------------------------------------------------------------------------- 1 | websocketsSet = {}; 2 | 3 | export subscribeWsSet = (key) -> 4 | websocketsSet[key] = 1 5 | 6 | export unsubscribeWsSet = (key) -> 7 | delete websocketsSet[key] 8 | 9 | export hasWsSetKey = (key) -> 10 | websocketsSet[key]? -------------------------------------------------------------------------------- /client/lib/addTotal.coffee: -------------------------------------------------------------------------------- 1 | accountAttempts = (result, countUnsolvedAttempts) -> 2 | if countUnsolvedAttempts or result?.solved or result?.ok 3 | result?.attempts || 0 4 | else 5 | 0 6 | 7 | export default addTotal = (a, b, countUnsolvedAttempts = false) -> 8 | SIMPLE_KEYS = ["total", "required", "solved", "ok", "ps", "ignored"] 9 | 10 | result = {} 11 | for key in SIMPLE_KEYS 12 | result[key] = (a?[key] || 0) + (b?[key] || 0) 13 | result.attempts = accountAttempts(a, countUnsolvedAttempts) + accountAttempts(b, countUnsolvedAttempts) 14 | result.lastSubmitId = a?.lastSubmitId 15 | result.lastSubmitTime = a?.lastSubmitTime 16 | 17 | if (!a?.lastSubmitId) or (b?.lastSubmitId and b.lastSubmitTime > a.lastSubmitTime) 18 | result.lastSubmitId = b?.lastSubmitId 19 | result.lastSubmitTime = b?.lastSubmitTime 20 | 21 | return result 22 | -------------------------------------------------------------------------------- /client/lib/awaitAll.coffee: -------------------------------------------------------------------------------- 1 | export default awaitAll = (promises) -> 2 | error = undefined 3 | tryPromise = (p) -> 4 | try 5 | await Promise.resolve(p) 6 | catch e 7 | error = e 8 | 9 | results = await Promise.all(promises.map(tryPromise)) 10 | if error 11 | throw error 12 | return results -------------------------------------------------------------------------------- /client/lib/correctUrl.ts: -------------------------------------------------------------------------------- 1 | import {parseLevel, encodeLevel} from '../lib/level' 2 | import stripLabel from '../lib/stripLabel' 3 | 4 | function correctSubmaterial(materialId: string, label: string) { 5 | const data = materialId.split(".") 6 | if (data.length != 2) 7 | return null 8 | const level = parseLevel(data[0]) 9 | if (!level) 10 | return null 11 | return "/material/" + stripLabel(encodeLevel(level, label)) + "." + stripLabel(data[1]) + label 12 | } 13 | 14 | export default function correctUrl(url: string, label: string) { 15 | if (!url.startsWith("/material/")) 16 | return url 17 | const data = url.split("/") 18 | if (data.length != 3) 19 | return url 20 | const level = parseLevel(data[2]) 21 | if (!level) { 22 | const correctedSubmaterial = correctSubmaterial(data[2], label) 23 | return correctedSubmaterial || (stripLabel(url) + label); 24 | } 25 | return "/material/" + encodeLevel(level, label) 26 | } 27 | -------------------------------------------------------------------------------- /client/lib/findMistake.coffee: -------------------------------------------------------------------------------- 1 | export DISTANCE_THRESHOLD = 15 2 | MAX_LENGTH = 3000 3 | 4 | export distance = (s1, s2) -> 5 | if (not s1) or (not s2) 6 | return DISTANCE_THRESHOLD + 1 7 | if s1.length > MAX_LENGTH or s2.length > MAX_LENGTH 8 | return DISTANCE_THRESHOLD + 1 9 | d = new Array(s1.length + 1) 10 | for _, i in d 11 | d[i] = new Array(s2.length + 1) 12 | d[0][0] = 0 13 | for _, i in s1 14 | d[i+1][0] = i+1 15 | for _, j in s2 16 | d[0][j+1] = j+1 17 | for c1, i in s1 18 | for c2, j in s2 19 | d[i+1][j+1] = Math.min(d[i][j+1], d[i+1][j]) + 1 20 | cost = if c1 == c2 then 0 else 1 21 | d[i+1][j+1] = Math.min(d[i+1][j+1], d[i][j] + cost) 22 | return d[s1.length][s2.length] 23 | -------------------------------------------------------------------------------- /client/lib/graduateYearToClass.coffee: -------------------------------------------------------------------------------- 1 | MS_PER_YEAR = 1000 * 60 * 60 * 24 * 365.25 2 | 3 | export getCurrentYearStart = () -> 4 | baseDate = new Date(1990, 6, 1) 5 | now = new Date() 6 | baseTime = now - baseDate 7 | baseYears = Math.floor(baseTime / MS_PER_YEAR) 8 | currentYearStart = baseDate.getTime() + baseYears * MS_PER_YEAR 9 | return new Date(currentYearStart).getFullYear() 10 | 11 | export getClassStartingFromJuly = (year) -> return getClass(new Date(year, 6, 1)) 12 | 13 | export getGraduateYear = (cl) -> 14 | if not cl 15 | return null 16 | yearStart = getCurrentYearStart() 17 | yearStartDate = new Date(yearStart, 6, 1) 18 | graduateDate = yearStartDate.getTime() + (12 - cl) * MS_PER_YEAR 19 | return new Date(graduateDate).getFullYear() 20 | 21 | export default getClass = (graduateDate) -> 22 | now = new Date() 23 | time = graduateDate - now 24 | if time < 0 25 | return null 26 | else 27 | return 11 - Math.floor(time / MS_PER_YEAR) -------------------------------------------------------------------------------- /client/lib/isContestRequired.coffee: -------------------------------------------------------------------------------- 1 | export default isContestRequired = (tableName) -> 2 | return tableName[4] != "*" and tableName[0] != "*" 3 | -------------------------------------------------------------------------------- /client/lib/isPaid.coffee: -------------------------------------------------------------------------------- 1 | import GROUPS from '../lib/groups' 2 | 3 | export default isPaid = (myUser) -> 4 | if !myUser?.paidTill 5 | return false 6 | # paidTill is for 0:00:00, but it is really paid until 23:59:59 7 | ms = new Date(myUser.paidTill).getTime() + 24 * 60 * 60 * 1000; 8 | realPaidTill = new Date(ms); 9 | return new Date() <= realPaidTill 10 | 11 | export isMuchUnpaid = (myUser) -> 12 | MAX_UNPAID_DAYS = 3 13 | if !myUser?.paidTill 14 | return false 15 | # paidTill is for 0:00:00, but it is really paid until 23:59:59 16 | ms = new Date(myUser.paidTill).getTime() + 24 * 60 * 60 * 1000 * (1 + MAX_UNPAID_DAYS); 17 | realPaidTill = new Date(ms); 18 | return new Date() > realPaidTill 19 | 20 | export unpaidBlocked = (user) -> 21 | (GROUPS[user?.userList]?.paid) and (user?.paidTill) && (isMuchUnpaid(user)) 22 | -------------------------------------------------------------------------------- /client/lib/needDeactivatedWarning.coffee: -------------------------------------------------------------------------------- 1 | objectHasKeys = (object) -> 2 | return object? && Object.keys(object)?.length 3 | 4 | export default needDeactivatedWarning = (myUser, me) -> 5 | return myUser && not me?.admin && not myUser?.activated && (myUser.rating > 0 || objectHasKeys(myUser.byWeek?.ok) || objectHasKeys(myUser.byWeek?.solved)) 6 | -------------------------------------------------------------------------------- /client/lib/requiredProblemsByLevelMinor.ts: -------------------------------------------------------------------------------- 1 | export default function requiredProblemsByLevelMinor(levelMinor: number, problemsNumber: number) { 2 | let needProblem = problemsNumber 3 | if (levelMinor == 3) 4 | needProblem *= 0.5 5 | else if (levelMinor == 4) 6 | needProblem *= 1.0 / 3 7 | return needProblem 8 | } -------------------------------------------------------------------------------- /client/lib/stripLabel.ts: -------------------------------------------------------------------------------- 1 | export default function stripLabel(id: string): string { 2 | if (!id) { 3 | return id 4 | } 5 | var idx = id.indexOf("!") 6 | if (idx != -1) { 7 | return id.substring(0, idx) 8 | } 9 | return id 10 | } -------------------------------------------------------------------------------- /client/lib/toUtf8.coffee: -------------------------------------------------------------------------------- 1 | iconv = require('iconv-lite') 2 | 3 | export default toUtf8 = (sourceRaw) -> 4 | iconv.decode(Buffer.from(sourceRaw, "latin1"), "utf8") 5 | -------------------------------------------------------------------------------- /client/lib/withLang.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | import { connect } from 'react-redux' 3 | 4 | mapStateToProps = (state) -> 5 | return 6 | lang: state.lang 7 | 8 | export default withLang = (Component) -> connect(mapStateToProps)(Component) -------------------------------------------------------------------------------- /client/lib/withMyResults.coffee: -------------------------------------------------------------------------------- 1 | import withMyUser from './withMyUser' 2 | import ConnectedComponent from './ConnectedComponent' 3 | 4 | options = 5 | urls: (props) -> 6 | if props.myUser?._id 7 | "myResults": "userResults/#{props.myUser._id}" 8 | else 9 | {} 10 | 11 | timeout: 20000 12 | 13 | allowNotLoaded: true 14 | 15 | export default withMyResults = (Component) -> 16 | withMyUser(ConnectedComponent(Component, options)) 17 | -------------------------------------------------------------------------------- /client/lib/withMyUser.coffee: -------------------------------------------------------------------------------- 1 | import ConnectedComponent from './ConnectedComponent' 2 | 3 | options = 4 | urls: (props) -> 5 | return {"myUser", "me"} 6 | 7 | timeout: 20 * 1000 8 | 9 | export default withMyUser = (Component) -> 10 | ConnectedComponent(Component, options) 11 | -------------------------------------------------------------------------------- /client/lib/withTheme.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | import { connect } from 'react-redux' 3 | 4 | mapStateToProps = (state) -> 5 | return 6 | theme: state.theme 7 | 8 | export default withTheme = (Component) -> connect(mapStateToProps)(Component) -------------------------------------------------------------------------------- /client/mathJaxObserver.coffee: -------------------------------------------------------------------------------- 1 | target = document.getElementById('main'); 2 | 3 | observer = new MutationObserver (mutations) -> 4 | MathJax.Hub.Queue(["Typeset",MathJax.Hub]); 5 | 6 | config = 7 | attributes: true, 8 | childList: true, 9 | characterData: true, 10 | subtree: true 11 | 12 | observer.observe target, config 13 | 14 | export default observer 15 | -------------------------------------------------------------------------------- /client/pages/AchievesPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { Grid } from 'react-bootstrap' 4 | import { Helmet } from "react-helmet" 5 | 6 | import {AllAchieves} from '../components/Achieves' 7 | import Sceleton from '../components/Sceleton' 8 | 9 | import {LangRaw} from '../lang/lang' 10 | import withLang from '../lib/withLang' 11 | 12 | class AchievesPage extends React.Component 13 | constructor: (props) -> 14 | super(props) 15 | 16 | render: () -> 17 | sceletonProps = { 18 | @props..., 19 | location: {title: LangRaw("all_achieves", @props.lang), _id: "achieves"}, 20 | } 21 | `` 22 | 23 | export default withLang(AchievesPage) -------------------------------------------------------------------------------- /client/pages/AllCommentsPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { Grid } from 'react-bootstrap' 4 | import { Helmet } from "react-helmet" 5 | 6 | import AllComments from '../components/AllComments' 7 | import Sceleton from '../components/Sceleton' 8 | 9 | import {LangRaw} from '../lang/lang' 10 | import withLang from '../lib/withLang' 11 | 12 | class AllCommentsPage extends React.Component 13 | constructor: (props) -> 14 | super(props) 15 | 16 | render: () -> 17 | sceletonProps = { 18 | @props..., 19 | location: {title: LangRaw("comments", @props.lang), _id: "comments" + LangRaw("material_suffix", @props.lang)}, 20 | } 21 | `` 22 | 23 | 24 | export default withLang(AllCommentsPage) -------------------------------------------------------------------------------- /client/pages/AllSubmitsPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { Grid } from 'react-bootstrap' 4 | import { Helmet } from "react-helmet" 5 | 6 | import AllSubmits from '../components/AllSubmits' 7 | import Sceleton from '../components/Sceleton' 8 | 9 | import {LangRaw} from '../lang/lang' 10 | import Lang from '../lang/lang' 11 | import withLang from '../lib/withLang' 12 | 13 | class AllSubmitsPage extends React.Component 14 | constructor: (props) -> 15 | super(props) 16 | 17 | render: () -> 18 | sceletonProps = { 19 | @props..., 20 | location: {title: LangRaw("submits_list", @props.lang), _id: "submits_list" + LangRaw("material_suffix", @props.lang)}, 21 | } 22 | child = 23 | `{child}` 24 | 25 | export default withLang(AllSubmitsPage) -------------------------------------------------------------------------------- /client/pages/ApproveFindMistakePage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { Grid } from 'react-bootstrap' 4 | import { Helmet } from "react-helmet" 5 | 6 | import ApproveFindMistake from '../components/ApproveFindMistake' 7 | import Sceleton from '../components/Sceleton' 8 | 9 | export default class ApproveFindMistakePage extends React.Component 10 | constructor: (props) -> 11 | super(props) 12 | 13 | render: () -> 14 | sceletonProps = { 15 | @props..., 16 | location: {title: "Одобрение поиска ошибок", _id: "achieves"}, 17 | showNews: "hide", 18 | showTree: "hide" 19 | } 20 | `` 21 | 22 | -------------------------------------------------------------------------------- /client/pages/CheckinsPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { Grid } from 'react-bootstrap' 4 | import { Helmet } from "react-helmet" 5 | 6 | import Checkins from '../components/Checkins' 7 | import Sceleton from '../components/Sceleton' 8 | import ConnectedComponent from '../lib/ConnectedComponent' 9 | 10 | class CheckinsPage extends React.Component 11 | constructor: (props) -> 12 | super(props) 13 | 14 | render: () -> 15 | sceletonProps = { 16 | @props..., 17 | location: {title: "Регистрация на занятие", _id: "checkins"}, 18 | } 19 | `` 20 | 21 | options = 22 | urls: () -> 23 | data: "checkins" 24 | myUser: "myUser" 25 | me: "me" 26 | 27 | timeout: 20000 28 | 29 | export default ConnectedComponent(CheckinsPage, options) 30 | -------------------------------------------------------------------------------- /client/pages/DashboardPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { Grid } from 'react-bootstrap' 4 | import { Helmet } from "react-helmet" 5 | 6 | import Dashboard from '../components/Dashboard' 7 | import Sceleton from '../components/Sceleton' 8 | import ConnectedComponent from '../lib/ConnectedComponent' 9 | 10 | class DashboardPage extends React.Component 11 | constructor: (props) -> 12 | super(props) 13 | 14 | render: () -> 15 | sceletonProps = { 16 | @props..., 17 | location: {title: "Последние посылки", _id: "dashboard"}, 18 | showNews: "hide", 19 | showTree: "hide" 20 | } 21 | `` 22 | 23 | options = 24 | urls: () -> 25 | data: "dashboard" 26 | 27 | timeout: 20000 28 | 29 | export default ConnectedComponent(DashboardPage, options) 30 | -------------------------------------------------------------------------------- /client/pages/EditUserPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { Grid } from 'react-bootstrap' 4 | import { Helmet } from "react-helmet" 5 | 6 | import EditUser from '../components/EditUser' 7 | import Sceleton from '../components/Sceleton' 8 | import ConnectedComponent from '../lib/ConnectedComponent' 9 | 10 | class EditUserPage extends React.Component 11 | constructor: (props) -> 12 | super(props) 13 | 14 | render: () -> 15 | sceletonProps = { 16 | @props..., 17 | location: {title: @props.data.user.name, _id: "user" + @props.data.user._id}, 18 | showNews: "hide", 19 | showTree: "hide" 20 | } 21 | child = 22 | `{child}` 23 | 24 | options = 25 | urls: (props) -> 26 | data: "fullUser/#{props.match.params.id}" 27 | me: "me" 28 | 29 | export default ConnectedComponent(EditUserPage, options) 30 | -------------------------------------------------------------------------------- /client/pages/FindMistakeListPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { Grid } from 'react-bootstrap' 4 | import { Helmet } from "react-helmet" 5 | 6 | import FindMistakeList from '../components/FindMistakeList' 7 | import Sceleton from '../components/Sceleton' 8 | 9 | import {LangRaw} from '../lang/lang' 10 | import withLang from '../lib/withLang' 11 | 12 | 13 | class FindMistakeListPage extends React.Component 14 | constructor: (props) -> 15 | super(props) 16 | 17 | render: () -> 18 | sceletonProps = { 19 | @props..., 20 | location: {title: LangRaw("find_mistake", @props.lang), _id: "findMistake" + LangRaw("material_suffix", @props.lang)}, 21 | } 22 | `` 23 | 24 | export default withLang(FindMistakeListPage) -------------------------------------------------------------------------------- /client/pages/FindMistakePage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { Grid } from 'react-bootstrap' 4 | import { Helmet } from "react-helmet" 5 | 6 | import FindMistake from '../components/FindMistake' 7 | import Sceleton from '../components/Sceleton' 8 | 9 | import {LangRaw} from '../lang/lang' 10 | import ConnectedComponent from '../lib/ConnectedComponent' 11 | import withLang from '../lib/withLang' 12 | import withMyUser from '../lib/withMyUser' 13 | 14 | class FindMistakePage extends React.Component 15 | constructor: (props) -> 16 | super(props) 17 | 18 | render: () -> 19 | sceletonProps = { 20 | @props..., 21 | location: {title: "#{LangRaw('find_mistake', @props.lang)}: #{@props.findMistake?.problemName}", _id: "findMistake" + LangRaw("material_suffix", @props.lang)}, 22 | } 23 | `` 24 | 25 | options = 26 | urls: (props) -> 27 | findMistake: "findMistake/#{props.match.params.id}/#{props.myUser?._id}?lang=#{LangRaw("material_suffix", props.lang)}" 28 | 29 | export default withLang(withMyUser(ConnectedComponent(FindMistakePage, options))) -------------------------------------------------------------------------------- /client/pages/FindMistakeProblemListPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { Grid } from 'react-bootstrap' 4 | import { Helmet } from "react-helmet" 5 | 6 | import FindMistakeList from '../components/FindMistakeList' 7 | import Sceleton from '../components/Sceleton' 8 | 9 | import {LangRaw} from '../lang/lang' 10 | import ConnectedComponent from '../lib/ConnectedComponent' 11 | import withLang from '../lib/withLang' 12 | 13 | class FindMistakeProblemListPage extends React.Component 14 | constructor: (props) -> 15 | super(props) 16 | 17 | render: () -> 18 | path = @props.data?.path.slice(0) 19 | path.push 20 | _id: @props.data._id 21 | title: @props.data.title 22 | sceletonProps = { 23 | @props..., 24 | location: {title: LangRaw("find_mistake", @props.lang), path, _id: "findMistakeProblem"} 25 | } 26 | `` 27 | 28 | options = 29 | urls: (props) -> 30 | data: "material/#{props.match.params.problemId}#{LangRaw("material_suffix", props.lang)}" 31 | 32 | export default withLang ConnectedComponent(FindMistakeProblemListPage, options) -------------------------------------------------------------------------------- /client/pages/FullNewsPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { Grid } from 'react-bootstrap' 4 | import { Helmet } from "react-helmet" 5 | 6 | import FullNews from '../components/FullNews' 7 | import Sceleton from '../components/Sceleton' 8 | 9 | import {LangRaw} from '../lang/lang' 10 | import withLang from '../lib/withLang' 11 | import ConnectedComponent from '../lib/ConnectedComponent' 12 | 13 | class FullNewsPage extends React.Component 14 | constructor: (props) -> 15 | super(props) 16 | 17 | render: () -> 18 | sceletonProps = {@props..., location: {title: LangRaw("news", @props.lang), path: @props.news.path, _id: @props.news._id}} 19 | `` 20 | 21 | 22 | options = 23 | urls: (props) -> 24 | news: "material/news" + LangRaw("material_suffix", props.lang) 25 | 26 | export default withLang(ConnectedComponent(FullNewsPage, options)) 27 | -------------------------------------------------------------------------------- /client/pages/FullUserPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { Grid } from 'react-bootstrap' 4 | import { Helmet } from "react-helmet" 5 | 6 | import FullUser from '../components/FullUser' 7 | import Sceleton from '../components/Sceleton' 8 | import ConnectedComponent from '../lib/ConnectedComponent' 9 | 10 | class FullUserPage extends React.Component 11 | constructor: (props) -> 12 | super(props) 13 | 14 | render: () -> 15 | sceletonProps = { 16 | @props..., 17 | location: {title: @props.data.user.name, _id: "user" + @props.data.user._id}, 18 | showNews: "hide", 19 | showTree: "hide" 20 | } 21 | child = 22 | `{child}` 23 | 24 | options = 25 | urls: (props) -> 26 | data: "fullUser/#{props.match.params.id}" 27 | me: "me" 28 | 29 | export default ConnectedComponent(FullUserPage, options) 30 | -------------------------------------------------------------------------------- /client/pages/LoginPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import Login from '../components/Login' 4 | import Sceleton from '../components/Sceleton' 5 | 6 | import {LangRaw} from '../lang/lang' 7 | import withLang from '../lib/withLang' 8 | 9 | class LoginPage extends React.Component 10 | render: () -> 11 | sceletonProps = {@props..., location: {title: LangRaw("sign_in", @props.lang), _id: "login"}} 12 | `` 13 | 14 | export default withLang(LoginPage) 15 | -------------------------------------------------------------------------------- /client/pages/MaterialPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import Material from '../components/Material' 4 | import Sceleton from '../components/Sceleton' 5 | import ConnectedComponent from '../lib/ConnectedComponent' 6 | 7 | class MaterialPage extends React.Component 8 | constructor: (props) -> 9 | super(props) 10 | 11 | render: () -> 12 | sceletonProps = {@props..., location: {title: @props.data?.title, path: @props.data?.path, _id: @props.data?._id}} 13 | `` 14 | 15 | options = 16 | urls: (props) -> 17 | data: "material/#{props.match.params.id}" 18 | 19 | export default MaterialPageConnected = ConnectedComponent(MaterialPage, options) 20 | -------------------------------------------------------------------------------- /client/pages/PaymentPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { Grid } from 'react-bootstrap' 4 | import { Helmet } from "react-helmet" 5 | 6 | import Payment from '../components/Payment' 7 | import Sceleton from '../components/Sceleton' 8 | 9 | import {LangRaw} from '../lang/lang' 10 | import ConnectedComponent from '../lib/ConnectedComponent' 11 | import withLang from '../lib/withLang' 12 | 13 | class PaymentPage extends React.Component 14 | constructor: (props) -> 15 | super(props) 16 | 17 | render: () -> 18 | sceletonProps = { 19 | @props..., 20 | location: {title: LangRaw("payment_for_the_course", @props.lang), _id: "payment"}, 21 | } 22 | `` 23 | 24 | options = 25 | urls: () -> 26 | myUser: "myUser" 27 | me: "me" 28 | 29 | timeout: 20000 30 | 31 | export default ConnectedComponent(withLang(PaymentPage), options) 32 | -------------------------------------------------------------------------------- /client/pages/PaymentSuccessPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { Grid } from 'react-bootstrap' 4 | import { Helmet } from "react-helmet" 5 | 6 | import PaymentSuccess from '../components/PaymentSuccess' 7 | 8 | export default class PaymentSuccessPage extends React.Component 9 | constructor: (props) -> 10 | super(props) 11 | 12 | render: () -> 13 | 14 | 15 | -------------------------------------------------------------------------------- /client/pages/RegisterPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import Register from '../components/Register' 4 | import Sceleton from '../components/Sceleton' 5 | 6 | import {LangRaw} from '../lang/lang' 7 | import withLang from '../lib/withLang' 8 | 9 | class RegisterPage extends React.Component 10 | render: () -> 11 | sceletonProps = {@props..., location: {title: LangRaw("register", @props.lang), _id: "register"}} 12 | `` 13 | 14 | export default withLang RegisterPage 15 | -------------------------------------------------------------------------------- /client/pages/RegisteredUsersPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { Grid } from 'react-bootstrap' 4 | import { Helmet } from "react-helmet" 5 | 6 | import RegisteredUsers from '../components/RegisteredUsers' 7 | import Sceleton from '../components/Sceleton' 8 | import ConnectedComponent from '../lib/ConnectedComponent' 9 | 10 | class RegisteredUsersPage extends React.Component 11 | constructor: (props) -> 12 | super(props) 13 | 14 | render: () -> 15 | sceletonProps = { 16 | @props..., 17 | location: {title: "Пользователи", _id: "registeredUsers"}, 18 | showNews: "hide", 19 | showTree: "hide" 20 | } 21 | `` 22 | 23 | options = 24 | urls: () -> 25 | "data": "registeredUsers" 26 | 27 | export default ConnectedComponent(RegisteredUsersPage, options) 28 | -------------------------------------------------------------------------------- /client/pages/ReviewPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import Review from '../components/Review' 4 | import Sceleton from '../components/Sceleton' 5 | import ConnectedComponent from '../lib/ConnectedComponent' 6 | 7 | class ReviewPage extends React.Component 8 | constructor: (props) -> 9 | super(props) 10 | 11 | render: () -> 12 | sceletonProps = { 13 | @props..., 14 | location: {title: "Ревью посылок", _id: "review"}, 15 | showNews: "hide", 16 | showTree: "hide" 17 | } 18 | `` 19 | 20 | options = 21 | urls: () -> 22 | "data": "dashboard" 23 | 24 | export default ConnectedComponent(ReviewPage, options) 25 | -------------------------------------------------------------------------------- /client/pages/ReviewResultPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { Grid } from 'react-bootstrap' 4 | import { Helmet } from "react-helmet" 5 | 6 | import ReviewResult from '../components/ReviewResult' 7 | import Sceleton from '../components/Sceleton' 8 | import ConnectedComponent from '../lib/ConnectedComponent' 9 | 10 | class ReviewResultPage extends React.Component 11 | constructor: (props) -> 12 | super(props) 13 | 14 | render: () -> 15 | sceletonProps = { 16 | @props..., 17 | location: {title: "Результат #{@props.match.params.id}", _id: "submit"}, 18 | showNews: "hide", 19 | showTree: "hide" 20 | } 21 | `` 22 | 23 | options = 24 | urls: (props) -> 25 | data: "result/#{props.match.params.id}" 26 | timeout: 0 27 | 28 | export default ConnectedComponent(ReviewResultPage, options) 29 | -------------------------------------------------------------------------------- /client/pages/RootPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import Root from '../components/Root' 4 | 5 | export default Root 6 | -------------------------------------------------------------------------------- /client/pages/SolvedByWeekPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { Grid } from 'react-bootstrap' 4 | import { Helmet } from "react-helmet" 5 | 6 | import SolvedByWeek from '../components/SolvedByWeek' 7 | import Sceleton from '../components/Sceleton' 8 | 9 | import {LangRaw} from '../lang/lang' 10 | import ConnectedComponent from '../lib/ConnectedComponent' 11 | import withLang from '../lib/withLang' 12 | 13 | class SolvedByWeekPage extends React.Component 14 | constructor: (props) -> 15 | super(props) 16 | @userList = props.match.params.userList 17 | 18 | render: () -> 19 | sceletonProps = { 20 | @props..., 21 | location: {title: LangRaw("solved_problems_by_week", @props.lang), _id: "table:#{@userList}:byWeek"}, 22 | showNews: "hide", 23 | showTree: "hide" 24 | } 25 | child = 26 | `{child}` 27 | 28 | options = 29 | urls: (props) -> 30 | data: "users/#{props.match.params.userList}" 31 | me: "me" 32 | 33 | timeout: 20000 34 | 35 | export default ConnectedComponent(withLang(SolvedByWeekPage), options) 36 | -------------------------------------------------------------------------------- /client/pages/SubmitPage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { Grid } from 'react-bootstrap' 4 | import { Helmet } from "react-helmet" 5 | 6 | import Submit from '../components/Submit' 7 | import Sceleton from '../components/Sceleton' 8 | 9 | import {LangRaw} from '../lang/lang' 10 | import ConnectedComponent from '../lib/ConnectedComponent' 11 | import withLang from '../lib/withLang' 12 | 13 | class SubmitPage extends React.Component 14 | constructor: (props) -> 15 | super(props) 16 | 17 | render: () -> 18 | sceletonProps = { 19 | @props..., 20 | location: {title: "#{LangRaw('attempts', @props.lang)} #{@props.match.params.id}", _id: "submit"}, 21 | showNews: "hide", 22 | showTree: "hide" 23 | } 24 | `` 25 | 26 | 27 | options = 28 | url: (props) -> 29 | data: "submit/#{props.match.params.id}" 30 | 31 | export default ConnectedComponent(withLang(SubmitPage), options) 32 | -------------------------------------------------------------------------------- /client/pages/TablePage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { Grid } from 'react-bootstrap' 4 | import Table from '../components/Table' 5 | import Sceleton from '../components/Sceleton' 6 | 7 | import ConnectedComponent from '../lib/ConnectedComponent' 8 | 9 | class TablePage extends React.Component 10 | constructor: (props) -> 11 | super(props) 12 | @id = props.match.params.id 13 | @userList = props.match.params.userList 14 | 15 | render: () -> 16 | sceletonProps = { 17 | @props..., 18 | location: {_id: "table:#{@userList}:#{@id}"}, 19 | showNews: "hide", 20 | showTree: "hide" 21 | } 22 | child = 23 | `{child}` 24 | 25 | options = 26 | urls: (props) -> 27 | data: "table/#{props.match.params.userList}/#{props.match.params.id}" 28 | me: "me" 29 | 30 | #timeout: 20000 31 | 32 | export default ConnectedComponent(TablePage, options) 33 | -------------------------------------------------------------------------------- /client/pages/UsersWithAchievePage.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import { Grid } from 'react-bootstrap' 4 | import { Helmet } from "react-helmet" 5 | 6 | import UsersWithAchieve from '../components/UsersWithAchieve' 7 | import Sceleton from '../components/Sceleton' 8 | 9 | import {LangRaw} from '../lang/lang' 10 | import ConnectedComponent from '../lib/ConnectedComponent' 11 | import withLang from '../lib/withLang' 12 | 13 | class UsersWithAchievePage extends React.Component 14 | constructor: (props) -> 15 | super(props) 16 | 17 | render: () -> 18 | sceletonProps = { 19 | @props..., 20 | location: {title: LangRaw("users_with_achieve", @props.lang), _id: "usersWithAchieve"}, 21 | } 22 | child = 23 | `{child}` 24 | 25 | options = 26 | urls: (props) -> 27 | users: "users/withAchieve/#{props.match.params.achieve}" 28 | 29 | export default ConnectedComponent(withLang(UsersWithAchievePage), options) -------------------------------------------------------------------------------- /client/redux/getters.coffee: -------------------------------------------------------------------------------- 1 | export equalUrl = (url1, url2) -> 2 | url1 == url2 or decodeURIComponent(url1) == url2 or url1 == decodeURIComponent(url2) 3 | 4 | export getRawData = (state, url) -> 5 | found = (x for x in state.data when equalUrl(url, x.url)) 6 | if found.length > 1 7 | throw "Duplicate url #{url} in state.data " 8 | if found.length == 0 9 | return null 10 | return found[0] 11 | 12 | export hasData = (state, url) -> 13 | return getRawData(state, url)?.data 14 | 15 | export isDataRejected = (state, url) -> 16 | d = getRawData(state, url) 17 | return d?.rejected and (not d?.data) 18 | 19 | export getData = (state, url) -> 20 | return getRawData(state, url)?.data 21 | -------------------------------------------------------------------------------- /client/redux/store.coffee: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from 'redux' 2 | import promiseMiddleware from 'redux-promise-middleware' 3 | import ReduxThunk from 'redux-thunk' 4 | 5 | import rootReducer from './reducers' 6 | 7 | export default createMyStore = (state) -> 8 | createStore(rootReducer, state, applyMiddleware(promiseMiddleware, ReduxThunk)) 9 | -------------------------------------------------------------------------------- /client/testSystems/Ejudge.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import TestSystem from './TestSystem' 4 | 5 | export default class Ejudge extends TestSystem 6 | constructor: (@server, @baseContest) -> 7 | super() 8 | 9 | id: () -> 10 | return "ejudge" 11 | 12 | problemLink: (material) -> 13 | ### 14 | href = "#{@server}/cgi-bin/new-client?contest_id=#{material.testSystemData.contest}" 15 |

Контест в ejudge

16 | ### 17 | null 18 | 19 | submitListLink: (submit) -> 20 | ### 21 | href = "#{@server}/cgi-bin/new-client?contest_id=#{submit.testSystemData.contest}" 22 |

Контест в ejudge

23 | ### 24 | null 25 | -------------------------------------------------------------------------------- /client/testSystems/Informatics.coffee: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | 3 | import {LangRaw} from '../lang/lang' 4 | 5 | import TestSystem from './TestSystem' 6 | 7 | export default class Informatics extends TestSystem 8 | BASE_URL = "https://informatics.msk.ru" 9 | 10 | _informaticsProblemId: (problemId) -> 11 | problemId.substring(1) 12 | 13 | id: () -> 14 | return "informatics" 15 | 16 | problemLink: (material, lang) -> 17 | id = @_informaticsProblemId(material._id) 18 | href = "#{BASE_URL}/mod/statements/view.php?chapterid=#{id}" 19 |

{LangRaw("informatics_problem_link", lang)}

20 | 21 | submitListLink: (submit, lang) -> 22 | id = @_informaticsProblemId(submit.problem) 23 | {LangRaw("informatics_submits_link", lang)} 24 | -------------------------------------------------------------------------------- /client/testSystems/TestSystem.coffee: -------------------------------------------------------------------------------- 1 | export default class TestSystem 2 | id: () -> 3 | throw "not implemented" 4 | 5 | problemLink: (material) -> 6 | throw "not implemented" 7 | 8 | submitsListLink: (problem, user) -> 9 | throw "not implemented" 10 | 11 | blockSubmission: (material, me) -> 12 | return null 13 | -------------------------------------------------------------------------------- /client/testSystems/TestSystemRegistry.coffee: -------------------------------------------------------------------------------- 1 | import Codeforces from './Codeforces' 2 | import Ejudge from './Ejudge' 3 | import Informatics from './Informatics' 4 | 5 | export REGISTRY = 6 | "informatics": new Informatics() 7 | "ejudge": new Ejudge('https://ejudge.algoprog.ru', 1) 8 | "codeforces": new Codeforces() 9 | 10 | export default getTestSystem = (id) -> 11 | REGISTRY[id || "informatics"] 12 | -------------------------------------------------------------------------------- /highlight/highlight.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/highlight/highlight.zip -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ 2 | module.exports = { 3 | preset: 'ts-jest', 4 | testEnvironment: 'node', 5 | }; -------------------------------------------------------------------------------- /k8s/app-network-networkpolicy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: NetworkPolicy 3 | metadata: 4 | creationTimestamp: null 5 | name: app-network 6 | spec: 7 | ingress: 8 | - from: 9 | - podSelector: 10 | matchLabels: 11 | io.kompose.network/app-network: "true" 12 | podSelector: 13 | matchLabels: 14 | io.kompose.network/app-network: "true" 15 | -------------------------------------------------------------------------------- /k8s/cert-manager-prod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cert-manager.io/v1 2 | kind: Issuer 3 | metadata: 4 | name: letsencrypt-prod 5 | spec: 6 | acme: 7 | server: https://acme-v02.api.letsencrypt.org/directory 8 | email: petr@kalinin.nnov.ru 9 | privateKeySecretRef: 10 | name: letsencrypt-prod 11 | solvers: 12 | - http01: 13 | ingress: 14 | class: nginx 15 | -------------------------------------------------------------------------------- /k8s/data-persistentvolumeclaim.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | io.kompose.service: data 7 | name: data 8 | spec: 9 | accessModes: 10 | - ReadWriteOnce 11 | resources: 12 | requests: 13 | storage: 10Gi 14 | status: {} 15 | -------------------------------------------------------------------------------- /k8s/db-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | annotations: 5 | kompose.cmd: kompose convert 6 | kompose.version: 1.18.0 (06a2e56) 7 | creationTimestamp: null 8 | labels: 9 | io.kompose.service: db 10 | name: db 11 | spec: 12 | ports: 13 | - port: 27017 14 | targetPort: 27017 15 | selector: 16 | io.kompose.service: db 17 | status: 18 | loadBalancer: {} -------------------------------------------------------------------------------- /k8s/ije-role-binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1beta1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: fabric8-rbac 5 | subjects: 6 | - kind: ServiceAccount 7 | name: ije-algoprog-ru 8 | namespace: default 9 | roleRef: 10 | kind: ClusterRole 11 | name: cluster-admin 12 | apiGroup: rbac.authorization.k8s.io -------------------------------------------------------------------------------- /k8s/ije-service-account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: ije-algoprog-ru -------------------------------------------------------------------------------- /k8s/ingress-config.yaml: -------------------------------------------------------------------------------- 1 | kind: ConfigMap 2 | apiVersion: v1 3 | metadata: 4 | name: ingress-nginx-controller 5 | data: 6 | hsts-include-subdomains: "false" 7 | compute-full-forwarded-for: "true" 8 | forwarded-for-header: "x-forrrerr" 9 | log-format-upstream: '{"time": "$time_iso8601", "proxy_protocol_addr": "$proxy_protocol_addr", "remote_addr": "$remote_addr", "x_forwarded_for": "$proxy_add_x_forwarded_for", "request_id": "$req_id", "remote_user": "$remote_user", "bytes_sent": $bytes_sent, "request_time": $request_time, "status": $status, "vhost": "$host", "request_proto": "$server_protocol", "path": "$uri", "request_query": "$args", "request_length": $request_length, "duration": $request_time,"method": "$request_method", "http_referrer": "$http_referer", "http_user_agent": "$http_user_agent" }' -------------------------------------------------------------------------------- /k8s/ingress-no-tls.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: algoprog-ingress 5 | annotations: 6 | # use the shared ingress-nginx 7 | kubernetes.io/ingress.class: "nginx" 8 | spec: 9 | rules: 10 | - http: 11 | paths: 12 | - path: / 13 | pathType: Prefix 14 | backend: 15 | service: 16 | name: nodejs 17 | port: 18 | number: 3000 -------------------------------------------------------------------------------- /k8s/nodejs-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | annotations: 5 | kompose.cmd: kompose convert 6 | kompose.version: 1.23.0 (bc7d9f4f) 7 | creationTimestamp: null 8 | labels: 9 | io.kompose.service: nodejs 10 | name: nodejs 11 | spec: 12 | type: NodePort 13 | ports: 14 | - name: "3000" 15 | port: 3000 16 | targetPort: 3000 17 | - name: "25" 18 | port: 1025 19 | targetPort: 1025 20 | nodePort: 30000 21 | selector: 22 | io.kompose.service: nodejs 23 | externalIPs: 24 | - 62.84.115.189 25 | status: 26 | loadBalancer: {} 27 | -------------------------------------------------------------------------------- /k8s/readme.txt: -------------------------------------------------------------------------------- 1 | Ref: https://github.com/Azure/k8s-set-context -------------------------------------------------------------------------------- /k8s/role-binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1beta1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: gh-rb 5 | subjects: 6 | - kind: ServiceAccount 7 | name: github-actions 8 | namespace: default 9 | roleRef: 10 | kind: ClusterRole 11 | name: cluster-admin 12 | apiGroup: rbac.authorization.k8s.io -------------------------------------------------------------------------------- /k8s/service-account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: github-actions -------------------------------------------------------------------------------- /logo/algoprog-2022.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/algoprog-2022.png -------------------------------------------------------------------------------- /logo/emoji_blog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/emoji_blog.png -------------------------------------------------------------------------------- /logo/emoji_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/emoji_main.png -------------------------------------------------------------------------------- /logo/emoji_notes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/emoji_notes.png -------------------------------------------------------------------------------- /logo/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/favicon.ico -------------------------------------------------------------------------------- /logo/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/favicon.png -------------------------------------------------------------------------------- /logo/favicon_blog.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/favicon_blog.ico -------------------------------------------------------------------------------- /logo/favicon_blog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/favicon_blog.png -------------------------------------------------------------------------------- /logo/favicon_notes.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/favicon_notes.ico -------------------------------------------------------------------------------- /logo/favicon_notes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/favicon_notes.png -------------------------------------------------------------------------------- /logo/head-20191006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/head-20191006.png -------------------------------------------------------------------------------- /logo/head-20191027.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/head-20191027.png -------------------------------------------------------------------------------- /logo/head-20191208.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/head-20191208.png -------------------------------------------------------------------------------- /logo/head-20200216.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/head-20200216.png -------------------------------------------------------------------------------- /logo/head-20200719.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/head-20200719.png -------------------------------------------------------------------------------- /logo/head-20210724.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/head-20210724.png -------------------------------------------------------------------------------- /logo/head-20210725-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/head-20210725-1.png -------------------------------------------------------------------------------- /logo/head-20210725-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/head-20210725-2.png -------------------------------------------------------------------------------- /logo/head-20210725-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/head-20210725-3.png -------------------------------------------------------------------------------- /logo/head-20210727.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/head-20210727.png -------------------------------------------------------------------------------- /logo/head-20210728.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/head-20210728.png -------------------------------------------------------------------------------- /logo/head-20210729.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/head-20210729.png -------------------------------------------------------------------------------- /logo/logo-1920-1080-2024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/logo-1920-1080-2024.png -------------------------------------------------------------------------------- /logo/logo-1920-1080.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/logo-1920-1080.png -------------------------------------------------------------------------------- /logo/logo-1920-1200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/logo-1920-1200.png -------------------------------------------------------------------------------- /logo/logo_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/logo_a.png -------------------------------------------------------------------------------- /logo/logo_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/logo_big.png -------------------------------------------------------------------------------- /logo/logo_h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/logo_h.png -------------------------------------------------------------------------------- /logo/topsort/graph_colored_h.2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/topsort/graph_colored_h.2.pdf -------------------------------------------------------------------------------- /logo/topsort/graph_colored_v.2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/topsort/graph_colored_v.2.pdf -------------------------------------------------------------------------------- /logo/topsort/topsort-v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/topsort/topsort-v.png -------------------------------------------------------------------------------- /logo/topsort/topsort.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/logo/topsort/topsort.jpg -------------------------------------------------------------------------------- /mongo.cmd: -------------------------------------------------------------------------------- 1 | "C:\Program Files\MongoDB\Server\3.4\bin\mongod.exe" --dbpath ./data -v -------------------------------------------------------------------------------- /mongo.sh: -------------------------------------------------------------------------------- 1 | mongod --dbpath ./data -v -------------------------------------------------------------------------------- /public/about-1-levels-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/about-1-levels-en.png -------------------------------------------------------------------------------- /public/about-1-levels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/about-1-levels.png -------------------------------------------------------------------------------- /public/about-2-submit-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/about-2-submit-en.png -------------------------------------------------------------------------------- /public/about-2-submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/about-2-submit.png -------------------------------------------------------------------------------- /public/about-3-results-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/about-3-results-en.png -------------------------------------------------------------------------------- /public/about-3-results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/about-3-results.png -------------------------------------------------------------------------------- /public/about-4-comments-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/about-4-comments-en.png -------------------------------------------------------------------------------- /public/about-4-comments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/about-4-comments.png -------------------------------------------------------------------------------- /public/about-5-ac-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/about-5-ac-en.png -------------------------------------------------------------------------------- /public/about-5-ac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/about-5-ac.png -------------------------------------------------------------------------------- /public/about-6-ig-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/about-6-ig-en.png -------------------------------------------------------------------------------- /public/about-6-ig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/about-6-ig.png -------------------------------------------------------------------------------- /public/about-7-best-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/about-7-best-en.png -------------------------------------------------------------------------------- /public/about-7-best.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/about-7-best.png -------------------------------------------------------------------------------- /public/additional_dark.css: -------------------------------------------------------------------------------- 1 | input { background-color: #182121 } 2 | span.badge { background-color: #555555 !important; } -------------------------------------------------------------------------------- /public/choco-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/choco-light.png -------------------------------------------------------------------------------- /public/choco-strut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/choco-strut.png -------------------------------------------------------------------------------- /public/choco.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/choco.png -------------------------------------------------------------------------------- /public/darklight.css: -------------------------------------------------------------------------------- 1 | .hljs { 2 | color: #a9b7c6; 3 | background: #282b2e; 4 | display: block; 5 | overflow-x: auto; 6 | padding: 0.5em; 7 | } 8 | 9 | .hljs-number, 10 | .hljs-literal, 11 | .hljs-symbol, 12 | .hljs-bullet { 13 | color: #6897BB; 14 | } 15 | 16 | .hljs-keyword, 17 | .hljs-selector-tag, 18 | .hljs-deletion { 19 | color: #cc7832; 20 | } 21 | 22 | .hljs-variable, 23 | .hljs-template-variable, 24 | .hljs-link { 25 | color: #629755; 26 | } 27 | 28 | .hljs-comment, 29 | .hljs-quote { 30 | color: #808080; 31 | } 32 | 33 | .hljs-meta { 34 | color: #bbb529; 35 | } 36 | 37 | .hljs-string, 38 | .hljs-attribute, 39 | .hljs-addition { 40 | color: #6A8759; 41 | } 42 | 43 | .hljs-section, 44 | .hljs-title, 45 | .hljs-type { 46 | color: #ffc66d; 47 | } 48 | 49 | .hljs-name, 50 | .hljs-selector-id, 51 | .hljs-selector-class { 52 | color: #e8bf6a; 53 | } 54 | 55 | .hljs-emphasis { 56 | font-style: italic; 57 | } 58 | 59 | .hljs-strong { 60 | font-weight: bold; 61 | } -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/favicon.ico -------------------------------------------------------------------------------- /public/ib.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/ib.odt -------------------------------------------------------------------------------- /public/ib.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/ib.pdf -------------------------------------------------------------------------------- /public/main.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | height: 100%; 3 | margin: 0; 4 | padding: 0; 5 | } 6 | @media (min-width: 768px) { 7 | body { 8 | padding-top: 50px; 9 | } 10 | } 11 | @media (max-width: 768px) { 12 | .navbar-fixed-top, .navbar-fixed-bottom { 13 | position: relative !important; 14 | } 15 | } 16 | .panel-heading a { 17 | cursor: pointer; 18 | } 19 | 20 | .panel-dq_text { 21 | background: black !important; 22 | } 23 | .panel-dq_text { 24 | color: white; 25 | } 26 | -------------------------------------------------------------------------------- /public/mastercard.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /public/oferta.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/oferta.docx -------------------------------------------------------------------------------- /public/oferta.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/oferta.pdf -------------------------------------------------------------------------------- /public/privacy.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/privacy.odt -------------------------------------------------------------------------------- /public/privacy.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/privacy.pdf -------------------------------------------------------------------------------- /public/raion_archive.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/raion_archive.pdf -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: /user/ -------------------------------------------------------------------------------- /public/testsystems.css: -------------------------------------------------------------------------------- 1 | .section-title { 2 | font-size: 120%; 3 | margin-top: 10px; 4 | margin-bottom: 10px; 5 | } 6 | .sample-test { 7 | display: flex; 8 | align-items: baseline; 9 | flex-wrap: wrap; 10 | } 11 | .sample-test .input { 12 | padding-right: 20px; 13 | flex-basis: 40%; 14 | } 15 | .sample-test .output { 16 | flex-basis: 50%; 17 | } 18 | .codeforces-statement .header { 19 | padding-bottom: 20px; 20 | } 21 | .codeforces-statement .property-title { 22 | display: inline-block; 23 | padding-right: 1em; 24 | } 25 | .codeforces-statement .property-title:after { 26 | content: ":"; 27 | } 28 | .codeforces-statement .sample-test { 29 | display: block; 30 | } 31 | .codeforces-statement .input, .codeforces-statement .output{ 32 | display: block; 33 | padding-right: 0px; 34 | } -------------------------------------------------------------------------------- /public/tinkoff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petr-kalinin/algoprog/4bfad17385c69091b3776411b6a5eb92143b149c/public/tinkoff.png -------------------------------------------------------------------------------- /scripts/2021_01_05_move_users.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | from bson.json_util import dumps 3 | import json 4 | import pymongo 5 | import os 6 | 7 | MONGODB_URI = os.environ['MONGODB_URI'] 8 | IDS = [301755] 9 | 10 | algoprog = pymongo.MongoClient(MONGODB_URI)["algoprog"] 11 | algoprog_sbory = pymongo.MongoClient(MONGODB_URI)["algoprog_sbory"] 12 | log = open("log.txt", "a") 13 | for user_id in IDS: 14 | print(user_id) 15 | registered_user = algoprog["registeredusers"].find_one({"informaticsId": user_id}) 16 | user = algoprog["users"].find_one({"_id": str(user_id)}) 17 | log.write(dumps(registered_user) + "\n") 18 | log.write(dumps(user) + "\n") 19 | user["mainUserList"] = user["userList"] 20 | user["userList"] = "sbory" 21 | algoprog["users"].replace_one({"_id": str(user_id)}, user) 22 | 23 | user["userList"] = "all" 24 | algoprog_sbory["users"].replace_one({"_id": str(user_id)}, user, upsert=True) 25 | algoprog_sbory["registeredusers"].replace_one({"informaticsId": user_id}, registered_user, upsert=True) 26 | -------------------------------------------------------------------------------- /scripts/2021_01_17_move_users_back.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | from bson.json_util import dumps 3 | import json 4 | import pymongo 5 | import os 6 | 7 | MONGODB_URI = os.environ['MONGODB_URI'] 8 | IDS = [454364, ] 9 | 10 | algoprog = pymongo.MongoClient(MONGODB_URI)["algoprog"] 11 | log = open("log_2021_01_17.txt", "a") 12 | for user_id in IDS: 13 | print(user_id) 14 | user = algoprog["users"].find_one({"_id": str(user_id)}) 15 | log.write(dumps(user) + "\n") 16 | user["userList"] = user["mainUserList"] 17 | algoprog["users"].replace_one({"_id": str(user_id)}, user) 18 | -------------------------------------------------------------------------------- /scripts/rating.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | for i in range(1, 14): 4 | print("%3d" % i, end="") 5 | for j in range(4): 6 | if j == 3 and i % 2 == 0: 7 | continue 8 | rating = 2.5 ** (i + j / 4) 9 | print("%11.2f" % rating, end="") 10 | print("") 11 | -------------------------------------------------------------------------------- /server/calculations/calculateCalendar.coffee: -------------------------------------------------------------------------------- 1 | import Calendar from '../models/Calendar' 2 | import Submit from '../models/submit' 3 | 4 | import logger from '../log' 5 | 6 | export default calculateCalendar = (user) -> 7 | start = new Date() 8 | logger.info "updating calendar for user ", user 9 | submits = await Submit.findByUserWithFindMistakeAny(user) 10 | events = {} 11 | previousYear = (new Date()).getFullYear() - 1 12 | for submit in submits 13 | t = submit.time 14 | if not t 15 | continue 16 | month = t.getMonth() + 1 17 | day = t.getDate() 18 | year = t.getFullYear() 19 | short = "#{year}-#{month}-#{day}" 20 | if year >= previousYear 21 | events[short] = if short of events then events[short] + 1 else 1 22 | calendar = new Calendar {_id: user, byDay : events} 23 | await calendar.upsert() 24 | logger.info "updated calendar for user ", user, " spent time ", (new Date()) - start 25 | -------------------------------------------------------------------------------- /server/calculations/ratingConstants.coffee: -------------------------------------------------------------------------------- 1 | # для общего заголовка в три колонки нужна кратность трём 2 | export lastWeeksToShow = 17 * 3 3 | 4 | export WEEK_ACTIVITY_EXP = 0.55 5 | export LEVEL_RATING_EXP = 2.5 6 | export ACTIVITY_THRESHOLD = 0.1 7 | export MSEC_IN_WEEK = 7 * 24 * 60 * 60 * 1000 8 | 9 | export FM_CONST = 1/3 10 | -------------------------------------------------------------------------------- /server/cmrh.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | generateScopedName: function (name, filepath, css) { 3 | var baseDir = __dirname.split("/"); 4 | var csspath = filepath 5 | .split("/") 6 | .slice(baseDir.length - 1) // -1 for 'client' 7 | .join("_") 8 | .slice(0, -4); 9 | 10 | return "_" + csspath + "__" + name; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /server/cron/cron.coffee: -------------------------------------------------------------------------------- 1 | cron = require('node-cron') 2 | 3 | import * as downloadSubmits from "./downloadSubmits" 4 | import * as downloadBlog from './downloadBlog' 5 | import updateCf from "./updateCf" 6 | import submitSubmits from './submitSubmits' 7 | import sendMetrics from './sendMetrics' 8 | 9 | import logger from '../log' 10 | import User from '../models/user' 11 | 12 | offset = (new Date().getTimezoneOffset()) / 60 13 | MOSCOW_OFFSET = -3 14 | nightHour = (3 + MOSCOW_OFFSET - offset - 1) %% 24 15 | 16 | logger.info "Will set updateResults to " + nightHour + ":59:58 local time" 17 | 18 | export default scheduleJobs = () -> 19 | cron.schedule('*/10 * * * * *', downloadSubmits.runForCT); 20 | cron.schedule('0 0 * * * *', updateCf); 21 | cron.schedule('45 46 ' + nightHour + ' * * *', User.updateAllUsers); 22 | cron.schedule('0 */5 * * * *', downloadBlog.run) 23 | cron.schedule("*/2 * * * * *", submitSubmits) 24 | cron.schedule("0 */5 * * * *", sendMetrics) 25 | -------------------------------------------------------------------------------- /server/cron/downloadBlog.coffee: -------------------------------------------------------------------------------- 1 | feedparser = require('feedparser-promised') 2 | 3 | import BlogPost from "../models/BlogPost" 4 | import logger from '../log' 5 | import awaitAll from '../../client/lib/awaitAll' 6 | 7 | URL = "https://blog.algoprog.ru/feed.xml" 8 | 9 | download = () -> 10 | posts = await feedparser.parse(URL) 11 | realIds = {} 12 | promises = [] 13 | 14 | for post in posts 15 | realIds[post.guid] = true 16 | post = new BlogPost 17 | _id: post.guid 18 | title: post.title 19 | link: post.link 20 | date: post.pubdate 21 | promises.push(post.upsert()) 22 | 23 | for oldPost in await BlogPost.find({}) 24 | if not realIds[oldPost._id] 25 | promises.push(oldPost.remove()) 26 | 27 | await awaitAll(promises) 28 | 29 | 30 | running = false 31 | 32 | wrapRunning = (callable) -> 33 | () -> 34 | if running 35 | logger.info "Already running downloadBlog" 36 | return 37 | try 38 | running = true 39 | await callable() 40 | finally 41 | running = false 42 | 43 | export run = wrapRunning () -> 44 | logger.info "Downloading blog posts" 45 | await download() 46 | logger.info "Done downloading blog posts" 47 | -------------------------------------------------------------------------------- /server/cron/updateCf.coffee: -------------------------------------------------------------------------------- 1 | import User from '../models/user' 2 | import logger from '../log' 3 | running = false 4 | 5 | wrapRunning = (callable) -> 6 | () -> 7 | if running 8 | logger.info "Already running updateCf" 9 | return 10 | try 11 | running = true 12 | await callable() 13 | finally 14 | running = false 15 | 16 | export default run = wrapRunning -> 17 | User.updateAllCf() 18 | -------------------------------------------------------------------------------- /server/hashes/findSimilarSubmits.coffee: -------------------------------------------------------------------------------- 1 | import Hash from '../models/Hash' 2 | import Submit from '../models/submit' 3 | 4 | export default findSimilarSubmits = (submit, limit) -> 5 | candidates = [] 6 | for h in submit.hashes 7 | otherHashes = await Hash.findByHashAndNotUser(h.hash, submit.user) 8 | candidates = candidates.concat(otherHashes) 9 | candidates.sort (a, b) -> 10 | scoreA = a.window * a.score 11 | scoreB = b.window * b.score 12 | if scoreB != scoreA 13 | return scoreB - scoreA 14 | if a._id < b._id 15 | return 1 16 | else if a._id > b._id 17 | return -1 18 | else 19 | return 0 20 | result = [] 21 | seenIds = {} 22 | for candidate in candidates 23 | if candidate.submit of seenIds 24 | continue 25 | seenIds[candidate.submit] = true 26 | submit = await Submit.findById(candidate.submit) 27 | result.push submit 28 | if result.length == limit 29 | break 30 | return result 31 | -------------------------------------------------------------------------------- /server/lib/cbrf.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import download from './download' 3 | import * as xml2js from 'xml2js' 4 | 5 | export default async function getCbRfRate(currencyCode: string) { 6 | const page = await download("http://www.cbr.ru/scripts/XML_daily.asp", undefined, {timeout: 30 * 1000}) 7 | const data = await xml2js.parseStringPromise(page) 8 | for (const currency of data.ValCurs.Valute) { 9 | if (currency.CharCode[0] == currencyCode) { 10 | const value = currency.Value[0].replace(",", ".") 11 | const nominal = currency.Nominal[0].replace(",", ".") 12 | return +value / +nominal 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /server/lib/normalizeCode.coffee: -------------------------------------------------------------------------------- 1 | export default normalizeCode = (string) -> 2 | if not string 3 | return string 4 | # remove bom, see https://ejudge.ru/wiki/index.php/Serve.cfg:global:ignore_bom 5 | if string.startsWith("\xEF\xBB\xBF") 6 | string = string.substring(3) 7 | # Informatics trims spaces in source, at least at the beginning 8 | string = string.trim() 9 | # normalize end-of-lines, including mixed ones 10 | string = string.replace(/\r\n/g, "\n") 11 | return string.replace(/\n/g, "\r\n") 12 | -------------------------------------------------------------------------------- /server/lib/setDirty.coffee: -------------------------------------------------------------------------------- 1 | import Problem from '../models/problem' 2 | import Table from '../models/table' 3 | 4 | export default setDirty = (submit, dirtyResults, dirtyUsers) -> 5 | userId = submit.user 6 | probId = submit.problem 7 | dirtyUsers[userId] = 1 8 | dirtyResults[userId + "::" + probId] = 1 9 | problem = await Problem.findById(probId) 10 | if not problem 11 | return 12 | for table in problem.tables 13 | t = table 14 | while true 15 | t = await Table.findById(t) 16 | if t._id.startsWith("main") 17 | break 18 | dirtyResults[userId + "::" + t._id] = 1 19 | t = t.parent 20 | dirtyResults[userId + "::main"] = 1 21 | dirtyResults[userId + "::main!en"] = 1 22 | -------------------------------------------------------------------------------- /server/lib/sleep.coffee: -------------------------------------------------------------------------------- 1 | export default sleep = (milliseconds) -> 2 | return new Promise((resolve) -> setTimeout(resolve, milliseconds)) 3 | -------------------------------------------------------------------------------- /server/lib/translate.coffee: -------------------------------------------------------------------------------- 1 | import download from './download' 2 | 3 | FOLDER_ID = process.env["TRANSLATE_FOLDER_ID"] 4 | API_KEY = process.env["TRANSLATE_API_KEY"] 5 | 6 | export default translate = (texts, options={}) -> 7 | data = { 8 | folderId: FOLDER_ID, 9 | "texts": texts, 10 | "targetLanguageCode": "en", 11 | "sourceLanguageCode": "ru", 12 | "format": "HTML", 13 | options... 14 | } 15 | href = "https://translate.api.cloud.yandex.net/translate/v2/translate" 16 | result = await download(href, undefined, { 17 | body: data, 18 | json: true, 19 | method: 'POST', 20 | followAllRedirects: true, 21 | timeout: 30 * 1000, 22 | headers: { 23 | "Content-Type": "application/json", 24 | "Authorization": "Api-Key #{API_KEY}" 25 | } 26 | }) 27 | return result?.translations?.map((x) -> x?.text) 28 | -------------------------------------------------------------------------------- /server/lib/translateProblems.coffee: -------------------------------------------------------------------------------- 1 | import Material from '../models/Material' 2 | 3 | import translate from './translate' 4 | 5 | stripLabel = (id) -> 6 | idx = id.indexOf("!") 7 | if idx != -1 8 | return id.substring(0, idx) 9 | return undefined 10 | 11 | 12 | export default translateProblems = () -> 13 | problems = await Material.findByType("problem") 14 | for prob in problems 15 | if not (prob.title?.startsWith("Name") and prob.content?.startsWith("Text")) 16 | continue 17 | console.log prob._id 18 | id_ru = stripLabel(prob._id) 19 | if not id_ru 20 | throw "Non-english problem " + prob._id 21 | prob_ru = await Material.findById(id_ru) 22 | res = await translate([prob_ru.title, prob_ru.content]) 23 | [title, content] = res 24 | content = "
The problem statement has been automatically translated from Russian. If the statement is not clear, or you have any comments about it, please contact me. Anyway, I hope that someday I will fix the translation manually.
" + content 25 | prob.content = content 26 | prob.title = title 27 | prob.force = true 28 | await prob.upsert() 29 | -------------------------------------------------------------------------------- /server/log.coffee: -------------------------------------------------------------------------------- 1 | log4js = require('log4js') 2 | logger = log4js.getLogger() 3 | logger.level = 'info' 4 | 5 | export default logger 6 | -------------------------------------------------------------------------------- /server/log.ts: -------------------------------------------------------------------------------- 1 | import log4js = require('log4js') 2 | 3 | const logger = log4js.getLogger() 4 | logger.level = 'info' 5 | 6 | export default logger 7 | -------------------------------------------------------------------------------- /server/materials/data-en/news.coffee: -------------------------------------------------------------------------------- 1 | import news from "../lib/news" 2 | import newsItem from "../lib/newsItem" 3 | 4 | export default allNews = () -> 5 | return news([ 6 | newsItem("English version", String.raw""" 7 | English version is basically working, although not all texts has been translated yet. 8 | """) 9 | ]) 10 | -------------------------------------------------------------------------------- /server/materials/data-en/root.coffee: -------------------------------------------------------------------------------- 1 | import link from "../lib/link" 2 | import main from "../lib/main" 3 | 4 | import level_about from "./level_about" 5 | import mainLevels from './mainLevels' 6 | import allNews from "./news" 7 | import tables from './tables' 8 | 9 | export default root = () -> 10 | return main([ 11 | level_about(), 12 | allNews(), 13 | link("/comments", "Comments", "comments!en"), 14 | link("/findMistakeList", "Find a bug", "findMistake!en"), 15 | mainLevels()..., 16 | tables() 17 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_nnoi.coffee: -------------------------------------------------------------------------------- 1 | import level from "../lib/level" 2 | import level_nnoi2016 from "./level_nnoi2016" 3 | import level_nnoi2018 from "./level_nnoi2018" 4 | import level_nnoi2019 from "./level_nnoi2019" 5 | import level_nnoi2020 from "./level_nnoi2020" 6 | import level_nnoi2021 from "./level_nnoi2021" 7 | import level_nnoi2022 from "./level_nnoi2022" 8 | import level_nnoi2023 from "./level_nnoi2023" 9 | 10 | export default level_nnoi = () -> 11 | return level("nnoi", "Нижегородские городские олимпиады", [ 12 | level_nnoi2016(), 13 | level_nnoi2018(), 14 | level_nnoi2019(), 15 | level_nnoi2020(), 16 | level_nnoi2021(), 17 | level_nnoi2022(), 18 | level_nnoi2023(), 19 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_nnoi2016.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | export default () -> 6 | return contest("2016", [ 7 | problem({testSystem: "codeforces", contest: "gym/100885", problem: "A"}), 8 | problem({testSystem: "codeforces", contest: "gym/100885", problem: "B"}), 9 | problem({testSystem: "codeforces", contest: "gym/100885", problem: "C"}), 10 | problem({testSystem: "codeforces", contest: "gym/100885", problem: "D"}), 11 | problem({testSystem: "codeforces", contest: "gym/100885", problem: "E"}), 12 | problem({testSystem: "codeforces", contest: "gym/100885", problem: "F"}), 13 | ]) 14 | -------------------------------------------------------------------------------- /server/materials/data/level_nnoi2018.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | export default () -> 6 | return contest("2018", [ 7 | problem({testSystem: "codeforces", contest: "gym/103265", problem: "A"}), 8 | problem({testSystem: "codeforces", contest: "gym/103265", problem: "B"}), 9 | problem({testSystem: "codeforces", contest: "gym/103265", problem: "C"}), 10 | problem({testSystem: "codeforces", contest: "gym/103265", problem: "D"}), 11 | problem({testSystem: "codeforces", contest: "gym/103265", problem: "E"}), 12 | problem({testSystem: "codeforces", contest: "gym/103265", problem: "F"}), 13 | ]) 14 | -------------------------------------------------------------------------------- /server/materials/data/level_nnoi2019.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | export default () -> 6 | return contest("2019", [ 7 | problem({testSystem: "codeforces", contest: "gym/102112", problem: "A"}), 8 | problem({testSystem: "codeforces", contest: "gym/102112", problem: "B"}), 9 | problem({testSystem: "codeforces", contest: "gym/102112", problem: "C"}), 10 | problem({testSystem: "codeforces", contest: "gym/102112", problem: "D"}), 11 | problem({testSystem: "codeforces", contest: "gym/102112", problem: "E"}), 12 | problem({testSystem: "codeforces", contest: "gym/102112", problem: "F"}), 13 | ]) 14 | -------------------------------------------------------------------------------- /server/materials/data/level_nnoi2020.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | export default () -> 6 | return contest("2020", [ 7 | problem({testSystem: "codeforces", contest: "gym/103264", problem: "A", name: "Нейросеть"}), 8 | problem({testSystem: "codeforces", contest: "gym/103264", problem: "B"}), 9 | problem({testSystem: "codeforces", contest: "gym/103264", problem: "C"}), 10 | problem({testSystem: "codeforces", contest: "gym/103264", problem: "D"}), 11 | problem({testSystem: "codeforces", contest: "gym/103264", problem: "E"}), 12 | problem({testSystem: "codeforces", contest: "gym/103264", problem: "F"}), 13 | ]) 14 | -------------------------------------------------------------------------------- /server/materials/data/level_nnoi2021.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | export default nnoi2021 = () -> 6 | return contest("2021", [ 7 | problem({testSystem: "codeforces", contest: "gym/103262", problem: "A"}), 8 | problem({testSystem: "codeforces", contest: "gym/103262", problem: "B"}), 9 | problem({testSystem: "codeforces", contest: "gym/103262", problem: "C"}), 10 | problem({testSystem: "codeforces", contest: "gym/103262", problem: "D", name: "Магические посохи"}), 11 | problem({testSystem: "codeforces", contest: "gym/103262", problem: "E", name: "Проектор"}), 12 | problem({testSystem: "codeforces", contest: "gym/103262", problem: "F"}), 13 | ]) 14 | -------------------------------------------------------------------------------- /server/materials/data/level_nnoi2022.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | export default nnoi2022 = () -> 6 | return contest("2022", [ 7 | problem({testSystem: "codeforces", contest: "gym/105150", problem: "A"}), 8 | problem({testSystem: "codeforces", contest: "gym/105150", problem: "B", name: "Налоги"}), 9 | problem({testSystem: "codeforces", contest: "gym/105150", problem: "C", name: "Карта кобры"}), 10 | problem({testSystem: "codeforces", contest: "gym/105150", problem: "D"}), 11 | problem({testSystem: "codeforces", contest: "gym/105150", problem: "E"}), 12 | problem({testSystem: "codeforces", contest: "gym/105150", problem: "F"}), 13 | problem({testSystem: "codeforces", contest: "gym/105150", problem: "G"}), 14 | ]) 15 | -------------------------------------------------------------------------------- /server/materials/data/level_nnoi2023.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | export default nnoi2023 = () -> 6 | return contest("2023", [ 7 | problem({testSystem: "codeforces", contest: "gym/105151", problem: "A"}), 8 | problem({testSystem: "codeforces", contest: "gym/105151", problem: "B"}), 9 | problem({testSystem: "codeforces", contest: "gym/105151", problem: "C"}), 10 | problem({testSystem: "codeforces", contest: "gym/105151", problem: "D"}), 11 | problem({testSystem: "codeforces", contest: "gym/105151", problem: "E"}), 12 | problem({testSystem: "codeforces", contest: "gym/105151", problem: "F"}), 13 | problem({testSystem: "codeforces", contest: "gym/105151", problem: "G"}), 14 | problem({testSystem: "codeforces", contest: "gym/105151", problem: "H"}), 15 | ]) 16 | -------------------------------------------------------------------------------- /server/materials/data/level_reg2009.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_895 = () -> 6 | return contest("2009, 2 тур", [ 7 | problem(1209), 8 | problem(1210), 9 | problem(1211), 10 | problem(1212), 11 | ]) 12 | 13 | contest_894 = () -> 14 | return contest("2009, 1 тур", [ 15 | problem(1205), 16 | problem(1206), 17 | problem(1207), 18 | problem(1208), 19 | ]) 20 | 21 | export default level_reg2009 = () -> 22 | return level("reg2009", "2009", [ 23 | contest_894(), 24 | contest_895(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_reg2010.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_1540 = () -> 6 | return contest("2010, 1 тур", [ 7 | problem(1922), 8 | problem(1923), 9 | problem(1924), 10 | problem(1925), 11 | ]) 12 | 13 | contest_1541 = () -> 14 | return contest("2010, 2 тур", [ 15 | problem(1926), 16 | problem(1927), 17 | problem(1928), 18 | problem(1929), 19 | ]) 20 | 21 | export default level_reg2010 = () -> 22 | return level("reg2010", "2010", [ 23 | contest_1540(), 24 | contest_1541(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_reg2011.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_2780 = () -> 6 | return contest("2011, 2 тур", [ 7 | problem(3206), 8 | problem(3207), 9 | problem(3208), 10 | problem(3209), 11 | ]) 12 | 13 | contest_2748 = () -> 14 | return contest("2011, 1 тур", [ 15 | problem(3181), 16 | problem(3182), 17 | problem(3183), 18 | problem(3184), 19 | ]) 20 | 21 | export default level_reg2011 = () -> 22 | return level("reg2011", "2011", [ 23 | contest_2748(), 24 | contest_2780(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_reg2012.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_4345 = () -> 6 | return contest("2012, 1 тур", [ 7 | problem(3864), 8 | problem(3865), 9 | problem(3866), 10 | problem(3867), 11 | ]) 12 | 13 | contest_4361 = () -> 14 | return contest("2012, 2 тур", [ 15 | problem(3868), 16 | problem(3869), 17 | problem(3870), 18 | problem(3871), 19 | ]) 20 | 21 | export default level_reg2012 = () -> 22 | return level("reg2012", "2012", [ 23 | contest_4345(), 24 | contest_4361(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_reg2013.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_6667 = () -> 6 | return contest("2013, 1 тур", [ 7 | problem(111488), 8 | problem(111489), 9 | problem(111490), 10 | problem(111491), 11 | ]) 12 | 13 | contest_6670 = () -> 14 | return contest("2013, 2 тур", [ 15 | problem(111492), 16 | problem(111493), 17 | problem(111494), 18 | problem(111495), 19 | ]) 20 | 21 | export default level_reg2013 = () -> 22 | return level("reg2013", "2013", [ 23 | contest_6667(), 24 | contest_6670(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_reg2014.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_10372 = () -> 6 | return contest("2014, 1 тур", [ 7 | problem(112036), 8 | problem(112037), 9 | problem(112038), 10 | problem(112039), 11 | ]) 12 | 13 | contest_10376 = () -> 14 | return contest("2014, 2 тур", [ 15 | problem(112040), 16 | problem(112041), 17 | problem(112042), 18 | problem(112043), 19 | ]) 20 | 21 | export default level_reg2014 = () -> 22 | return level("reg2014", "2014", [ 23 | contest_10372(), 24 | contest_10376(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_reg2015.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_14482 = () -> 6 | return contest("2015, 1 тур", [ 7 | problem(112744), 8 | problem(112745), 9 | problem(112746), 10 | problem(112747), 11 | ]) 12 | 13 | contest_14483 = () -> 14 | return contest("2015, 2 тур", [ 15 | problem(112748), 16 | problem(112749), 17 | problem(112750), 18 | problem(112751), 19 | ]) 20 | 21 | export default level_reg2015 = () -> 22 | return level("reg2015", "2015", [ 23 | contest_14482(), 24 | contest_14483(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_reg2016.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_18805 = () -> 6 | return contest("2016, 1 тур", [ 7 | problem(113096), 8 | problem(113097), 9 | problem(113098), 10 | problem(113099), 11 | ]) 12 | 13 | contest_18806 = () -> 14 | return contest("2016, 2 тур", [ 15 | problem(113100), 16 | problem(113101), 17 | problem(113102), 18 | problem(113103), 19 | ]) 20 | 21 | export default level_reg2016 = () -> 22 | return level("reg2016", "2016", [ 23 | contest_18805(), 24 | contest_18806(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_reg2017.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_24703 = () -> 6 | return contest("2017, 2 тур", [ 7 | problem(113443), 8 | problem(113444), 9 | problem(113445), 10 | problem(113446), 11 | ]) 12 | 13 | contest_24702 = () -> 14 | return contest("2017, 1 тур", [ 15 | problem(113439), 16 | problem(113440), 17 | problem(113441), 18 | problem(113442), 19 | ]) 20 | 21 | export default level_reg2017 = () -> 22 | return level("reg2017", "2017", [ 23 | contest_24702(), 24 | contest_24703(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_reg2018.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_30794 = () -> 6 | return contest("2018, 2 тур", [ 7 | problem(113761), 8 | problem(113762), 9 | problem(113763), 10 | problem(113764), 11 | ]) 12 | 13 | contest_30793 = () -> 14 | return contest("2018, 1 тур", [ 15 | problem(113757), 16 | problem(113758), 17 | problem(113759), 18 | problem(113760), 19 | ]) 20 | 21 | export default level_reg2018 = () -> 22 | return level("reg2018", "2018", [ 23 | contest_30793(), 24 | contest_30794(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_reg2019.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_40162 = () -> 6 | return contest("2019, 1 тур", [ 7 | problem(114038), 8 | problem(114039), 9 | problem(114040), 10 | problem(114041), 11 | ]) 12 | 13 | contest_40163 = () -> 14 | return contest("2019, 2 тур", [ 15 | problem(114042), 16 | problem(114043), 17 | problem(114044), 18 | problem(114045), 19 | ]) 20 | 21 | export default level_reg2019 = () -> 22 | return level("reg2019", "2019", [ 23 | contest_40162(), 24 | contest_40163(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_reg2020.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | reg2020_1 = () -> 6 | return contest("2020, 1 тур", [ 7 | problem({testSystem: "codeforces", contest: "gym/102479", problem: "1"}), 8 | problem({testSystem: "codeforces", contest: "gym/102479", problem: "2", name: "Превышение скорости"}), 9 | problem({testSystem: "codeforces", contest: "gym/102479", problem: "3", name: "Борьба с рутиной"}), 10 | problem({testSystem: "codeforces", contest: "gym/102479", problem: "4", name: "Олимпиада для роботов"}), 11 | ]) 12 | 13 | reg2020_2 = () -> 14 | return contest("2020, 2 тур", [ 15 | problem({testSystem: "codeforces", contest: "gym/102480", problem: "5", name: "Максимальное произведение"}), 16 | problem({testSystem: "codeforces", contest: "gym/102480", problem: "6", name: "Планировка участка"}), 17 | problem({testSystem: "codeforces", contest: "gym/102480", problem: "7", name: "Банкомат"}), 18 | problem({testSystem: "codeforces", contest: "gym/102480", problem: "8", name: "Плакаты"}), 19 | ]) 20 | 21 | export default level_reg2020 = () -> 22 | return level("reg2020", "2020", [ 23 | reg2020_1(), 24 | reg2020_2(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_reg2021.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | reg2021_1 = () -> 6 | return contest("2021, 1 тур", [ 7 | problem({testSystem: "codeforces", contest: "gym/102935", problem: "1", name: "Два станка"}), 8 | problem({testSystem: "codeforces", contest: "gym/102935", problem: "2", name: "Разбиение таблицы"}), 9 | problem({testSystem: "codeforces", contest: "gym/102935", problem: "3", name: "Изменённая ДНК"}), 10 | problem({testSystem: "codeforces", contest: "gym/102935", problem: "4", name: "Антенна"}), 11 | ]) 12 | 13 | reg2021_2 = () -> 14 | return contest("2021, 2 тур", [ 15 | problem({testSystem: "codeforces", contest: "gym/102936", problem: "5", name: "Календарь на Альфе Центавра"}), 16 | problem({testSystem: "codeforces", contest: "gym/102936", problem: "6", name: "Числа"}), 17 | problem({testSystem: "codeforces", contest: "gym/102936", problem: "7", name: "Хорошие раскраски"}), 18 | problem({testSystem: "codeforces", contest: "gym/102936", problem: "8", name: "A+B"}), 19 | ]) 20 | 21 | export default level_reg2021 = () -> 22 | return level("reg2021", "2021", [ 23 | reg2021_1(), 24 | reg2021_2(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_reg2022.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | reg2022_1 = () -> 6 | return contest("2022, 1 тур", [ 7 | problem({testSystem: "codeforces", contest: "gym/103532", problem: "1", name: "Чемпионат по устному счету"}), 8 | problem({testSystem: "codeforces", contest: "gym/103532", problem: "2", name: "Прыгающий робот"}), 9 | problem({testSystem: "codeforces", contest: "gym/103532", problem: "3", name: "Треугольная головоломка"}), 10 | problem({testSystem: "codeforces", contest: "gym/103532", problem: "4", name: "Массивы-палиндромы"}), 11 | ]) 12 | 13 | reg2022_2 = () -> 14 | return contest("2022, 2 тур", [ 15 | problem({testSystem: "codeforces", contest: "gym/103533", problem: "5", name: "Новый год в детском саду"}), 16 | problem({testSystem: "codeforces", contest: "gym/103533", problem: "6", name: "Сортировка дробей"}), 17 | problem({testSystem: "codeforces", contest: "gym/103533", problem: "7", name: "Оптические каналы связи"}), 18 | problem({testSystem: "codeforces", contest: "gym/103533", problem: "8", name: "Подарки"}), 19 | ]) 20 | 21 | export default level_reg2022 = () -> 22 | return level("reg2022", "2022", [ 23 | reg2022_1(), 24 | reg2022_2(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_reg2023.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | reg2023_1 = () -> 6 | return contest("2023, 1 тур", [ 7 | problem({testSystem: "codeforces", contest: "gym/104155", problem: "1", name: "Разделение прямоугольника"}), 8 | problem({testSystem: "codeforces", contest: "gym/104155", problem: "2", name: "Произведение Фиббоначи"}), 9 | problem({testSystem: "codeforces", contest: "gym/104155", problem: "3", name: "Робот-пылесос"}), 10 | problem({testSystem: "codeforces", contest: "gym/104155", problem: "4", name: "Разноцветные точки"}), 11 | ]) 12 | 13 | reg2023_2 = () -> 14 | return contest("2023, 2 тур", [ 15 | problem({testSystem: "codeforces", contest: "gym/104156", problem: "5", name: "Метрострой"}), 16 | problem({testSystem: "codeforces", contest: "gym/104156", problem: "6", name: "Красивые последовательности"}), 17 | problem({testSystem: "codeforces", contest: "gym/104156", problem: "7", name: "Камни"}), 18 | problem({testSystem: "codeforces", contest: "gym/104156", problem: "8", name: "Обыкновенная задача про строки"}), 19 | ]) 20 | 21 | export default level_reg2023 = () -> 22 | return level("reg2023", "2023", [ 23 | reg2023_1(), 24 | reg2023_2(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_reg2024.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | reg2024_1 = () -> 6 | return contest("2024, 1 тур", [ 7 | problem({testSystem: "codeforces", contest: "gym/104949", problem: "1", name: "Посадка в самолёт"}), 8 | problem({testSystem: "codeforces", contest: "gym/104949", problem: "2", name: "Битоническая последовательность"}), 9 | problem({testSystem: "codeforces", contest: "gym/104949", problem: "3", name: "Игра с таблицей"}), 10 | problem({testSystem: "codeforces", contest: "gym/104949", problem: "4", name: "Выбор столицы"}), 11 | ]) 12 | 13 | reg2024_2 = () -> 14 | return contest("2024, 2 тур", [ 15 | problem({testSystem: "codeforces", contest: "gym/104950", problem: "5", name: "Разбиение массива"}), 16 | problem({testSystem: "codeforces", contest: "gym/104950", problem: "6", name: "Бактерии"}), 17 | problem({testSystem: "codeforces", contest: "gym/104950", problem: "7", name: "Разбиение на тройки"}), 18 | problem({testSystem: "codeforces", contest: "gym/104950", problem: "8", name: "Обходы бинарного дерева"}), 19 | ]) 20 | 21 | export default level_reg2024 = () -> 22 | return level("reg2024", "2024", [ 23 | reg2024_1(), 24 | reg2024_2(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_roi2004.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_791 = () -> 6 | return contest("2004, 1 тур", [ 7 | problem(1047), 8 | problem(1048), 9 | problem(1049), 10 | ]) 11 | 12 | contest_805 = () -> 13 | return contest("2004, 2 тур", [ 14 | problem(1053), 15 | problem(1054), 16 | problem(1055), 17 | ]) 18 | 19 | export default level_roi2004 = () -> 20 | return level("roi2004", "2004", [ 21 | contest_791(), 22 | contest_805(), 23 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_roi2005.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_195 = () -> 6 | return contest("2005, 1 тур", [ 7 | problem(9), 8 | problem(10), 9 | problem(11), 10 | ]) 11 | 12 | contest_196 = () -> 13 | return contest("2005, 2 тур", [ 14 | problem(12), 15 | problem(13), 16 | problem(14), 17 | ]) 18 | 19 | export default level_roi2005 = () -> 20 | return level("roi2005", "2005", [ 21 | contest_195(), 22 | contest_196(), 23 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_roi2006.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_197 = () -> 6 | return contest("2006, 1 тур", [ 7 | problem(8), 8 | problem(15), 9 | problem(16), 10 | ]) 11 | 12 | contest_198 = () -> 13 | return contest("2006, 2 тур", [ 14 | problem(17), 15 | problem(18), 16 | problem(19), 17 | ]) 18 | 19 | export default level_roi2006 = () -> 20 | return level("roi2006", "2006", [ 21 | contest_197(), 22 | contest_198(), 23 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_roi2007.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_199 = () -> 6 | return contest("2007, 1 тур", [ 7 | problem(20), 8 | problem(21), 9 | problem(22), 10 | ]) 11 | 12 | contest_200 = () -> 13 | return contest("2007, 2 тур", [ 14 | problem(23), 15 | problem(24), 16 | problem(25), 17 | ]) 18 | 19 | export default level_roi2007 = () -> 20 | return level("roi2007", "2007", [ 21 | contest_199(), 22 | contest_200(), 23 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_roi2008.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_922 = () -> 6 | return contest("2008, 1 тур", [ 7 | problem(1216), 8 | problem(1217), 9 | problem(1277), 10 | ]) 11 | 12 | contest_988 = () -> 13 | return contest("2008, 2 тур", [ 14 | problem(1281), 15 | problem(1282), 16 | problem(1283), 17 | ]) 18 | 19 | export default level_roi2008 = () -> 20 | return level("roi2008", "2008", [ 21 | contest_922(), 22 | contest_988(), 23 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_roi2009.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_1041 = () -> 6 | return contest("2009", [ 7 | problem(1337), 8 | problem(1338), 9 | problem(1339), 10 | problem(1340), 11 | problem(1341), 12 | problem(1342), 13 | ]) 14 | 15 | export default level_roi2009 = () -> 16 | return level("roi2009", "2009", [ 17 | contest_1041(), 18 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_roi2010.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_1681 = () -> 6 | return contest("2010", [ 7 | problem(2529), 8 | problem(2530), 9 | problem(2531), 10 | problem(2532), 11 | problem(2533), 12 | problem(2534), 13 | ]) 14 | 15 | export default level_roi2010 = () -> 16 | return level("roi2010", "2010", [ 17 | contest_1681(), 18 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_roi2011.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_3102 = () -> 6 | return contest("2011", [ 7 | problem(3393), 8 | problem(3394), 9 | problem(3395), 10 | problem(3396), 11 | problem(3397), 12 | problem(3398), 13 | problem(3399), 14 | problem(3400), 15 | ]) 16 | 17 | export default level_roi2011 = () -> 18 | return level("roi2011", "2011", [ 19 | contest_3102(), 20 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_roi2012.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_4908 = () -> 6 | return contest("2012", [ 7 | problem(111221), 8 | problem(111222), 9 | problem(111223), 10 | problem(111224), 11 | problem(111225), 12 | problem(111226), 13 | problem(111562), 14 | problem(111227), 15 | ]) 16 | 17 | export default level_roi2012 = () -> 18 | return level("roi2012", "2012", [ 19 | contest_4908(), 20 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_roi2013.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_7334 = () -> 6 | return contest("2013, 1 тур", [ 7 | problem(111633), 8 | problem(111634), 9 | problem(111635), 10 | problem(111636), 11 | ]) 12 | 13 | contest_7513 = () -> 14 | return contest("2013, 2 тур", [ 15 | problem(111637), 16 | problem(111644), 17 | problem(111645), 18 | problem(111646), 19 | ]) 20 | 21 | export default level_roi2013 = () -> 22 | return level("roi2013", "2013", [ 23 | contest_7334(), 24 | contest_7513(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_roi2014.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_11347 = () -> 6 | return contest("2014, 1 тур", [ 7 | problem(112335), 8 | problem(112332), 9 | problem(112333), 10 | problem(112334), 11 | ]) 12 | 13 | contest_11348 = () -> 14 | return contest("2014, 2 тур", [ 15 | problem(112328), 16 | problem(112330), 17 | problem(112329), 18 | ]) 19 | 20 | export default level_roi2014 = () -> 21 | return level("roi2014", "2014", [ 22 | contest_11347(), 23 | contest_11348(), 24 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_roi2015.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_15255 = () -> 6 | return contest("2015, 1 тур", [ 7 | problem(112815), 8 | problem(112816), 9 | problem(112817), 10 | problem(112818), 11 | ]) 12 | 13 | contest_15256 = () -> 14 | return contest("2015, 2 тур", [ 15 | problem(112819), 16 | problem(112820), 17 | problem(112821), 18 | problem(112822), 19 | ]) 20 | 21 | export default level_roi2015 = () -> 22 | return level("roi2015", "2015", [ 23 | contest_15255(), 24 | contest_15256(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_roi2016.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_20058 = () -> 6 | return contest("2016, 1 тур", [ 7 | problem(113217), 8 | problem(113218), 9 | problem(113219), 10 | problem(113220), 11 | ]) 12 | 13 | contest_20059 = () -> 14 | return contest("2016, 2 тур", [ 15 | problem(113221), 16 | problem(113222), 17 | problem(113223), 18 | problem(113224), 19 | ]) 20 | 21 | export default level_roi2016 = () -> 22 | return level("roi2016", "2016", [ 23 | contest_20058(), 24 | contest_20059(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_roi2017.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_26246 = () -> 6 | return contest("2017, 2 тур", [ 7 | problem(113548), 8 | problem(113549), 9 | problem(113550), 10 | problem(113551), 11 | ]) 12 | 13 | contest_26245 = () -> 14 | return contest("2017, 1 тур", [ 15 | problem(113544), 16 | problem(113545), 17 | problem(113546), 18 | problem(113547), 19 | ]) 20 | 21 | export default level_roi2017 = () -> 22 | return level("roi2017", "2017", [ 23 | contest_26245(), 24 | contest_26246(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_roi2018.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_32817 = () -> 6 | return contest("2018, 1 тур", [ 7 | problem(113911), 8 | problem(113912), 9 | problem(113913), 10 | problem(113914), 11 | ]) 12 | 13 | contest_32818 = () -> 14 | return contest("2018, 2 тур", [ 15 | problem(113915), 16 | problem(113916), 17 | problem(113917), 18 | problem(113918), 19 | ]) 20 | 21 | export default level_roi2018 = () -> 22 | return level("roi2018", "2018", [ 23 | contest_32817(), 24 | contest_32818(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_roi2019.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_41904 = () -> 6 | return contest("2019, 2 тур", [ 7 | problem(114129), 8 | problem(114130), 9 | problem(114131), 10 | problem(114132), 11 | ]) 12 | 13 | contest_41903 = () -> 14 | return contest("2019, 1 тур", [ 15 | problem(114125), 16 | problem(114126), 17 | problem(114127), 18 | problem(114128), 19 | ]) 20 | 21 | export default level_roi2019 = () -> 22 | return level("roi2019", "2019", [ 23 | contest_41903(), 24 | contest_41904(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_roi2021.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_76875 = () -> 6 | return contest("2021, 1 тур", [ 7 | problem(114896), 8 | problem(114897), 9 | problem(114898), 10 | ]) 11 | 12 | contest_76876 = () -> 13 | return contest("2021, 2 тур", [ 14 | problem(114895), 15 | problem(114894), 16 | problem(114899), 17 | problem(114900), 18 | ]) 19 | 20 | export default level_roi2021 = () -> 21 | return level("roi2021", "2021", [ 22 | contest_76875(), 23 | contest_76876(), 24 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_roi2022.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | contest_74625 = () -> 6 | return contest("2022, 1 тур", [ 7 | problem(114760), 8 | problem(114761), 9 | problem(114762), 10 | problem(114763), 11 | ]) 12 | 13 | contest_74664 = () -> 14 | return contest("2022, 2 тур", [ 15 | problem(114764), 16 | problem(114765), 17 | problem(114766), 18 | problem(114767), 19 | ]) 20 | 21 | export default level_roi2022 = () -> 22 | return level("roi2022", "2022", [ 23 | contest_74625(), 24 | contest_74664(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_roi2023.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../lib/contest" 2 | import level from "../lib/level" 3 | import problem from "../lib/problem" 4 | 5 | roi2023_1 = () -> 6 | return contest("2023, 1 тур", [ 7 | problem({testSystem: "codeforces", contest: "gym/104290", problem: "1", name: "Видеонаблюдение"}), 8 | problem({testSystem: "codeforces", contest: "gym/104290", problem: "2", name: "Тайное послание"}), 9 | problem({testSystem: "codeforces", contest: "gym/104290", problem: "3", name: "Рекорды и антирекорды"}), 10 | problem({testSystem: "codeforces", contest: "gym/104290", problem: "4", name: "Ультра mex"}), 11 | ]) 12 | 13 | roi2023_2 = () -> 14 | return contest("2023, 2 тур", [ 15 | problem({testSystem: "codeforces", contest: "gym/104291", problem: "5", name: "Улитка на склоне"}), 16 | problem({testSystem: "codeforces", contest: "gym/104291", problem: "6", name: "Конференция"}), 17 | problem({testSystem: "codeforces", contest: "gym/104291", problem: "7", name: "Яблоки по корзинам"}), 18 | problem({testSystem: "codeforces", contest: "gym/104291", problem: "8", name: "Выполнить план, но не перевыполнить"}), 19 | ]) 20 | 21 | export default level_roi2023 = () -> 22 | return level("roi2023", "2023", [ 23 | roi2023_1(), 24 | roi2023_2(), 25 | ]) -------------------------------------------------------------------------------- /server/materials/data/level_sch.coffee: -------------------------------------------------------------------------------- 1 | import label from "../lib/label" 2 | import level from "../lib/level" 3 | import level_sch2021 from "./level_sch2021" 4 | 5 | export default level_reg = () -> 6 | return level("sch", "Школьные олимпиады", [ 7 | label("

C 2020 года олимпиады проводятся на платформе Сириус, с 2021 г. задачи доступны на Codeforces.

"), 8 | level_sch2021(), 9 | ]) -------------------------------------------------------------------------------- /server/materials/data/root.coffee: -------------------------------------------------------------------------------- 1 | import link from "../lib/link" 2 | import main from "../lib/main" 3 | import level_about from "./level_about" 4 | import level_sch from "./level_sch" 5 | import level_nnoi from "./level_nnoi" 6 | import level_reg from "./level_reg" 7 | import level_roi from "./level_roi" 8 | import mainLevels from './mainLevels' 9 | import allNews from "./news" 10 | import tables from './tables' 11 | 12 | export default root = () -> 13 | return main([ 14 | level_about(), 15 | allNews(), 16 | link("/comments", "Комментарии", "comments"), 17 | link("/findMistakeList", "Найди ошибку", "findMistake"), 18 | mainLevels()..., 19 | level_sch(), 20 | level_nnoi(), 21 | level_reg(), 22 | level_roi(), 23 | tables() 24 | ]) -------------------------------------------------------------------------------- /server/materials/data/topics/2sat.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default two_sat = () -> 10 | return { 11 | topic: topic( 12 | ruen("2-SAT", "2-SAT"), 13 | ruen("Задачи на 2-SAT", "Problems on 2-SAT"), 14 | [label(ruen( 15 | "Теория на e-maxx", 16 | "Theory on e-maxx")), 17 | problem({testSystem: "codeforces", contest: "1239", problem: "D"}), # конкурс котиков 18 | problem({testSystem: "codeforces", contest: "1903", problem: "F"}), # няня 19 | problem({testSystem: "codeforces", contest: "1657", problem: "F"}), # слова 20 | problem({testSystem: "codeforces", contest: "568", problem: "C"}), # новый язык 21 | problem({testSystem: "codeforces", contest: "587", problem: "D"}), # duff 22 | ], 23 | "2sat"), 24 | advancedProblems: [ 25 | problem(113793) 26 | problem({testSystem: "codeforces", contest: "1215", problem: "F"}), 27 | ] 28 | } -------------------------------------------------------------------------------- /server/materials/data/topics/advanced_scanline.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default advanced_scanline = () -> 10 | return { 11 | topic: topic( 12 | ruen("Продвинутый scanline", "Advanced scanline"), 13 | ruen("Задачи на продвинутый scanline", "Problems on advanced scanline"), 14 | [problem(1217), 15 | problem(2866), 16 | problem(111800), 17 | problem(113809), 18 | ], "advanced_scanline"), 19 | advancedProblems: [ 20 | problem(112817) 21 | ] 22 | } -------------------------------------------------------------------------------- /server/materials/data/topics/aho_corasick.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default aho_corasick = () -> 10 | return { 11 | topic: topic( 12 | ruen("Алгоритм Ахо-Корасик", "The Aho-Korasik algorithm"), 13 | ruen("Задачи на Ахо-Корасик", "Problems on Aho-Korasik"), 14 | [label(ruen( 15 | "

См. теорию на e-maxx.

", 16 | "

See the theory on e-maxx.

")), 17 | problem(111732), 18 | ], "aho"), 19 | advancedProblems: [ 20 | problem(2881), 21 | ] 22 | } -------------------------------------------------------------------------------- /server/materials/data/topics/bfs_01.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default bfs_01 = () -> 10 | return { 11 | topic: topic( 12 | ruen("Поиск в ширину в 1-k и 0-k графах", "Breadth-first search in 1-k and 0-k graphs"), 13 | ruen("Задачи на поиск в ширину в 1-k и 0-k графах", "Problems on breadth-first search in 1-k and 0-k graphs"), 14 | [label(ruen( 15 | "Видеозаписи ЛКШ, 2013, B'
\nВидеозаписи ЛКШ, 2008, B' (см. эту и следующие темы, до \"Повторение: кратчайшие пути в 0-1-графе.\")", 16 | "SIS videos, 2013, B'
\nSIS videos, 2008, B' (see this and the following topics, up to \"Repetition: Shortest paths in a 0-1 graph.\")")), 17 | problem(3376), 18 | problem(2003), 19 | ], "bfs_01") 20 | } -------------------------------------------------------------------------------- /server/materials/data/topics/binary_trees_and_trie.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default binary_trees_and_trie = () -> 10 | return { 11 | topic: topic( 12 | ruen("Бинарные деревья и бор", "Binary trees and trie"), 13 | ruen("Задачи на бинарные деревья и бор", "Problems on binary trees and trie"), 14 | [problem(757), 15 | problem(760), 16 | problem(761), 17 | problem(111730), 18 | problem(3302), 19 | problem(111729), 20 | ], "trees_and_trie"), 21 | advancedProblems: [ 22 | problem(30), 23 | problem(1044), 24 | ] 25 | } -------------------------------------------------------------------------------- /server/materials/data/topics/cartesian_tree_implicit.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default cartesian_tree_implicit = () -> 10 | return { 11 | topic: topic( 12 | ruen("Декартово дерево по неявному ключу", "Cartesian tree with implicit key"), 13 | ruen("Задачи на декартово дерево по неявному ключу", "Problems on cartesian tree with implicit key"), 14 | [label(ruen( 15 | "

Теория на e-maxx
\nТеория на хабре
\nДумаю, еще много чего легко ищется в интернете

", 16 | "

Theory on e-maxx
\nTheory on habr
\nI think a lot of other things are easily searched for on the Internet

")), 17 | problem(2791), 18 | problem(111881), 19 | ], "implicit_cartesian_tree"), 20 | advancedProblems: [ 21 | problem(571), 22 | ] 23 | } -------------------------------------------------------------------------------- /server/materials/data/topics/debugging.coffee: -------------------------------------------------------------------------------- 1 | import label from "../../lib/label" 2 | import topic from "../../lib/topic" 3 | import {ruen} from "../../lib/util" 4 | 5 | export default debugging = () -> 6 | return { 7 | topic: topic( 8 | ruen("Как отлаживать программы", "How to debug programs"), 9 | null, 10 | [label(ruen( 11 | "Про то, как искать ошибки в маленьких программах. Вы, наверное, пока еще не все тут поймете, но тем не менее прочитайте, а потом возвращайтесь к этому тексту на всем протяжении уровня 1.", 12 | "How to debug small programs. This is a rather famous text, although I find it way too complex. Anyway, read it and you may find it useful, and one day I will add my own vision of this topic here." 13 | )), 14 | # TODO: en 15 | #"About how to look for errors in small programs. You probably won't understand everything here yet, but read it anyway, and then come back to this text throughout level 1.")), 16 | ], "debugging"), 17 | count: false 18 | } 19 | -------------------------------------------------------------------------------- /server/materials/data/topics/dijkstra_with_heap.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default dijkstra_with_heap = () -> 10 | return { 11 | topic: topic( 12 | ruen("Алгоритм Дейкстры с кучей", "Dijkstra's algorithm with heap"), 13 | ruen("Задачи на алгоритм Дейкстры с кучей", "Problems on Dijkstra's algorithm with heap"), 14 | [label(ruen( 15 | "См. видеозаписи лекций ЛКШ.2013.B', раздел \"Алгоритм Дейкстры поиска кратчайших путей. Использование кучи.\"", 16 | "See the video recordings of lectures SIS.2013.B', section \"Dijkstra algorithm for finding shortest paths. Using the heap.\"")), 17 | problem(3494), 18 | problem(1745), 19 | problem(1087), 20 | ], "dijkstra_with_heap"), 21 | advancedProblems: [ 22 | problem(1967), 23 | ] 24 | } -------------------------------------------------------------------------------- /server/materials/data/topics/divide_and_conquer.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default divide_and_conquer = () -> 10 | return { 11 | topic: topic( 12 | ruen("Разделяй и влавствуй", "Divide and conquer"), 13 | ruen("Задачи на разделяй и влавствуй", "Problems on divide and conquer"), 14 | [ 15 | problem({testSystem: "codeforces", contest: "429", problem: "D"}), 16 | problem({testSystem: "codeforces", contest: "120", problem: "J"}), 17 | #problem({testSystem: "codeforces", contest: "100273", problem: "A"}), # TODO 18 | ], "divide_and_conquer"), 19 | } -------------------------------------------------------------------------------- /server/materials/data/topics/dp_advanced.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default dp_advanced = () -> 10 | return { 11 | topic: topic( 12 | ruen("Сложные задачи на ДП", "Difficult problems on DP"), 13 | ruen("Сложные задачи на ДП", "Difficult problems on DP"), 14 | [problem(1793), 15 | problem(1720), 16 | problem(3898), 17 | problem(111490), 18 | ], "dp_advanced"), 19 | additionalProblems: [ 20 | problem(11), 21 | problem(16), 22 | problem(2534), 23 | ] 24 | } -------------------------------------------------------------------------------- /server/materials/data/topics/dp_hard.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default dp_hard = () -> 10 | return { 11 | topic: topic( 12 | ruen("Супер-сложное ДП", "Super-difficult DP"), 13 | ruen("Задачи на супер-сложное ДП", "Problems on super-difficult DP"), 14 | [label(ruen( 15 | "Полезный прием: convex hull trick", 16 | "Useful technique: convex hull trick")), 17 | problem({testSystem: "codeforces", contest: "1083", problem: "E"}), 18 | problem({testSystem: "codeforces", contest: "319", problem: "C"}), 19 | problem({testSystem: "codeforces", contest: "311", problem: "B"}), 20 | ], "dp_hard"), 21 | advancedProblems: [ 22 | problem({testSystem: "codeforces", contest: "631", problem: "E"}), 23 | problem({testSystem: "codeforces", contest: "1388", problem: "E"}), 24 | problem({testSystem: "codeforces", contest: "932", problem: "F"}), 25 | ] 26 | } -------------------------------------------------------------------------------- /server/materials/data/topics/dp_middle.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default dp_middle = () -> 10 | return { 11 | topic: topic( 12 | ruen("Задачи средней сложности на ДП", "Problems of medium difficulty on DP"), 13 | ruen("Задачи средней сложности на ДП", "Problems of medium difficulty on DP"), 14 | [problem(212), 15 | problem(492), 16 | problem(587), 17 | problem(515), 18 | problem(545), 19 | problem(208), 20 | problem(1129), 21 | ], "dp_middle"), 22 | advancedProblems: [ 23 | problem(860), 24 | problem(3717), 25 | problem(218), 26 | problem(1212), 27 | problem(215), 28 | problem(1254), 29 | problem(1106), 30 | problem(3892), 31 | problem(44), 32 | problem(691), 33 | problem(111882), 34 | ] 35 | } -------------------------------------------------------------------------------- /server/materials/data/topics/dp_sbory.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default dp_sbory = () -> 10 | return { 11 | topic: topic( 12 | ruen("*Доп. задачи на ДП", "*Additional tasks for DP"), 13 | ruen("*Дополнительные задачи на ДП", "*Additional tasks on DP"), 14 | [label(ruen( 15 | "Это задачи на ДП с зимних сборов алгопрога 2021. Раздел не обязательный. Сложность задач очень разная.", 16 | "These are the tasks for the DP from the winter training camps of the algoprog 2021. The section is optional. The difficulty of the tasks is very different.")) 17 | problem(498), 18 | problem(44), 19 | problem(631), 20 | problem(691), 21 | problem(217), 22 | problem(1212), 23 | problem(24), 24 | problem(571), 25 | problem(78), 26 | problem({testSystem: "ejudge", contest: "3001", problem: "2"}), 27 | problem({testSystem: "ejudge", contest: "3001", problem: "1"}), 28 | ], "dp_sbory"), 29 | count: 0 30 | } -------------------------------------------------------------------------------- /server/materials/data/topics/events_sort.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default events_sort = () -> 10 | return { 11 | topic: topic( 12 | ruen("Сортировка событий", "Sorting events"), 13 | ruen("Задачи на сортировку событий", "Problems on sorting events"), 14 | [label(ruen( 15 | "См. видеозаписи лекций ЛКШ параллели B', раздел «Отрезки на прямой»
", 16 | "See video recordings of lectures of the Parallel B' LCS, section \"Straight line segments\"
")), 17 | problem(112542), 18 | problem(1755), 19 | problem(3721), 20 | problem(1338), 21 | problem(111790), 22 | ], "events_sort"), 23 | advancedProblems: [ 24 | problem(1622) 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /server/materials/data/topics/games_cyclic.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default games_cyclic = () -> 10 | return { 11 | topic: topic( 12 | ruen("Игры на циклических графах", "Games on cyclic graphs"), 13 | ruen("Задачи на игры на циклических графах", "Problems on games on cyclic graphs"), 14 | [problem(3390), 15 | problem({testSystem: "codeforces", contest: "787", problem: "C"}), 16 | ], "games_cyclic"), 17 | } -------------------------------------------------------------------------------- /server/materials/data/topics/games_simple.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default simple_games = () -> 10 | return { 11 | topic: topic( 12 | ruen("Простые игры на графах", "Simple games on graphs"), 13 | ruen("Задачи на простые игры на графах", "Problems on simple games on graphs"), 14 | [label(ruen( 15 | "Некоторая теория на e-maxx", 16 | "Some theory on e-maxx")), 17 | problem(202), 18 | problem(366), 19 | problem(3344), 20 | problem(371), 21 | ], "games_simple"), 22 | advancedProblems: [ 23 | problem(112448), 24 | problem(112445), 25 | ] 26 | } -------------------------------------------------------------------------------- /server/materials/data/topics/geometry_advanced.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default geometry_advanced = () -> 10 | return { 11 | topic: topic( 12 | ruen("Сложная геометрия", "Advanced geometry"), 13 | ruen("Задачи на сложную геометрию", "Problems on advanced geometry"), 14 | [problem(34), 15 | problem(923), 16 | problem(1109), 17 | problem(111780), 18 | problem(1360), 19 | problem(1128), 20 | problem(3209), 21 | ], "geometry_advanced"), 22 | advancedProblems: [ 23 | problem(519), 24 | problem(111500), 25 | problem(3894), 26 | problem(19), 27 | problem(3400), 28 | problem(111828), 29 | ] 30 | } -------------------------------------------------------------------------------- /server/materials/data/topics/grundy.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default grundy = () -> 10 | return { 11 | topic: topic( 12 | ruen("Функция Гранди", "Grundi's function"), 13 | ruen("Задачи на функцию Гранди", "Problems on grundy function"), 14 | [label(ruen( 15 | "

Теория на e-maxx
\nТеория на хабре
\nМожете еще в интернете поискать

", 16 | "

Theory on e-maxx
\nTheory on habr
\nYou can also search the Internet

")), 17 | problem(369), 18 | problem(905), 19 | problem(2916), 20 | ], "grundy") 21 | } -------------------------------------------------------------------------------- /server/materials/data/topics/heap.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default heap = () -> 10 | return { 11 | topic: topic( 12 | ruen("Куча", "Heap"), 13 | ruen("Задачи на кучу", "Problems on heap"), 14 | [label(ruen( 15 | "См. видеозаписи лекций ЛКШ.2013.B', раздел \"Куча\"
\nСм. видеозаписи лекций ЛКШ.2008.B', раздел \"Куча\"", 16 | "See the video recordings of lectures of SIS.2013.B', section \"Heap\"
\nSee video recordings of lectures of SIS.2008.B', section \"Heap\"")), 17 | problem(755), 18 | problem(756), 19 | problem(489), 20 | ], "heap"), 21 | advancedProblems: [ 22 | problem(3350), 23 | problem(1207), 24 | ] 25 | } -------------------------------------------------------------------------------- /server/materials/data/topics/hld.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default hld = () -> 10 | return { 11 | topic: topic( 12 | ruen("Heavy-light decomposition", "Heavy-light decomposition"), 13 | ruen("Задачи на HLD", "Problems on HLD"), 14 | [ 15 | label(ruen( 16 | "Некоторея теория", 17 | "Some theory")) 18 | problem({testSystem: "codeforces", contest: "600", problem: "E"}), 19 | problem({testSystem: "codeforces", contest: "570", problem: "D"}), 20 | problem({testSystem: "codeforces", contest: "246", problem: "E"}), 21 | ], "hld"), 22 | advancedProblems: [ 23 | problem({testSystem: "codeforces", contest: "208", problem: "E"}), 24 | problem({testSystem: "codeforces", contest: "291", problem: "E"}), 25 | ] 26 | } -------------------------------------------------------------------------------- /server/materials/data/topics/inclusion_exclusion.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default two_sat = () -> 10 | return { 11 | topic: topic( 12 | ruen("Формула включения-исключения", "Inclusion-exclusion formula"), 13 | ruen("Задачи на формулу включения-исключения", "Problems on the inclusion-exclusion formula"), 14 | [ 15 | problem(552), 16 | ], "inclusion_exclusion"), 17 | advancedProblems: [ 18 | problem({testSystem: "codeforces", contest: "585", problem: "E"}), 19 | ] 20 | } -------------------------------------------------------------------------------- /server/materials/data/topics/lca.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default lca = () -> 10 | return { 11 | topic: topic( 12 | ruen("LCA (наименьший общий предок)", "Lowest common ancestor"), 13 | ruen("Задачи на LCA", "Problems on LCA"), 14 | [label(ruen( 15 | "

Теория по LCA от Алексея Упирвицкого

\n

См. еще теорию на e-maxx (там несколько разделов).

", 16 | "

Theory on LCA by Alexey Upirvitsky

\n

See more theory on e-maxx (there are several sections).

")), 17 | problem(111796), 18 | problem(111711), 19 | problem(111894) 20 | ], "lca"), 21 | advancedProblems: [ 22 | problem(724) 23 | ] 24 | } -------------------------------------------------------------------------------- /server/materials/data/topics/mass_operations.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default mass_operations = () -> 10 | return { 11 | topic: topic( 12 | ruen("Групповые операции на деревьях", "Group operations on trees"), 13 | ruen("Задачи на групповые операции", "Problems on group operations"), 14 | [label(ruen( 15 | "

См. теорию на e-maxx.

", 16 | "

See the theory on e-maxx.

")), 17 | problem(3327), 18 | problem(3329), 19 | problem(1364), 20 | problem(3328), 21 | problem(111240) 22 | ], "mass_operations"), 23 | advancedProblems: [ 24 | problem(113563), 25 | problem(113775), 26 | problem(113287), 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /server/materials/data/topics/matrices.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default matrices = () -> 10 | return { 11 | topic: topic( 12 | ruen("Матрицы и их применение к ДП", "Matrices and their application to DP"), 13 | ruen("Задачи на матрицы", "Problems on matrices"), 14 | [label(ruen( 15 | "

См.\nтеорию по методу Гаусса на e-maxx. Теории по применению матриц к ДП в удобоваримом виде я не нашел.\n

", 16 | "

See\nthe theory of the Gauss method on e-maxx. I have not found a theory on the application of matrices to DP in a digestible form.\n

")), 17 | problem(76), 18 | ], "matrices") 19 | } -------------------------------------------------------------------------------- /server/materials/data/topics/maxmatching.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default maxmatching = () -> 10 | return { 11 | topic: topic( 12 | ruen("Паросочетание максимального веса, венгерский алгоритм", "Maximum weight matching, Hungarian algorithm"), 13 | ruen("Задачи на венгерский алгоритм", "Problems on hungarian algorithm"), 14 | [label(ruen( 15 | "

См.\nтеорию на e-maxx, но можно писать и mincost-maxflow.\n

", 16 | "

See\nthe theory on e-maxx, but you can also write mincost-maxflow.\n

")), 17 | problem(111556), 18 | problem({testSystem: "codeforces", contest: "1107", problem: "F"}), 19 | ], "maxmatching") 20 | } -------------------------------------------------------------------------------- /server/materials/data/topics/mincost_maxflow.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default mincost_maxflow = () -> 10 | return { 11 | topic: topic( 12 | ruen("Mincost-maxflow", "Mincost-maxflow"), 13 | ruen("Задачи на mincost-maxflow", "Problems on mincost-maxflow"), 14 | [label(ruen( 15 | "

См. теорию на e-maxx\n

", 16 | "

See the theory on e-maxx\n

")), 17 | problem({testSystem: "codeforces", contest: "863", problem: "F"}), 18 | problem({testSystem: "codeforces", contest: "818", problem: "G"}), 19 | problem({testSystem: "codeforces", contest: "1187", problem: "G"}), 20 | ], "mincost_maxflow") 21 | } -------------------------------------------------------------------------------- /server/materials/data/topics/persistency.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default persistency = () -> 10 | return { 11 | topic: topic( 12 | ruen("Персистентные структуры данных", "Persistent data structures"), 13 | ruen("Задачи на персистентные структуры данных", "Problems on persistent data structures"), 14 | [problem(114323), 15 | problem(1817) 16 | problem(2980) 17 | problem(111614) 18 | problem({testSystem: "codeforces", contest: "1000", problem: "F"}), 19 | ], "persistency"), 20 | } -------------------------------------------------------------------------------- /server/materials/data/topics/primes.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import problem from "../../lib/problem" 4 | import topic from "../../lib/topic" 5 | import {ruen} from "../../lib/util" 6 | 7 | export default primes = () -> 8 | return { 9 | topic: topic( 10 | ruen("Простые числа и разложение на множители", "Prime numbers and factorization"), 11 | ruen("Задачи на множители", "Problems on factorization"), 12 | [label(ruen( 13 | "См. видеозаписи лекций ЛКШ параллели C', раздел «Арифметические алгоритмы»", 14 | "Theory on cp-algorithms: section one, section two, section three (you don't need advanced topics like Fermat's or Miller-Rabin methods)")), 15 | problem(310), 16 | problem(623), 17 | problem(973), 18 | ], "primes"), 19 | advancedProblems: [ 20 | problem(152), 21 | problem(584), 22 | problem(1009), 23 | problem(1037), 24 | problem(422), 25 | ] 26 | } -------------------------------------------------------------------------------- /server/materials/data/topics/pythonAdditional.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import labelLink from "../../lib/labelLink" 4 | import problem from "../../lib/problem" 5 | import topic from "../../lib/topic" 6 | import {ruen} from "../../lib/util" 7 | 8 | export default pythonAdditional = () -> 9 | return { 10 | topic: topic( 11 | ruen("*Дополнительные замечания по питону", "*Additional notes on python"), 12 | null, 13 | [labelLink(ruen("https://notes.algoprog.ru/python_basics/6_functions.html", "https://notes.algoprog.ru/en/python_basics/6_functions.html"), ruen("Функции", "Functions")) 14 | labelLink(ruen("https://notes.algoprog.ru/python_basics/7_files.html", "https://notes.algoprog.ru/en/python_basics/7_files.html"), ruen("Работа с файлами", "Working with files")) 15 | labelLink(ruen("https://notes.algoprog.ru/python_basics/8_addtypes.html", "https://notes.algoprog.ru/en/python_basics/8_addtypes.html"), ruen("Еще разные полезные типы данных", "Some additional useful data types")) 16 | ], "python_additional"), 17 | count: false 18 | } -------------------------------------------------------------------------------- /server/materials/data/topics/sparse_tables.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default sparse_tables = () -> 10 | return { 11 | topic: topic( 12 | ruen("Sparse tables, двоичный подъем", "Sparse tables, binary ascent"), 13 | ruen("Задачи на sparse tables", "Problems on sparse tables"), 14 | [ label(ruen( 15 | "

Теория на хабре
\nЕще теория
\nБолее продвинутая структура, нужна не так часто: Disjoint sparse tables

", 16 | "")), 17 | problem(113919), 18 | problem(752), 19 | ], "sparse_tables"), 20 | advancedProblems: [ 21 | problem(113550), 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /server/materials/data/topics/suffixes.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default suffixes = () -> 10 | return { 11 | topic: topic( 12 | ruen("Суффиксные структуры данных", "Suffix data structures"), 13 | ruen("Задачи на суффиксные структуры", "Problems on suffix structures"), 14 | [label(ruen( 15 | "

См. теорию на e-maxx:
\nсуффиксный массив,
\nсуффиксный автомат,
\nсуффиксное дерево.

", 16 | "

See the theory on e-maxx:
\nsuffix array,
\nsuffix automaton,
\nsuffix tree.

")), 17 | problem(111789), 18 | ], "suffixes"), 19 | advancedProblems: [ 20 | problem(113932), 21 | ] 22 | } -------------------------------------------------------------------------------- /server/materials/data/topics/tertiary_search.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default tertiary_search = () -> 10 | return { 11 | topic: topic( 12 | ruen("Тернарный (троичный) поиск", "Ternary search"), 13 | ruen("Задачи на тернарный поиск", "Problems on ternary search"), 14 | [label(ruen( 15 | "См. видеозаписи лекций ЛКШ.2013.B', раздел \"тернарный поиск\"", 16 | "See the video recordings of lectures of SIS.2013.B', section \"ternary search\"")), 17 | problem(3398), 18 | problem(3859), 19 | problem({testSystem: "codeforces", contest: "1288", problem: "A"}), 20 | problem({testSystem: "codeforces", contest: "782", problem: "B"}), 21 | ], "tertiary_search"), 22 | advancedProblems: [ 23 | problem(1116), 24 | problem({testSystem: "codeforces", contest: "1354", problem: "C1"}), 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /server/materials/data/topics/testing_advanced.coffee: -------------------------------------------------------------------------------- 1 | import contest from "../../lib/contest" 2 | import label from "../../lib/label" 3 | import link from "../../lib/link" 4 | import page from "../../lib/page" 5 | import problem from "../../lib/problem" 6 | import topic from "../../lib/topic" 7 | import {ruen} from "../../lib/util" 8 | 9 | export default testing_advanced = () -> 10 | return { 11 | topic: topic( 12 | ruen("Продвинутое тестирование задач", null), 13 | null, 14 | [label(ruen( 15 | "

Перечитайте еще раз текст про тестирование задач из уровня 1В — вам он теперь наверняка еще более полезен, и вы можете освоить более продвинутые техники (если еще не освоили).

", 16 | # TODO: translate 17 | null)), 18 | ], "testing_advanced"), 19 | count: false 20 | } -------------------------------------------------------------------------------- /server/materials/lib/contest.coffee: -------------------------------------------------------------------------------- 1 | import MaterialList from "./MaterialList" 2 | 3 | class Contest extends MaterialList 4 | constructor: (@title, materials) -> 5 | super(materials) 6 | 7 | build: (context, order) -> 8 | properties = 9 | _id: context.generateId() 10 | type: "contest" 11 | title: @title?(context.label) || @title 12 | 13 | material = await super.build(context, order, properties, {allowAsync: true}) 14 | 15 | return material 16 | 17 | export default contest = (args...) -> () -> new Contest(args...) -------------------------------------------------------------------------------- /server/materials/lib/epigraph.coffee: -------------------------------------------------------------------------------- 1 | import {Page} from './page' 2 | 3 | class Epigraph extends Page 4 | constructor: (title, content) -> 5 | super(title, content, {type: "epigraph"}) 6 | 7 | export default epigraph = (args...) -> () -> new Epigraph(args...) -------------------------------------------------------------------------------- /server/materials/lib/label.coffee: -------------------------------------------------------------------------------- 1 | export class Label 2 | constructor: (@content) -> 3 | 4 | build: (context, order) -> 5 | data = 6 | _id: context.generateId(), 7 | type: "label", 8 | content: @content?(context.label) || @content 9 | order: order 10 | 11 | await context.process(data) 12 | return data 13 | 14 | export default label = (args...) -> () -> new Label(args...) -------------------------------------------------------------------------------- /server/materials/lib/labelLink.coffee: -------------------------------------------------------------------------------- 1 | import {Label} from './label' 2 | 3 | class LabelLink extends Label 4 | constructor: (link, name) -> 5 | super((label) -> "#{name?(label) || name}") 6 | 7 | export default labelLink = (args...) -> () -> new LabelLink(args...) -------------------------------------------------------------------------------- /server/materials/lib/level.coffee: -------------------------------------------------------------------------------- 1 | import MaterialList from "./MaterialList" 2 | 3 | labelToName = 4 | "": "Уровень" 5 | "!en": "Level" 6 | 7 | class Level extends MaterialList 8 | constructor: (id, title, levels) -> 9 | if not levels 10 | levels = title 11 | title = undefined 12 | super(levels) 13 | @title = title 14 | @id = id 15 | 16 | build: (context, order) -> 17 | id = @id?(context.label) || @id 18 | if not @title 19 | @title = "#{labelToName[context.label]} #{id}" 20 | properties = 21 | _id: "#{id}#{context.label}" 22 | type: "level" 23 | title: @title?(context.label) || @title 24 | 25 | material = await super.build(context, order, properties, {keepSubmaterials: true}) 26 | 27 | return material 28 | 29 | export default level = (args...) -> () -> new Level(args...) -------------------------------------------------------------------------------- /server/materials/lib/link.coffee: -------------------------------------------------------------------------------- 1 | class Link 2 | constructor: (@link, @title, @id) -> 3 | 4 | build: (context, order) -> 5 | data = 6 | _id: @id || context.generateId(), 7 | type: "link", 8 | content: @link 9 | title: @title?(context.label) || @title 10 | order: order 11 | 12 | await context.process(data) 13 | return data 14 | 15 | export default link = (args...) -> () -> new Link(args...) -------------------------------------------------------------------------------- /server/materials/lib/main.coffee: -------------------------------------------------------------------------------- 1 | import MaterialList from "./MaterialList" 2 | 3 | class Main extends MaterialList 4 | constructor: (levels) -> 5 | super(levels) 6 | 7 | build: (context, order) -> 8 | properties = 9 | _id: "main#{context.label}" 10 | type: "main" 11 | title: "/" 12 | 13 | material = await super.build(context, order, properties) 14 | 15 | return material 16 | 17 | export default main = (args...) -> () -> new Main(args...) 18 | 19 | -------------------------------------------------------------------------------- /server/materials/lib/news.coffee: -------------------------------------------------------------------------------- 1 | import MaterialList from "./MaterialList" 2 | 3 | labelToName = 4 | "": "Новости" 5 | "!en": "News" 6 | 7 | class News extends MaterialList 8 | constructor: (materials) -> 9 | super(materials) 10 | 11 | build: (context, order) -> 12 | properties = 13 | _id: "news#{context.label}" 14 | type: "news" 15 | title: labelToName[context.label] 16 | 17 | material = await super.build(context, order, properties) 18 | 19 | return material 20 | 21 | export default news = (args...) -> () -> new News(args...) -------------------------------------------------------------------------------- /server/materials/lib/newsItem.coffee: -------------------------------------------------------------------------------- 1 | class NewsItem 2 | constructor: (@title, @content) -> 3 | 4 | build: (context, order) -> 5 | data = 6 | _id: context.generateId(), 7 | type: "newsItem", 8 | title: @title, 9 | content: @content, 10 | order: order 11 | 12 | await context.process(data) 13 | return data 14 | 15 | export default newsItem = (args...) -> () -> new NewsItem(args...) 16 | -------------------------------------------------------------------------------- /server/materials/lib/page.coffee: -------------------------------------------------------------------------------- 1 | export class Page 2 | constructor: (@title, @content, options={}) -> 3 | {@type="page", @skipTree=false, @id} = options 4 | 5 | build: (context, order) -> 6 | data = 7 | _id: if @id then "#{@id}#{context.label}" else context.generateId(), 8 | type: @type, 9 | content: @content?(context.label) || @content 10 | title: @title?(context.label) || @title 11 | order: order 12 | 13 | if @skipTree 14 | data.treeTitle = null 15 | 16 | await context.process(data) 17 | delete data.content 18 | return data 19 | 20 | export default page = (args...) -> () -> new Page(args...) -------------------------------------------------------------------------------- /server/materials/lib/simpleLevel.coffee: -------------------------------------------------------------------------------- 1 | import MaterialList from "./MaterialList" 2 | 3 | class SimpleLevel extends MaterialList 4 | constructor: (id, title, levels) -> 5 | super(levels) 6 | @title = title 7 | @id = id 8 | 9 | build: (context, order) -> 10 | properties = 11 | _id: "#{@id}#{context.label}" 12 | type: "simpleLevel" 13 | title: @title?(context.label) || @title 14 | 15 | material = await super.build(context, order, properties) 16 | 17 | return material 18 | 19 | export default simpleLevel = (args...) -> () -> new SimpleLevel(args...) -------------------------------------------------------------------------------- /server/materials/lib/table.coffee: -------------------------------------------------------------------------------- 1 | import MaterialList from "./MaterialList" 2 | 3 | 4 | getTableLink = (group, table) -> 5 | if table == "byWeek" 6 | return "/solvedByWeek/#{group}" 7 | return "/table/#{group}/#{table}" 8 | 9 | class Table 10 | constructor: (@group, @table, @title, @treeTitle) -> 11 | 12 | build: (context, order) -> 13 | data = 14 | _id: "table:" + @group + ":" + @table + context.label 15 | type: "table" 16 | title: @title 17 | treeTitle: @treeTitle 18 | content: getTableLink(@group, @table) 19 | order: order 20 | 21 | await context.process(data) 22 | 23 | return data 24 | 25 | export default table = (args...) -> () -> new Table(args...) -------------------------------------------------------------------------------- /server/materials/lib/topic.coffee: -------------------------------------------------------------------------------- 1 | import label from './label' 2 | import MaterialList from "./MaterialList" 3 | 4 | class Topic extends MaterialList 5 | constructor: (@title, @contestTitle, materials, @id) -> 6 | super(materials) 7 | 8 | build: (context, order) -> 9 | properties = 10 | _id: if @id then "#{@id}#{context.label}" else context.generateId() 11 | type: "topic" 12 | title: @title?(context.label) || @title 13 | treeTitle: @contestTitle?(context.label) || @contestTitle 14 | 15 | material = await super.build(context, order, properties, {keepSubmaterials: true}) 16 | material.treeTitle = properties.treeTitle 17 | 18 | return material 19 | 20 | export default topic = (args...) -> () -> new Topic(args...) -------------------------------------------------------------------------------- /server/materials/lib/util.coffee: -------------------------------------------------------------------------------- 1 | export ruen = (ru, en) -> 2 | (lbl) -> 3 | if lbl == "" then ru 4 | else if lbl == "!en" then en 5 | else throw "unknown label #{lbl}" 6 | 7 | export levelDtitle = (num) -> 8 | (label) -> 9 | if label == "" then "Дополнительные задачи на разные темы — #{num}" 10 | else if label == "!en" then "Additional miscellaneous problems — #{num}" 11 | else throw "unknown label #{label}" 12 | 13 | export levelDmessage = ruen("

Чтобы перейти на следующий уровень, надо решить минимум треть задач. Когда вы их решите, я рекомендую вам переходить на следующий уровень, чтобы не откладывать изучение новой теории. К оставшимся задачам этого уровня возвращайтесь позже время от времени и постарайтесь со временем все-таки дорешать почти все их до конца.

", 14 | "

To advance to next level, you need to solve at least one third of the problems. When you solve them, I recommend that you move to the next level, so as not to delay the study of new theory. Return to the remaining tasks of this level later from time to time and try to gradually solve almost all of them.

") 15 | 16 | export levelDid = (num) -> 17 | (lbl) -> 18 | if lbl == "" then "#{num}Г" 19 | else if lbl == "!en" then "#{num}D" 20 | -------------------------------------------------------------------------------- /server/metrics/graphite.coffee: -------------------------------------------------------------------------------- 1 | graphite = require('graphite') 2 | import logger from '../log' 3 | 4 | client = graphite.createClient('plaintext://ije.algoprog.ru:2003/') 5 | 6 | instance_number = process.env["INSTANCE_NUMBER"] || "0" 7 | enabled = process.env["GRAPHITE"] || process.env["GRAPHITE_PREFIX"] 8 | PREFIX = process.env["GRAPHITE_PREFIX"] || "algoprog" 9 | 10 | export default send = (metrics) -> 11 | if not enabled 12 | console.log "disabled send metrics ", metrics 13 | return 14 | 15 | metrics["instance"] = +instance_number 16 | 17 | prefix = "#{PREFIX}.#{instance_number}" 18 | metricsWithPrefix = {} 19 | for key, value of metrics 20 | metricsWithPrefix["#{prefix}.#{key}"] = value 21 | try 22 | client.write(metricsWithPrefix, (err) -> if err? then logger.error("Can't send metrics to graphite: #{err}")) 23 | catch e 24 | logger.error("Can't send metrics to graphite: #{e}") 25 | -------------------------------------------------------------------------------- /server/models/AdminAction.ts: -------------------------------------------------------------------------------- 1 | import { Schema, model } from 'mongoose' 2 | 3 | // @ts-ignore 4 | import logger from '../log' 5 | 6 | interface IAction { 7 | action: string, 8 | userList: string, 9 | url: string, 10 | userId: string, 11 | allowed: boolean 12 | date: Date 13 | } 14 | 15 | const actionSchema = new Schema({ 16 | action: String, 17 | userList: String, 18 | url: String, 19 | userId: String, 20 | allowed: Boolean, 21 | date: Date 22 | }) 23 | 24 | actionSchema.methods.upsert = function () { 25 | try { 26 | this.date = new Date() 27 | this.save() 28 | } catch { 29 | logger.info("Could not upsert a action") 30 | } 31 | } 32 | 33 | const AdminAction = model('AdminAction', actionSchema) 34 | 35 | export default AdminAction -------------------------------------------------------------------------------- /server/models/BlogPost.coffee: -------------------------------------------------------------------------------- 1 | mongoose = require('mongoose') 2 | 3 | import logger from '../log' 4 | 5 | blogPostSchema = new mongoose.Schema 6 | _id: String 7 | title: String 8 | link: String 9 | date: Date 10 | 11 | blogPostSchema.methods.upsert = () -> 12 | # https://jira.mongodb.org/browse/SERVER-14322 13 | try 14 | @update(this, {upsert: true}) 15 | catch 16 | logger.info "Could not upsert a material" 17 | 18 | blogPostSchema.statics.findLast = (limit) -> 19 | BlogPost.find().sort({date: -1}).limit(limit) 20 | 21 | 22 | blogPostSchema.index({ date : -1 }) 23 | 24 | BlogPost = mongoose.model('BlogPosts', blogPostSchema); 25 | 26 | export default BlogPost 27 | -------------------------------------------------------------------------------- /server/models/Calendar.coffee: -------------------------------------------------------------------------------- 1 | mongoose = require('mongoose') 2 | 3 | import logger from '../log' 4 | 5 | calendarSchema = new mongoose.Schema 6 | _id: String 7 | byDay: mongoose.Schema.Types.Mixed 8 | 9 | calendarSchema.methods.upsert = () -> 10 | @update(this, {upsert: true, overwrite: true}) 11 | 12 | Calendar = mongoose.model('Calendar', calendarSchema) 13 | 14 | export default Calendar 15 | -------------------------------------------------------------------------------- /server/models/Checkin.coffee: -------------------------------------------------------------------------------- 1 | mongoose = require('mongoose') 2 | 3 | checkinSchema = new mongoose.Schema 4 | user: String 5 | session: Number 6 | checkinTime: Date 7 | deleted: { type: Boolean, default: false } 8 | deletedTime: Date 9 | 10 | checkinSchema.methods.upsert = () -> 11 | # https://jira.mongodb.org/browse/SERVER-14322 12 | try 13 | @checkinTime = new Date() 14 | @update(this, {upsert: true}) 15 | catch 16 | logger.info "Could not upsert a checkin" 17 | 18 | checkinSchema.methods.markDeleted = () -> 19 | @deleted = true 20 | @deletedTime = new Date() 21 | @update(this) 22 | 23 | checkinSchema.statics.findBySession = (session) -> 24 | Checkin.find({ 25 | session: session 26 | deleted: false 27 | }).sort({checkinTime: 1}) 28 | 29 | checkinSchema.statics.findNotDeleted = () -> 30 | Checkin.find 31 | deleted: false 32 | 33 | checkinSchema.statics.findByUser = (user) -> 34 | Checkin.find 35 | user: user 36 | deleted: false 37 | 38 | checkinSchema.index({ deleted: 1, session : 1, checkinTime : 1 }) 39 | checkinSchema.index({ deleted: 1, user : 1 }) 40 | 41 | Checkin = mongoose.model('Checkins', checkinSchema); 42 | 43 | export default Checkin 44 | 45 | export MAX_CHECKIN_PER_SESSION = [18] 46 | -------------------------------------------------------------------------------- /server/models/Config.coffee: -------------------------------------------------------------------------------- 1 | mongoose = require('mongoose') 2 | 3 | configSchema = new mongoose.Schema 4 | _id: String 5 | data: mongoose.Schema.Types.Mixed 6 | 7 | configSchema.methods.upsert = () -> 8 | # https://jira.mongodb.org/browse/SERVER-14322 9 | try 10 | @update(this, {upsert: true}) 11 | catch 12 | logger.info "Could not upsert a material" 13 | 14 | configSchema.statics.set = (id, data) -> 15 | config = new Config 16 | _id: id 17 | data: data 18 | await config.upsert() 19 | 20 | configSchema.statics.get = (id) -> 21 | config = await Config.findById(id) 22 | return config?.toObject?()?.data 23 | 24 | Config = mongoose.model('Configs', configSchema); 25 | 26 | export default Config 27 | -------------------------------------------------------------------------------- /server/models/Hash.coffee: -------------------------------------------------------------------------------- 1 | mongoose = require('mongoose') 2 | 3 | hashSchema = new mongoose.Schema 4 | _id: String 5 | hash: String 6 | submit: String 7 | user: String 8 | problem: String 9 | window: Number 10 | score: Number 11 | 12 | hashSchema.methods.upsert = () -> 13 | # https://jira.mongodb.org/browse/SERVER-14322 14 | try 15 | @update(this, {upsert: true}) 16 | catch 17 | logger.info "Could not upsert a hash" 18 | 19 | hashSchema.statics.findByHashAndNotUser = (hash, user) -> 20 | Hash.find 21 | hash: hash 22 | user: {$ne: user} 23 | 24 | hashSchema.statics.removeForSubmit = (submit) -> 25 | Hash.remove 26 | submit: submit 27 | 28 | hashSchema.index({ hash : 1, user: 1 }) 29 | 30 | Hash = mongoose.model('Hash', hashSchema); 31 | 32 | export default Hash 33 | -------------------------------------------------------------------------------- /server/models/Material.coffee: -------------------------------------------------------------------------------- 1 | mongoose = require('mongoose') 2 | 3 | import logger from '../log' 4 | 5 | materialsSchema = new mongoose.Schema 6 | _id: String 7 | type: String 8 | title: String 9 | content: String 10 | path: [{_id: String, title: String}] 11 | materials: [mongoose.Schema.Types.Mixed] # will always be an array of dictionaries 12 | force: { type: Boolean, default: false } 13 | testSystemData: mongoose.Schema.Types.Mixed 14 | order: String 15 | 16 | 17 | materialsSchema.methods.upsert = () -> 18 | # https://jira.mongodb.org/browse/SERVER-14322 19 | try 20 | @update(this, {upsert: true}) 21 | catch 22 | logger.info "Could not upsert a material" 23 | 24 | materialsSchema.statics.findByType = (type) -> 25 | Material.find 26 | type: type 27 | 28 | Material = mongoose.model('Materials', materialsSchema); 29 | 30 | export default Material 31 | -------------------------------------------------------------------------------- /server/models/Payment.coffee: -------------------------------------------------------------------------------- 1 | mongoose = require('mongoose') 2 | 3 | paymentSchema = new mongoose.Schema 4 | user: String 5 | orderId: String 6 | time: Date 7 | success: Boolean 8 | processed: Boolean 9 | oldPaidTill: Date 10 | newPaidTill: Date 11 | payload: mongoose.Schema.Types.Mixed 12 | receipt: String 13 | 14 | 15 | paymentSchema.methods.upsert = () -> 16 | # https://jira.mongodb.org/browse/SERVER-14322 17 | try 18 | @time = new Date() 19 | @update(this, {upsert: true}) 20 | catch 21 | logger.info "Could not upsert a payment" 22 | 23 | paymentSchema.statics.findLastReceiptByUserId = (userId) -> 24 | return (await Payment.find({user: userId}).sort("-time").limit(1))[0] 25 | 26 | paymentSchema.statics.findSuccessfulByOrderId = (orderId) -> 27 | return Payment.findOne({orderId, success: true}) 28 | 29 | 30 | paymentSchema.index({ user : 1, time: -1 }) 31 | paymentSchema.index({ time : 1 }) 32 | paymentSchema.index({ orderId : 1 }) 33 | 34 | Payment = mongoose.model('Payments', paymentSchema); 35 | 36 | export default Payment 37 | -------------------------------------------------------------------------------- /server/models/SubmitProcess.coffee: -------------------------------------------------------------------------------- 1 | mongoose = require('mongoose') 2 | 3 | import logger from '../log' 4 | 5 | submitProcessSchema = new mongoose.Schema 6 | _id: String 7 | attempts: Number 8 | lastAttempt: Date 9 | 10 | submitProcessSchema.methods.upsert = () -> 11 | # https://jira.mongodb.org/browse/SERVER-14322 12 | try 13 | @update(this, {upsert: true}) 14 | catch 15 | logger.info "Could not upsert a submitProcess" 16 | 17 | 18 | SubmitProcess = mongoose.model('SubmitProcess', submitProcessSchema); 19 | 20 | export default SubmitProcess 21 | -------------------------------------------------------------------------------- /server/models/TableResults.coffee: -------------------------------------------------------------------------------- 1 | mongoose = require('mongoose') 2 | 3 | import logger from '../log' 4 | 5 | TableResultsSchema = new mongoose.Schema 6 | _id: String 7 | user: String 8 | table: String 9 | data: mongoose.Schema.Types.Mixed 10 | 11 | TableResultsSchema.methods.upsert = () -> 12 | @update(this, {upsert: true, overwrite: true}) 13 | 14 | TableResultsSchema.statics.findByUserAndTable = (user, table) -> 15 | TableResults.findOne({user, table}) 16 | 17 | TableResultsSchema.index 18 | user: 1 19 | table: 1 20 | 21 | TableResults = mongoose.model('TableResults', TableResultsSchema) 22 | 23 | export default TableResults 24 | -------------------------------------------------------------------------------- /server/models/UserPrivate.coffee: -------------------------------------------------------------------------------- 1 | mongoose = require('mongoose') 2 | 3 | import logger from '../log' 4 | 5 | usersPrivateSchema = new mongoose.Schema 6 | _id: String, 7 | paidTill: Date, 8 | price: Number, 9 | email: String 10 | 11 | usersPrivateSchema.methods.upsert = () -> 12 | # https://jira.mongodb.org/browse/SERVER-14322 13 | try 14 | console.log "upserting userPrivate", this 15 | @update(this, {upsert: true}) 16 | catch 17 | logger.info "Could not upsert a userPrivate" 18 | 19 | usersPrivateSchema.methods.setPaidTill = (paidTill) -> 20 | logger.info "setting paidTill id ", @_id, paidTill 21 | await @update({$set: {"paidTill": paidTill}}) 22 | @paidTill = paidTill 23 | 24 | usersPrivateSchema.methods.setEmail = (email) -> 25 | logger.info "setting email id ", @_id, email 26 | await @update({$set: {"email": email}}) 27 | @email = email 28 | 29 | usersPrivateSchema.methods.setPrice = (price) -> 30 | logger.info "setting price id ", @_id, price 31 | await @update({$set: {"price": price}}) 32 | @price = price 33 | 34 | UserPrivate = mongoose.model('UsersPrivate', usersPrivateSchema); 35 | 36 | export default UserPrivate 37 | -------------------------------------------------------------------------------- /server/models/cfResult.coffee: -------------------------------------------------------------------------------- 1 | mongoose = require('mongoose') 2 | 3 | cfResultsSchema = new mongoose.Schema 4 | _id: String, 5 | userId: String, 6 | contestId: String, 7 | time: Date, 8 | place: Number, 9 | oldRating: Number, 10 | newRating: Number 11 | 12 | 13 | cfResultsSchema.methods.upsert = -> 14 | @_id = @contestId + "::" + @userId 15 | @update(this, {upsert: true}) 16 | 17 | 18 | cfResultsSchema.statics.findLastResults = (limit) -> 19 | CfResult.find({}).sort({ time: -1, place: 1 }).limit(limit) 20 | 21 | 22 | cfResultsSchema.index 23 | time: -1 24 | place: 1 25 | 26 | 27 | CfResult = mongoose.model('CfResults', cfResultsSchema); 28 | 29 | export default CfResult 30 | -------------------------------------------------------------------------------- /server/models/problem.coffee: -------------------------------------------------------------------------------- 1 | mongoose = require('mongoose') 2 | 3 | import Table from './table' 4 | import logger from '../log' 5 | 6 | problemsSchema = new mongoose.Schema 7 | _id: String 8 | name: String 9 | tables: [String] 10 | level: String 11 | testSystemData: mongoose.Schema.Types.Mixed 12 | order: String 13 | 14 | problemsSchema.methods.upsert = () -> 15 | # https://jira.mongodb.org/browse/SERVER-14322 16 | try 17 | @update(this, {upsert: true}) 18 | catch 19 | logger.info "Could not upsert a problemsSchema" 20 | 21 | problemsSchema.statics.findByLevel = (level) -> 22 | return Problem.find 23 | level: level 24 | 25 | Problem = mongoose.model('Problems', problemsSchema); 26 | 27 | export default Problem 28 | -------------------------------------------------------------------------------- /server/mongo/MongooseCallbackManager.coffee: -------------------------------------------------------------------------------- 1 | scheme2cb = {} 2 | 3 | getRandomString = (length) => 4 | Math.random().toString(36).substring(2, length + 2) 5 | 6 | export mongoCallbacksCount = () -> 7 | cnt = 0 8 | for schemeName of scheme2cb 9 | for user of scheme2cb[schemeName] 10 | for cbKey of scheme2cb[schemeName][user] 11 | cnt++ 12 | return cnt 13 | 14 | export addMongooseCallback = (ws, schemeName, user, cb) -> 15 | cbName = getRandomString(5) 16 | if not scheme2cb[schemeName]? then scheme2cb[schemeName] = {} 17 | if not scheme2cb[schemeName][user]? then scheme2cb[schemeName][user] = {} 18 | scheme2cb[schemeName][user][cbName] = cb 19 | ws.on 'close', -> 20 | delete scheme2cb[schemeName][user][cbName] 21 | cb() 22 | 23 | export runMongooseCallback = (schemeName, user) -> 24 | for k of scheme2cb?[schemeName]?[user] 25 | try 26 | scheme2cb[schemeName][user][k]() 27 | catch e 28 | delete scheme2cb[schemeName][user][k] -------------------------------------------------------------------------------- /server/mongo/mongo.coffee: -------------------------------------------------------------------------------- 1 | mongoose = require('mongoose') 2 | import logger from '../log' 3 | 4 | mongoose.Promise = global.Promise; 5 | 6 | if process.env.MONGO_HOST and process.env.MONGO_USER and process.env.MONGO_PASSWORD 7 | url = "mongodb://#{process.env.MONGO_USER}:#{process.env.MONGO_PASSWORD}@#{process.env.MONGO_HOST}/algoprog" 8 | else if process.env.MONGODB_ADDON_URI 9 | url = process.env.MONGODB_ADDON_URI 10 | else 11 | url =(process.env.MONGODB_URL || 'mongodb://localhost/') + 'algoprog' 12 | 13 | logger.info "Using mongo url #{url}" 14 | 15 | ( () -> 16 | await mongoose.connect(url, {useNewUrlParser: true, useUnifiedTopology:true, useCreateIndex: true }) 17 | )().then(() -> logger.info "Successfully connected to mongo") 18 | .catch((error) -> 19 | logger.error error 20 | process.exit(1) 21 | ) 22 | 23 | export default db = mongoose.connection 24 | -------------------------------------------------------------------------------- /server/passport.coffee: -------------------------------------------------------------------------------- 1 | passport = require('passport') 2 | session = require('express-session') 3 | MongoStore = require('connect-mongo')(session); 4 | import bodyParser from "body-parser" 5 | import cookieParser from "cookie-parser" 6 | 7 | import RegisteredUser from './models/registeredUser' 8 | 9 | passport.use(RegisteredUser.createStrategy()) 10 | 11 | passport.serializeUser(RegisteredUser.serializeUser()) 12 | passport.deserializeUser(RegisteredUser.deserializeUser()) 13 | 14 | export default configure = (app, db) -> 15 | mongoStore = new MongoStore({ mongooseConnection: db }) 16 | 17 | app.use(cookieParser('zdgadf')) 18 | app.use('/api', bodyParser.json()) 19 | app.use(bodyParser.urlencoded({ extended: true })) 20 | app.use(bodyParser.raw({type: 'multipart/form-data'})) 21 | app.use(session({secret: 'zdgadf', store: mongoStore, resave: false, saveUninitialized: false})) 22 | app.use(passport.initialize()) 23 | app.use(passport.session()) 24 | -------------------------------------------------------------------------------- /server/testSystems/TestSystemRegistry.coffee: -------------------------------------------------------------------------------- 1 | import Codeforces from './Codeforces' 2 | import Ejudge from './Ejudge' 3 | import Informatics from './Informatics' 4 | 5 | export REGISTRY = 6 | "informatics": new Informatics() 7 | "ejudge": new Ejudge('https://ejudge.algoprog.ru', 2000), 8 | "codeforces": new Codeforces() 9 | 10 | export default getTestSystem = (id) -> 11 | REGISTRY[id] 12 | -------------------------------------------------------------------------------- /todo.txt: -------------------------------------------------------------------------------- 1 | + Разобраться с получением данных о задаче (чтобы название было английское) в findMistake 2 | + с отправкой ее на проверку в findMistake 3 | + И в списке поиска ошибок тоже 4 | + И в таблице результатов названия контестов 5 | + Статусы сабмитов 6 | + Перенаправление на другую страничку при смене языка 7 | + Названия задач в списке попыток в календаре 8 | + Проверит результаты в дереве и их подписи (и сделать так, чтобы отображались) 9 | + Расчет уровня 10 | + outcomeToText 11 | + названия групп (или показывать только английские группы?..) 12 | + Регистрация + ошибка про "логин уже существует" и неопознанная ошибка 13 | + Переделать работу с уровнями на нормальный parseLevel 14 | + Переделать calculateLevel (возможно, надо уровень везде хранить нормально, а при отображении менять) 15 | + Аналогично в calculateRating 16 | + Редирект с русского уровня на английский 17 | + Проверить ачивки касательно контестов 18 | + Раскраска задач в контесте 19 | + Язык нотификаций 20 | + Картинки на главной 21 | + Проверить fullProblem'ы, в т.ч. hover в таблице результатов 22 | + Корректность markDirty при сабмите и т.п. (и соответственно обновление результатов), и при зачтении/игнорировании 23 | + Удалить requiredProblemsByLevel, levelVersion 24 | + Перевод комментариев по клику 25 | 26 | - Задачи на ДП на графах 27 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "sourceMap": true, 4 | "noEmitOnError": true, 5 | "jsx": "react" 6 | }, 7 | "include": ["**/*.ts", "**/*.tsx"], 8 | "exclude": ["node_modules", "**/*.test.ts"] 9 | } --------------------------------------------------------------------------------