diff --git a/.eslintrc.json b/.eslintrc.json
new file mode 100644
index 000000000..c540d3701
--- /dev/null
+++ b/.eslintrc.json
@@ -0,0 +1,53 @@
+{
+ "ignorePatterns": [
+ "build/**"
+ ],
+ "env": {
+ "node": true,
+ "browser": true,
+ "es2021": true
+ },
+ "extends": [
+ "eslint:recommended"
+ ],
+ "parserOptions": {
+ "ecmaFeatures": {
+ "jsx": true
+ },
+ "ecmaVersion": 12,
+ "sourceType": "module"
+ },
+ "rules": {
+ "indent": [
+ "error",
+ 4
+ ],
+ "linebreak-style": [
+ "error",
+ "unix"
+ ],
+ "quotes": [
+ "error",
+ "double"
+ ],
+ "semi": [
+ "error",
+ "always"
+ ],
+ "eol-last": [
+ "error",
+ "always"
+ ],
+ "no-case-declarations": "off",
+ "object-curly-spacing": [
+ "error",
+ "always"
+ ],
+ "no-unused-vars": [
+ "warn"
+ ],
+ "react/prop-types": [
+ "off"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/.gitattributes b/.gitattributes
index cbdcbbc25..ca3f85b65 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1 +1,2 @@
*.js text eol=lf
+*.dat text eol=crlf
diff --git a/.github/workflows/dokka-gh-pages.yml b/.github/workflows/dokka-gh-pages.yml
new file mode 100644
index 000000000..cc80d1411
--- /dev/null
+++ b/.github/workflows/dokka-gh-pages.yml
@@ -0,0 +1,49 @@
+name: Deploy Dokka with GitHub Pages
+
+on:
+ # Runs on pushes targeting the default branch
+ push:
+ branches: ["main"]
+
+ # Allows you to run this workflow manually from the Actions tab
+ workflow_dispatch:
+
+# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
+# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
+concurrency:
+ group: "pages"
+ cancel-in-progress: false
+
+jobs:
+ # Build job
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Setup Pages
+ uses: actions/configure-pages@v3
+ - name: Build with Dokka
+ uses: gradle/gradle-build-action@v2
+ with:
+ arguments: doc -i
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v2
+
+ # Deployment job
+ deploy:
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: ubuntu-latest
+ needs: build
+ steps:
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v2
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 000000000..8da7ff77c
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,71 @@
+name: Tests
+on:
+ push:
+ branches: [main, master]
+ pull_request:
+ branches: [main, master]
+jobs:
+ test:
+ timeout-minutes: 20
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+
+ - uses: actions/setup-node@v3
+ with:
+ node-version: '16'
+ cache: 'npm'
+ cache-dependency-path: 'src/frontend/package-lock.json'
+
+ - uses: actions/setup-java@master
+ with:
+ distribution: adopt
+ java-version: 11
+
+ - uses: gradle/gradle-build-action@v2.4.2
+ with:
+ arguments: build release --scan -Pnpm.download=false -i
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Store Playwright's Version
+ run: |
+ PLAYWRIGHT_VERSION=$(npm ls @playwright/test | grep @playwright | sed 's/.*@//')
+ echo "Playwright's Version: $PLAYWRIGHT_VERSION"
+ echo "PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION" >> $GITHUB_ENV
+
+ - name: Cache Playwright Browsers for Playwright's Version
+ id: cache-playwright-browsers
+ uses: actions/cache@v3
+ with:
+ path: ~/.cache/ms-playwright
+ key: playwright-browsers-${{ env.PLAYWRIGHT_VERSION }}
+
+ - name: Setup Playwright
+ if: steps.cache-playwright-browsers.outputs.cache-hit != 'true'
+ run: npx playwright install --with-deps
+
+ - name: Run Playwright tests
+ run: npx playwright test 2>&1
+
+ - uses: actions/upload-artifact@v3
+ if: always()
+ with:
+ name: screenshots
+ path: tests/screenshots/
+ retention-days: 3
+
+ - uses: actions/upload-artifact@v3
+ if: always()
+ with:
+ name: playwright-report
+ path: playwright-report/
+ retention-days: 3
+
+ - uses: actions/upload-artifact@v3
+ if: always()
+ with:
+ name: artifacts
+ path: artifacts
+ retention-days: 3
diff --git a/.gitignore b/.gitignore
index 73b51c2f0..5f2af5a40 100644
--- a/.gitignore
+++ b/.gitignore
@@ -355,3 +355,6 @@ gradle-app.setting
.idea
artifacts
+/test-results/
+/playwright-report/
+/playwright/.cache/
diff --git a/.idea/jsonSchemas.xml b/.idea/jsonSchemas.xml
new file mode 100644
index 000000000..c1309bfde
--- /dev/null
+++ b/.idea/jsonSchemas.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 5b4bbba91..3b8cb231e 100644
--- a/README.md
+++ b/README.md
@@ -5,47 +5,34 @@ Welcome to the ICPC Live Source Code Repository.
# Run release version
* Download release from https://github.com/icpc/live-v3/releases
-* Create contest config files
- * [Example for CLICS](https://github.com/icpc/live-v3/tree/main/config/icpc-rmc/2021)
- * [Example for PCMS](https://github.com/icpc/live-v3/tree/main/config/icpc-nef/2021-2022/main)
- * [Example for Codeforces](https://github.com/icpc/live-v3/tree/main/config/vkoshp/2022-junior)
- * [Example for Yandex.Contest](https://github.com/icpc/live-v3/tree/main/config/_examples/_yandex/)
- * [Example for Ejudge](https://github.com/icpc/live-v3/tree/main/config/lscpc/2022/)
- * [See full archive for more examples](https://github.com/icpc/live-v3/tree/main/config)
- * [How to fine tune imported data](https://github.com/icpc/live-v3/blob/main/advanced.json.md)
- * [How to get current state of imported data](http://localhost:8080/api/admin/advancedJsonPreview?fields=all)
-*
-
-Run `java -jar /path/to/jar/file -port=8080 -P:live.configDirectory=/path/to/config/directory -P:live.credsFile=creds.json`
-
-Possible java invocation options are:
-* ```-P:live.configDirectory=config/icpc-nef/2022-2023``` -- path to config directory
-* ```-P:live.credsFile=artifacts/creds.json``` -- path to credentials file
-* ```-P:auth.disabled=true``` -- do not use credentials in admin interface
-* ```-P:live.analyticsTemplatesFile=config/analyticsTemplateRu.json``` -- path to i18n configuration for Analytics and Analytics enable
-* ```-P:live.allowUnsecureConnections=true``` -- allow non-https contest system urls
-* ```-P:live.widgetPositionsFile=config/widget_positions.json.splitscreen``` -- set non-standard widget positions, for example for split screen or fullscreen leaderboard.
-
-
-* Port 8080 is default, if you are okay with it this option can be omitted
-
-* Add source to OBS
+ * You can download [latest dev build](https://github.com/icpc/live-v3/actions/runs/5968512041) instead if you are brave enough
+* Create [contest config files](https://github.com/icpc/live-v3/tree/main/docs/settings.md)
+* (Optional) [Tune](https://github.com/icpc/live-v3/blob/main/docs/advanced.json.md) imported data, so it looks better
+* Run `java -jar /path/to/jar/file -c /path/to/config/directory`
+
+ Check for more options by running `java -jar /path/to/jar/file` without arguments. Here is the couple most useful
+ * ```--creds creds.json``` -- The path to the credential file. It can be used to avoid storing credentials in the main config file.
+ * ```--no-auth``` -- Disable auth in admin interface. It's useful if you are running the overlayer on localhost.
+ * ```-p 8080``` -- 8080 is default port to listen, but it can be changed.
+
+* (Optional) Check [imported contest data](http://localhost:8080/api/admin/advancedJsonPreview?fields=all)
+
+* Add a source to OBS
* +Source
* Browser
* URL http://localhost:8080/overlay?noStatus
* W H 1920x1080
- * OBS Custom css:
-
-```css
-#root > div {
- background: unset;
-}
-```
-
-* Use http://localhost:8080/admin in your browser to control overlay
-
-Also, check emulation mode part of development doc for testing.
-
+ * OBS Custom css:
+ ```css
+ #root > div {
+ background: unset;
+ }
+ ```
+
+* Use [admin interface](http://localhost:8080/admin) in your browser to control overlay
+* Check general broadcast production [schema](https://docs.google.com/document/d/1JcOhmkvbRtG3MLLYUpzVBMqiQOoNpamOz-MvppCgcYk) for other details of typical setup
+* Check [emulation mode](https://github.com/icpc/live-v3/blob/main/docs/emulation.md) part of development doc for testing your setup before the contest started.
+* Check [troubleshooting guide](https://github.com/icpc/live-v3/blob/main/docs/troubleshooting.md) is something looks wrong.
# Authorisation
For now http basic auth is used. If you try to login with
@@ -55,141 +42,22 @@ someone with admin rights confirms, it's okay.
Consider, if you are okay with passing your passwords using plain HTTP.
-If you don't need auth, you can disable it by -P:auth.disabled=true command-line option,
-or corresponding property in config file.
+If you don't need auth, you can disable it by `--no-auth` command-line option.
# Run in development mode
-Requirements:
-
-* gradle
-* jdk
-* node:16
-* browser
-
-Before cloning on Windows configure correct crlf handling
-
-* `git config --global core.autocrlf false`
-* `git config --global core.symlinks true`
-
-## Developing backend
-
-### To test your changes:
-
-1. `live-v3\gradlew :backend:run -Plive.dev.contest=nerc-onsite-2020`
- * Or run one of configurations from IDEA stored in .run
-2. open http://localhost:8080/admin to control overlay
-3. open http://localhost:8080/overlay to view result
-
-### General backend architecture
-
-Backend is implemented in kotlin as [ktor](https://ktor.io/docs/) server.
-
-Admin api endpoints are `/api/admin`. They are using REST-like conventions for naming,
-and mostly implemented in `org.icpclive.admin` package. All data is stored in json-files in
-contest config directory for now.
-
-Overlay api endpoints are `/api/overlay`. They are websockets with updates, read by
-overlay frontend part. Internally, they are implemented
-as [flows](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/)
-from kotlinx.coroutines.
-
-Admin and overlay can be hosted over `/admin` and `/overlay` paths as SPA using ktor builtin
-SPA hosting.
-
-Contest systems integrations are implemented in `org.icpclive.cds` package. Currently,
-CLICS, PCMS, Codeforces and Yandex.Contest, Ejudge and KRSU are supported. Only ICPC mode
-is supported at the moment.
-
-Basically, to add new contest data provider, you need to implement contest information updates
-(start time, list of problems, list of teams, etc.) and runs updates (events like new run, run status changes, partial
-and final testing). In simple cases, if you reload all data every time, it can be useful to inherit from FullReloadContestDataSource.
-
-Everything else should work automatically in the same manner for all CDS sources.
-
-### Emulation mode
-
-If `elmulation.startTime` property is defined, instead of regular updating, cds provider need to download all runs once,
-and
-they would be timely pushed further automatically. This is useful to check everything on already happened contest.
-
-```
-emulation.speed=10
-emulation.startTime=2022-04-03 22:50
-```
-
-Emulation only works if contest is finished.
-
-## Developing frontend
-
-We have two front end packages:
-
-* overlay - webapp that is rendered in OBS (located in `overlay`)
-* admin - admin app for controlling the overlay (located in `admin`)
-
-Install dependencies with `npm ci` in the root path of the project
-(see package.json for more details)
-
-### Running frontend separate from backend
-
-If you are running locally replace `` with `localhost`
-
-#### overlay
-
-Overlay takes base url from environment variable `VITE_WEBSOCKET_URL`
-A path to backend's path for websocket connection.
-Exposed on /api/overlay path
-
-Run this in `overlay` directory to start the development server:
-Linux:
-
-```
-VITE_WEBSOCKET_URL=ws://:8080/api/overlay npm run start
-```
-
-Windows:
-
-```
-set VITE_WEBSOCKET_URL=ws://:8080/api/overlay
-npm run start
-```
-
-#### admin
-
-Admin panel takes two urls:
-
-* `VITE_BACKEND_URL` - for updating data and talking to the backend (exposed in /api/admin)
-* `VITE_WEBSOCKET_URL` - for real time updates of presets and settings (exposed in /api/admin)
-
-Run this in `admin` directory to start the development server:
-Linux:
-
-```
-VITE_BACKEND_URL=http://:8080/api/admin;VITE_WEBSOCKET_URL=ws://:8080/api/admin npm run start
-```
-
-Windows:
-
-```
-set VITE_BACKEND_URL=http://:8080/api/admin
-set VITE_WEBSOCKET_URL=ws://:8080/api/admin
-npm run start
-```
# Previous versions:
* https://github.com/icpc-live
* https://github.com/Aksenov239/icpc-live-v2
-Other repos:
+# Other repos:
-* https://github.com/EgorKulikov/acm_profiles script that collects competitive programming historical data for
+* [Script](https://github.com/EgorKulikov/acm_profiles) that collects competitive programming historical data for
analytical information
-* https://github.com/icpc-live/autoanalyst Autoanalyst
-* https://github.com/pashkal/obs-video-scheduler OBS Video Scheduler Plugin with web interface
-* https://github.com/pmavrin/obs-overlays/tree/master/overlaymaster OBS plugin for shared memory (
- dll https://drive.google.com/file/d/1MvCmhlSpftUFC3N2gj0Lv88-ZV2dtnhP)
-
-for more information email Live@icpc.global
+* [Autoanalyst](https://github.com/icpc-live/autoanalyst)
+* OBS Video Scheduler [Plugin](https://github.com/pashkal/obs-video-scheduler) with web interface
+* Outdated OBS [plugin](https://github.com/pmavrin/obs-overlays/tree/master/overlaymaster) for shared memory ([dll](https://drive.google.com/file/d/1MvCmhlSpftUFC3N2gj0Lv88-ZV2dtnhP))
-General broadcast production schema: https://docs.google.com/document/d/1JcOhmkvbRtG3MLLYUpzVBMqiQOoNpamOz-MvppCgcYk
+For more information, email `live@icpc.global`
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index fe238bedf..6afd1bb3b 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,28 +1,62 @@
+import com.github.jengelman.gradle.plugins.shadow.ShadowJavaPlugin
+import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
plugins {
// versions are set in dependencies block for build.gradle.kts
- java
+ // apply false brings the plugins into the Gradle script classpath (see import above)
alias(libs.plugins.kotlin.jvm) apply false
- alias(libs.plugins.kotlin.serialization) apply false
+ alias(libs.plugins.shadow) apply false
}
+tasks {
+ register("doc") {
+ destinationDir = rootDir.resolve("_site/cds/")
-allprojects {
- tasks {
- withType().all {
- sourceCompatibility = "11"
- targetCompatibility = "11"
- }
- withType().all {
- kotlinOptions {
- jvmTarget = "11"
- kotlinOptions.allWarningsAsErrors = true
+ from(project(":cds").tasks.named("dokkaHtml"))
+ }
+
+ // If you invoke a gen task, :schema-generator:gen will be invoked. It's defined in :schema-generator project
+ // since that project is already aware of global location for schema testing purposes.
+}
+
+subprojects {
+ group = "org.icpclive"
+ version = rootProject.findProperty("build_version")!!
+
+ plugins.withType {
+ configure {
+ toolchain {
+ languageVersion = JavaLanguageVersion.of(11)
}
}
+
+ tasks.named("jar") {
+ archiveClassifier = "just"
+ }
+
+ tasks.named("test") {
+ useJUnitPlatform()
+ }
}
-}
+ // Technically, Ktor pulls this too, but reconfigures...
+ plugins.withType {
+ tasks.register("release") {
+ destinationDir = rootDir.resolve("artifacts/")
+ preserve { include("*") }
+ from(tasks.named("shadowJar"))
+ }
+ tasks.named("shadowJar") {
+ mergeServiceFiles()
-extensions.findByName("buildScan")?.withGroovyBuilder {
- setProperty("termsOfServiceUrl", "https://gradle.com/terms-of-service")
- setProperty("termsOfServiceAgree", "yes")
+ archiveClassifier = null
+ }
+ }
+
+ tasks.withType().configureEach {
+ kotlinOptions {
+ allWarningsAsErrors = true
+ }
+ }
}
\ No newline at end of file
diff --git a/config/_2019-test/events.properties b/config/_2019-test/events.properties
deleted file mode 100644
index 454dbf483..000000000
--- a/config/_2019-test/events.properties
+++ /dev/null
@@ -1,13 +0,0 @@
-login=live
-password=evMUzdqM
-
-url=archive/pcms-test/events-new.xml
-teams.url=archive/pcms-test/participants.xml
-problems.url=archive/pcms-test/problems.xml
-problems.number=6
-
-standings.type=PCMS
-
-running.time=18000000
-freeze.time=18000000
-#freeze.time=14400000
diff --git a/config/_2019-test/mainscreen.properties b/config/_2019-test/mainscreen.properties
deleted file mode 100644
index 953006f79..000000000
--- a/config/_2019-test/mainscreen.properties
+++ /dev/null
@@ -1,82 +0,0 @@
-update.wait=500
-backup.persons=persons.txt
-backup.advertisements=advertisements.txt
-backup.pictures=pictures.txt
-breakingnews.time=20000
-breakingnews.runs.number=10
-breakingnews.patterns.filename=patterns.txt
-standings.blinking.time=10000
-advertisement.time=50000
-person.time=50000
-latency.time=2000
-data.update=1000
-data.host=localhost
-data.port=25675
-
-info.types=screen;camera;video
-info.screen=https://live:evMUzdqM@192.168.1.207/video/desktop/%s
-info.camera=https://live:evMUzdqM@192.168.1.207/video/webcam/%s
-info.record=https://live:evMUzdqM@192.168.1.207:9080/video/reaction/%d
-#info.screen=pics/screen.png
-#info.camera=pics/team.jpg
-#info.record=pics/team.jpg
-#info.types=photo;screen
-info.video=teamVideos/%03d.mp4
-#pics/BigBuckBunny_320x180.mp4
-#pics/team.jpg
-#info.screen=pics/BigBuckBunny_320x180.mp4
-#pics/screen.png
-
-sleep.time=10000
-automated.show.time=20000
-automated.info=screen
-team.double.video=false
-
-ticker.rotate.time=10000
-ticker.logo=#Clock#;#ICPC2018
-ticker.logo.time=5000
-ticker.clock.time=20000
-ticker.logo.change.time=1000
-
-queue.show.verdict=true
-
-overlayed.delay=3000
-
-width=1280
-height=720
-#width=1920
-#height=1080
-
-rate=25
-
-top.teams=S101,S105
-onsite.teams=S.*
-
-stylesheet=stylesheets/wf.jss
-
-polls.backup.file=polls.txt
-poll.show.time=20000
-poll.top.teams=5
-poll.hashtag=#ICPC2019Vote
-
-twitch.chat.server=irc.chat.twitch.tv
-twitch.chat.username=aksenov239
-twitch.chat.password=oauth:8yb7ygy3ey2wdwmlkvd7bs2o8guwf3
-twitch.chat.channel=#aksenov239;#icpclive1;#icpclive_ru
-
-twitter.hashtag=#ICPC2019
-
-word.statistics.backup.file=words-statistics.txt
-word.statistics.words=tweets;goose;energy
-word.statistics.tweets.text=$tweets$
-word.statistics.tweets.picture=
-word.statistics.goose.text=(*)>
-word.statistics.goose.picture=pics/goose.jpg
-word.statistics.energy.text=-- ? Ѝ_Ѝ -?
-word.statistics.energy.picture=pics/energy.jpg
-word.statistics.word.show.time=10000
-
-backup.pictures=pictures.txt
-
-output.mode=window
-#outputFile=d:/work/image.bin
diff --git a/config/_2019-test/splitscreen.properties b/config/_2019-test/splitscreen.properties
deleted file mode 100644
index f9ffcef2d..000000000
--- a/config/_2019-test/splitscreen.properties
+++ /dev/null
@@ -1,17 +0,0 @@
-sleep.time=20000
-update.wait=1000
-
-switch.time=20000
-relevance.time=600000
-top.places=20
-replay.time=20000
-#choose at least 9 teams
-setup=1,2,3,4
-
-width=1920
-height=1080
-rate=25
-
-main.hashtag=#ICPC2019
-account.wait.time=60000
-votes.to.show=3
\ No newline at end of file
diff --git a/config/__sample/events.properties b/config/__sample/events.properties
deleted file mode 100644
index 05df745f1..000000000
--- a/config/__sample/events.properties
+++ /dev/null
@@ -1,18 +0,0 @@
-login=live
-password=live7218
-
-url=archive/2018-test
-#problems.url=archive/2016/problem.json
-#teams.url=archive/2016/teams.json
-
-emulation.startTime=180
-emulation.speed=10
-
-#url=https://192.168.1.207:9443/events
-#problems.url=https://192.168.1.207:9443/contest/problem
-#teams.url=https://192.168.1.207:9443/contest/team
-
-problemsNumber=13
-standings.type=WF
-
-#regions.mapping={"11738":"North America", "11735":"Europe", "11744":"Latin America", "11737":"Africa and the Middle East", "11743":"South Pacific", "11742":"Asia"}
\ No newline at end of file
diff --git a/config/__sample/mainscreen.properties b/config/__sample/mainscreen.properties
deleted file mode 100644
index 315e85e99..000000000
--- a/config/__sample/mainscreen.properties
+++ /dev/null
@@ -1,75 +0,0 @@
-width=1920
-height=1080
-rate=25
-output.file=c:/work/image.bin
-output.mode=file
-#output.mode=window
-
-update.wait=500
-backup.persons=persons.txt
-backup.advertisements=advertisements.txt
-breakingnews.time=20000
-breakingnews.runs.number=10
-breakingnews.patterns.filename=patterns.txt
-standings.blinking.time=10000
-advertisement.time=50000
-person.time=50000
-latency.time=2000
-data.update=1000
-data.host=localhost
-data.port=25675
-
-info.types=screen;camera;video
-info.screen=http://192.168.1.207:9080/video/screen/%d
-info.camera=http://192.168.1.207:9080/video/camera/%d
-info.record=http://192.168.1.207:9080/video/reaction/%d
-#info.screen=pics/screen.png
-#info.camera=pics/team.jpg
-#info.record=pics/team.jpg
-#info.types=photo;screen
-info.video=teamVideos/%03d.mp4
-#pics/BigBuckBunny_320x180.mp4
-#pics/team.jpg
-#info.screen=pics/BigBuckBunny_320x180.mp4
-#pics/screen.png
-
-sleep.time=10000
-automated.show.time=20000
-automated.info=screen
-team.double.video=false
-
-ticker.rotate.time=10000
-ticker.logo=#Clock#;#ICPC2017
-ticker.logo.time=5000
-ticker.clock.time=20000
-ticker.logo.change.time=1000
-
-queue.show.verdict=true
-
-overlayed.delay=3000
-
-top.teams=76,53
-onsite.teams=.*
-
-stylesheet=stylesheets/wf.jss
-
-polls.backup.file=polls.txt
-poll.show.time=20000
-poll.top.teams=5
-
-twitch.chat.server=irc.chat.twitch.tv
-twitch.chat.username=aksenov239
-twitch.chat.password=oauth:8yb7ygy3ey2wdwmlkvd7bs2o8guwf3
-twitch.chat.channel=#aksenov239;#icpclive1;#icpclive_ru
-
-twitter.hashtag=#ICPC2017
-
-word.statistics.backup.file=words-statistics.txt
-word.statistics.words=tweets;goose;energy
-word.statistics.tweets.text=$tweets$
-word.statistics.tweets.picture=
-word.statistics.goose.text=(*)>
-word.statistics.goose.picture=pics/goose.jpg
-word.statistics.energy.text=ί-- ??φ Π?_Π? ί-ι??φ
-word.statistics.energy.picture=pics/energy.jpg
-word.statistics.word.show.time=10000
diff --git a/config/__sample/splitscreen.properties b/config/__sample/splitscreen.properties
deleted file mode 100644
index 43537c6a5..000000000
--- a/config/__sample/splitscreen.properties
+++ /dev/null
@@ -1,17 +0,0 @@
-sleep.time=3000
-update.wait=1000
-
-switch.time=20000
-relevance.time=60000
-top.places=12
-replay.time=20000
-#choose at least 9 teams
-setup=1,2,3,4,5,6,7,8,9
-
-width=1280
-height=720
-rate=25
-
-main.hashtag=#ICPC2018
-votes.to.show=5
-
diff --git a/config/fed/2023-voronezh/events.properties b/config/__tests/ejudge_icpc_unfreeze/2023-voronezh/events.properties
similarity index 100%
rename from config/fed/2023-voronezh/events.properties
rename to config/__tests/ejudge_icpc_unfreeze/2023-voronezh/events.properties
diff --git a/config/regionalroi/lpk-2021-d1/events.properties b/config/__tests/ejudge_ioi/regionalroi-lpk-2021-d1/events.properties
similarity index 75%
rename from config/regionalroi/lpk-2021-d1/events.properties
rename to config/__tests/ejudge_ioi/regionalroi-lpk-2021-d1/events.properties
index 2958fe36c..028faa7d0 100644
--- a/config/regionalroi/lpk-2021-d1/events.properties
+++ b/config/__tests/ejudge_ioi/regionalroi-lpk-2021-d1/events.properties
@@ -1,3 +1,3 @@
standings.type=EJUDGE
-standings.resultType=IOI
+standings.resultType=ioi
url=https://ejudge.strategy48.ru/regional-2021-d1.xml
\ No newline at end of file
diff --git a/config/__tests/ejudge_ioi_virtual/mosh-2023-keldysh/advanced.json b/config/__tests/ejudge_ioi_virtual/mosh-2023-keldysh/advanced.json
new file mode 100644
index 000000000..fdf1747e6
--- /dev/null
+++ b/config/__tests/ejudge_ioi_virtual/mosh-2023-keldysh/advanced.json
@@ -0,0 +1,924 @@
+{
+ "teamOverrides": {
+ "143769": {
+ "shortname": "Абраров Нияз, 7, Уфа"
+ },
+ "143770": {
+ "shortname": "Алахвердиева Камилла, 7, Лен. область"
+ },
+ "143771": {
+ "shortname": "Александров Даниил, 7, Якутск"
+ },
+ "143772": {
+ "shortname": "Александров Николай, 8, Якутск"
+ },
+ "143773": {
+ "shortname": "Аллаяров Аскар, 7, Уфа"
+ },
+ "143774": {
+ "shortname": "Ангелов Артур, 8, Лен. область"
+ },
+ "143775": {
+ "shortname": "Антонов Александр, 7, Якутск"
+ },
+ "143776": {
+ "shortname": "Анчуков Дмитрий, 7, Вологда"
+ },
+ "143777": {
+ "shortname": "Арапов Рамир, 8, Уфа"
+ },
+ "143778": {
+ "shortname": "Артемьев Егор, 8, Якутск"
+ },
+ "143779": {
+ "shortname": "Арутюнов Давид, 5, Владикавказ"
+ },
+ "143780": {
+ "shortname": "Архипова Арина, 7, Саранск"
+ },
+ "143781": {
+ "shortname": "Атаев Артур, 7, Ухта"
+ },
+ "143782": {
+ "shortname": "Атаев Семён, 8, Владикавказ"
+ },
+ "143783": {
+ "shortname": "Афанасьева Мария, 8, Вологда"
+ },
+ "143784": {
+ "shortname": "Афонин Евгений, 7, Вологда"
+ },
+ "143785": {
+ "shortname": "Бабич Кирилл, 8, Вологда"
+ },
+ "143786": {
+ "shortname": "Бабушкин Дмитрий, 8, Пермь"
+ },
+ "143787": {
+ "shortname": "Баранцев Михаил, 8, Ульяновск"
+ },
+ "143788": {
+ "shortname": "Батырев Иван, 8, Ульяновск"
+ },
+ "143789": {
+ "shortname": "Батяева Ангелина, 8, Владикавказ"
+ },
+ "143790": {
+ "shortname": "Бахарев Кирилл, 7, Вологда"
+ },
+ "143791": {
+ "shortname": "Бацарова Елизавета, 6, Ульяновск"
+ },
+ "143792": {
+ "shortname": "Безклубный Никита, 8, Лен. область"
+ },
+ "143793": {
+ "shortname": "Безрукова Анастасия, 8, Вологда"
+ },
+ "143794": {
+ "shortname": "Бектеев Михаил, 8, Ульяновск"
+ },
+ "143795": {
+ "shortname": "Белозеров Артём, 8, Вологда"
+ },
+ "143796": {
+ "shortname": "Березин Александр, 8, Вологда"
+ },
+ "143797": {
+ "shortname": "Бечканов Ренат, 8, Нальчик"
+ },
+ "143798": {
+ "shortname": "Богданов Егор, 8, Уфа"
+ },
+ "143799": {
+ "shortname": "Бочкарева Ольга, 8, Вологда"
+ },
+ "143800": {
+ "shortname": "Брага Арсений, 8, Омск"
+ },
+ "143801": {
+ "shortname": "Бугрин Эмир, 7, Владикавказ"
+ },
+ "143802": {
+ "shortname": "Ваничев Илья, 7, Лен. область"
+ },
+ "143803": {
+ "shortname": "Васенин Матвей, 7, Лен. область"
+ },
+ "143804": {
+ "shortname": "Васильев Богдан, 8, Вологда"
+ },
+ "143805": {
+ "shortname": "Верин Иван, 8, Мос. область"
+ },
+ "143806": {
+ "shortname": "Винокурова Светлана, 8, Якутск"
+ },
+ "143807": {
+ "shortname": "Власов Артём, 7, Вологда"
+ },
+ "143808": {
+ "shortname": "Воробьева Яна, 8, Лен. область"
+ },
+ "143809": {
+ "shortname": "Воробьева Яна, 8, Лен. область"
+ },
+ "143810": {
+ "shortname": "Гагарин Ярослав, 7, Якутск"
+ },
+ "143811": {
+ "shortname": "Газюмова Милана, 8, Владикавказ"
+ },
+ "143812": {
+ "shortname": "Газюмова Яна, 8, Владикавказ"
+ },
+ "143813": {
+ "shortname": "Галеев Арсен, 7, Уфа"
+ },
+ "143814": {
+ "shortname": "Герасимович Валерий, 8, Вологда"
+ },
+ "143815": {
+ "shortname": "Гиниятов Динислам, 6, Уфа"
+ },
+ "143816": {
+ "shortname": "Глисанов Александр, 8, Псков"
+ },
+ "143817": {
+ "shortname": "Глущенко Александр, 7, Лен. область"
+ },
+ "143818": {
+ "shortname": "Головина Анна, 7, Ульяновск"
+ },
+ "143819": {
+ "shortname": "Горшков Кирилл, 7, Ульяновск"
+ },
+ "143820": {
+ "shortname": "Громова Дарья, 8, Вологда"
+ },
+ "143821": {
+ "shortname": "Грошев Олег, 8, Уфа"
+ },
+ "143822": {
+ "shortname": "Гусев Арсений, 7, Вологда"
+ },
+ "143823": {
+ "shortname": "Гуськова Диана, 5, Ульяновск"
+ },
+ "143824": {
+ "shortname": "Давлетбаков Артур, 6, Уфа"
+ },
+ "143825": {
+ "shortname": "Давлетханов Шамиль, 8, Уфа"
+ },
+ "143826": {
+ "shortname": "Данилов Михаил, 8, Ульяновск"
+ },
+ "143827": {
+ "shortname": "Дементьев Максим, 6, Ульяновск"
+ },
+ "143828": {
+ "shortname": "Дергачев Василий, 7, Лен. область"
+ },
+ "143829": {
+ "shortname": "Дзиов Марат, 8, Владикавказ"
+ },
+ "143830": {
+ "shortname": "Домрачева Дарья, 8, Пермь"
+ },
+ "143831": {
+ "shortname": "Доронин Денис, 7, Ульяновск"
+ },
+ "143832": {
+ "shortname": "Доронин Илья, 5, Ульяновск"
+ },
+ "143833": {
+ "shortname": "Доткулов Инал, 8, Нальчик"
+ },
+ "143834": {
+ "shortname": "Душанбаев Ильдар, 7, Уфа"
+ },
+ "143835": {
+ "shortname": "Еланский Максим, 8, Владикавказ"
+ },
+ "143836": {
+ "shortname": "Елизаров Василий, 6, Якутск"
+ },
+ "143837": {
+ "shortname": "Еловикова Татьяна, 7, Лен. область"
+ },
+ "143838": {
+ "shortname": "Елфимов Илья, 8, Лен. область"
+ },
+ "143839": {
+ "shortname": "Ефремов Арсений, 7, Лен. область"
+ },
+ "143840": {
+ "shortname": "Зацепилина Елизавета, 7, Вологда"
+ },
+ "143841": {
+ "shortname": "Зацепина Анастасия, 7, Липецк"
+ },
+ "143842": {
+ "shortname": "Зубаиров Искандер, 6, Уфа"
+ },
+ "143843": {
+ "shortname": "Иванов Александр, 8, Лен. область"
+ },
+ "143844": {
+ "shortname": "Иванов Саян, 7, Якутск"
+ },
+ "143845": {
+ "shortname": "Имангулов Самир, 7, Ульяновск"
+ },
+ "143846": {
+ "shortname": "Исаев Александр, 8, Ульяновск"
+ },
+ "143847": {
+ "shortname": "Калачев Павел, 8, Вологда"
+ },
+ "143848": {
+ "shortname": "Калов Самир, 7, Нальчик"
+ },
+ "143849": {
+ "shortname": "Калугин Александр, 8, Пермь"
+ },
+ "143850": {
+ "shortname": "Кальянов Алексей, 8, Псков"
+ },
+ "143851": {
+ "shortname": "Камалдинов Айрат, 6, Ульяновск"
+ },
+ "143852": {
+ "shortname": "Камалов Айдар, 7, Уфа"
+ },
+ "143853": {
+ "shortname": "Камболов Дзамболат, 7, Владикавказ"
+ },
+ "143854": {
+ "shortname": "Карташов Григорий, 8, Вологда"
+ },
+ "143855": {
+ "shortname": "Киляров Асланбек, 7, Нальчик"
+ },
+ "143856": {
+ "shortname": "Ким Яна, 8, Улан-Удэ"
+ },
+ "143857": {
+ "shortname": "Кирносов Константин, 7, Лен. область"
+ },
+ "143858": {
+ "shortname": "Киселев Андрей, 8, Лен. область"
+ },
+ "143859": {
+ "shortname": "Китаев Андрей, 5, Ульяновск"
+ },
+ "143860": {
+ "shortname": "Колосов Владислав, 8, Лен. область"
+ },
+ "143861": {
+ "shortname": "Колосов Владислав, 8, Лен. область"
+ },
+ "143862": {
+ "shortname": "Кольцов Богдан, 8, Лен. область"
+ },
+ "143863": {
+ "shortname": "Кондрашин Максим, 7, Липецк"
+ },
+ "143864": {
+ "shortname": "Кондуков Никита, 8, Вологда"
+ },
+ "143865": {
+ "shortname": "Корякин Виктор, 8, Якутск"
+ },
+ "143866": {
+ "shortname": "Костин Александр, 6, Ульяновск"
+ },
+ "143867": {
+ "shortname": "Коцоев Руслан, 8, Владикавказ"
+ },
+ "143868": {
+ "shortname": "Крышень Владимир, 7, Лен. область"
+ },
+ "143869": {
+ "shortname": "Куваев Кирилл, 7, Вологда"
+ },
+ "143870": {
+ "shortname": "Куварин Илья, 7, Ульяновск"
+ },
+ "143871": {
+ "shortname": "Кузнецов Александр, 8, Саранск"
+ },
+ "143872": {
+ "shortname": "Кузнецов Вадим, 8, Вологда (Единство)"
+ },
+ "143873": {
+ "shortname": "Кузнецов Иван, 7, Лен. область"
+ },
+ "143874": {
+ "shortname": "Кулагин Богдан, 7, Ульяновск"
+ },
+ "143875": {
+ "shortname": "Курзин Игорь, 6, Ульяновск"
+ },
+ "143876": {
+ "shortname": "Лавриненко Егор, 8, Якутск"
+ },
+ "143877": {
+ "shortname": "Лазуткин Дмитрий, 10, Мос. область"
+ },
+ "143878": {
+ "shortname": "Логинов Кирилл, 7, Саранск"
+ },
+ "143879": {
+ "shortname": "Майоров Артур, 8, Ухта"
+ },
+ "143880": {
+ "shortname": "Малышев Никита, 8, Вологда"
+ },
+ "143881": {
+ "shortname": "Малышева Полина, 8, Омск"
+ },
+ "143882": {
+ "shortname": "Малькова Софья, 8, Саранск"
+ },
+ "143883": {
+ "shortname": "Мамсуров Абисал, 7, Владикавказ"
+ },
+ "143884": {
+ "shortname": "Марченко Максим, 7, Владикавказ"
+ },
+ "143885": {
+ "shortname": "Матвеенков Игорь, 8, Лен. область"
+ },
+ "143886": {
+ "shortname": "Меньщиков Егор, 5, Псков"
+ },
+ "143887": {
+ "shortname": "Митусов Богдан, 7, Лен. область"
+ },
+ "143888": {
+ "shortname": "Молчанов Матвей, 8, Лен. область"
+ },
+ "143889": {
+ "shortname": "Монахов Никита, 8, Вологда (Единство)"
+ },
+ "143890": {
+ "shortname": "Надыкто Илья, 7, Омск"
+ },
+ "143891": {
+ "shortname": "Назаров Михаил, 8, Лен. область"
+ },
+ "143892": {
+ "shortname": "Неграшев Денис, 7, Якутск"
+ },
+ "143893": {
+ "shortname": "Никишин Иван, 6, Пермь"
+ },
+ "143894": {
+ "shortname": "Николаев Артём, 7, Вологда"
+ },
+ "143895": {
+ "shortname": "Новиков Михаил, 8, Лен. область"
+ },
+ "143896": {
+ "shortname": "Ноговицын Дьулустаан, 8, Якутск"
+ },
+ "143897": {
+ "shortname": "Няшин Алексей, 6, Пермь"
+ },
+ "143898": {
+ "shortname": "Овчинников Дмитрий, 8, Вологда (Единство)"
+ },
+ "143899": {
+ "shortname": "Окулов Дмитрий, 8, Вологда"
+ },
+ "143900": {
+ "shortname": "Окулов Дмитрий, 8, Вологда (Единство)"
+ },
+ "143901": {
+ "shortname": "Олейников Егор, 6, Вологда"
+ },
+ "143902": {
+ "shortname": "Осокин Никита, 7, Пермь"
+ },
+ "143903": {
+ "shortname": "Павлов Арсений, 6, Ульяновск"
+ },
+ "143904": {
+ "shortname": "Панюгин Дмитрий, 8, Саранск"
+ },
+ "143905": {
+ "shortname": "Парпиева Ольга, 6, Вологда"
+ },
+ "143906": {
+ "shortname": "Паршин Павел, 6, Ульяновск"
+ },
+ "143907": {
+ "shortname": "Пахомова Ольга, 5, Ульяновск"
+ },
+ "143908": {
+ "shortname": "Песцов Захар, 8, Саранск"
+ },
+ "143909": {
+ "shortname": "Петров Артем, 8, Якутск"
+ },
+ "143910": {
+ "shortname": "Петров Матвей, 8, Лен. область"
+ },
+ "143911": {
+ "shortname": "Петрова Елизавета, 8, Ухта"
+ },
+ "143912": {
+ "shortname": "Петухова Анастасия, 8, Лен. область"
+ },
+ "143913": {
+ "shortname": "Пилипенко Леонид, 8, Вологда"
+ },
+ "143914": {
+ "shortname": "Платонов Алексей, 7, Лен. область"
+ },
+ "143915": {
+ "shortname": "Покатилов Фёдор, 8, Лен. область"
+ },
+ "143916": {
+ "shortname": "Полторабатько Роман, 7, Лен. область"
+ },
+ "143917": {
+ "shortname": "Попов Максим, 8, Пермь"
+ },
+ "143918": {
+ "shortname": "Потапов Кирилл, 6, Якутск"
+ },
+ "143919": {
+ "shortname": "Прокопенко Герман, 7, Лен. область"
+ },
+ "143920": {
+ "shortname": "Прокопьев Гаврил, 8, Якутск"
+ },
+ "143921": {
+ "shortname": "Пулова Христина, 8, Саранск"
+ },
+ "143922": {
+ "shortname": "Романов Даниил, 5, Омск"
+ },
+ "143923": {
+ "shortname": "Руднев Костя, 8, Владикавказ"
+ },
+ "143924": {
+ "shortname": "Румянцев Андрей, 8, Вологда"
+ },
+ "143925": {
+ "shortname": "Рымарь Екатерина, 7, Омск"
+ },
+ "143926": {
+ "shortname": "Рябов Михаил, 7, Ульяновск"
+ },
+ "143927": {
+ "shortname": "Сабанов Виктор, 8, Владикавказ"
+ },
+ "143928": {
+ "shortname": "Сабанова Лана, 7, Владикавказ"
+ },
+ "143929": {
+ "shortname": "Сабанчиев Магомед, 7, Нальчик"
+ },
+ "143930": {
+ "shortname": "Сабеев Ацамаз, 8, Владикавказ"
+ },
+ "143931": {
+ "shortname": "Самигулин Андрей, 8, Ульяновск"
+ },
+ "143932": {
+ "shortname": "Сауткин Алексей, 8, Пермь"
+ },
+ "143933": {
+ "shortname": "Семëнов Матвей, 7, Ульяновск"
+ },
+ "143934": {
+ "shortname": "Сергеев Мирослав, 8, Мос. область"
+ },
+ "143935": {
+ "shortname": "Симендеев Константин, 8, Ульяновск"
+ },
+ "143936": {
+ "shortname": "Скутин Александр, 8, Ухта"
+ },
+ "143937": {
+ "shortname": "Смирнов Егор, 8, Вологда"
+ },
+ "143938": {
+ "shortname": "Сорокин Юрий, 8, Ульяновск"
+ },
+ "143939": {
+ "shortname": "Старостин Матвей, 8, Вологда"
+ },
+ "143940": {
+ "shortname": "Степанов Аюр, 6, Улан-Удэ"
+ },
+ "143941": {
+ "shortname": "Степанов Дмитрий, 7, Ульяновск"
+ },
+ "143942": {
+ "shortname": "Султангулов Батыр, 8, Уфа"
+ },
+ "143943": {
+ "shortname": "Супрун Иван, 6, Псков"
+ },
+ "143944": {
+ "shortname": "Сыченов Артём, 7, Вологда"
+ },
+ "143945": {
+ "shortname": "Тагиров Керим, 7, Владикавказ"
+ },
+ "143946": {
+ "shortname": "Тансыккужин Линар, 8, Уфа"
+ },
+ "143947": {
+ "shortname": "Темираев Сергей, 7, Владикавказ"
+ },
+ "143948": {
+ "shortname": "Темиров Георгий, 7, Владикавказ"
+ },
+ "143949": {
+ "shortname": "Типикин Артур, 5, Ульяновск"
+ },
+ "143950": {
+ "shortname": "Тихонова Кира, 5, Ульяновск"
+ },
+ "143951": {
+ "shortname": "Тишков Инал, 8, Нальчик"
+ },
+ "143952": {
+ "shortname": "Токарь Артём, 8, Ульяновск"
+ },
+ "143953": {
+ "shortname": "Туснин Александр, 6, Ульяновск"
+ },
+ "143954": {
+ "shortname": "Удовиченко Владимир, 8, Лен. область"
+ },
+ "143955": {
+ "shortname": "Федоренко София, 7, Нальчик"
+ },
+ "143956": {
+ "shortname": "Федотов Егор, 7, Ульяновск"
+ },
+ "143957": {
+ "shortname": "Фролов Прохор, 8, Ульяновск"
+ },
+ "143958": {
+ "shortname": "Хайдаров Максим, 6, Ульяновск"
+ },
+ "143959": {
+ "shortname": "Халикшина Алина, 7, Пермь"
+ },
+ "143960": {
+ "shortname": "Халикшина Ульяна, 7, Пермь"
+ },
+ "143961": {
+ "shortname": "Хандрыкин Артур, 8, Лен. область"
+ },
+ "143962": {
+ "shortname": "Харламов Максим, 8, Вологда"
+ },
+ "143963": {
+ "shortname": "Хрусталёв Егор, 6, Ульяновск"
+ },
+ "143964": {
+ "shortname": "Царев Андрей, 8, Вологда"
+ },
+ "143965": {
+ "shortname": "Цориева Ева, 8, Владикавказ"
+ },
+ "143966": {
+ "shortname": "Чавкин Илья, 6, Ульяновск"
+ },
+ "143967": {
+ "shortname": "Чашинова Алёна, 8, Вологда"
+ },
+ "143968": {
+ "shortname": "Чепелин Дмитрий, 7, Лен. область"
+ },
+ "143969": {
+ "shortname": "Черепанова Алина, 8, Вологда"
+ },
+ "143970": {
+ "shortname": "Четвертной Илья, 7, Псков"
+ },
+ "143971": {
+ "shortname": "Чиранов Александр, 8, Саранск"
+ },
+ "143972": {
+ "shortname": "Шайбеков Артем, 8, Ухта"
+ },
+ "143973": {
+ "shortname": "Шевченко Дарья, 8, Вологда"
+ },
+ "143974": {
+ "shortname": "Шейкин Дмитрий, 7, Ульяновск"
+ },
+ "143975": {
+ "shortname": "Шестакова Мария, 8, Вологда"
+ },
+ "143976": {
+ "shortname": "Шилов Дмитрий, 7, Мос. область"
+ },
+ "143977": {
+ "shortname": "Шириков Дмитрий, 8, Вологда"
+ },
+ "143978": {
+ "shortname": "Шириков Дмитрий, 8, Вологда"
+ },
+ "143979": {
+ "shortname": "Ширыханов Роман, 6, Пермь"
+ },
+ "143980": {
+ "shortname": "Ширяев Иван, 7, Вологда"
+ },
+ "143981": {
+ "shortname": "Шурыгина Мария, 8, Ульяновск"
+ },
+ "143982": {
+ "shortname": "Юмшанов Эрчим, 8, Якутск"
+ },
+ "143983": {
+ "shortname": "Явтушенко Максим, 5, Ульяновск"
+ },
+ "143984": {
+ "shortname": "Якуничева Мария, 8, Вологда"
+ },
+ "143985": {
+ "shortname": "Боброва Арина, 6, Ульяновск"
+ },
+ "143986": {
+ "shortname": "mosolymp-2023-1218"
+ },
+ "143987": {
+ "shortname": "mosolymp-2023-1219"
+ },
+ "143988": {
+ "shortname": "mosolymp-2023-1220"
+ },
+ "143989": {
+ "shortname": "mosolymp-2023-1221"
+ },
+ "143990": {
+ "shortname": "mosolymp-2023-1222"
+ },
+ "143991": {
+ "shortname": "mosolymp-2023-1223"
+ },
+ "143992": {
+ "shortname": "mosolymp-2023-1224"
+ },
+ "143993": {
+ "shortname": "mosolymp-2023-1225"
+ },
+ "143994": {
+ "shortname": "mosolymp-2023-1226"
+ },
+ "143995": {
+ "shortname": "mosolymp-2023-1227"
+ },
+ "143996": {
+ "shortname": "mosolymp-2023-1228"
+ },
+ "143997": {
+ "shortname": "mosolymp-2023-1229"
+ },
+ "143998": {
+ "shortname": "mosolymp-2023-1230"
+ },
+ "143999": {
+ "shortname": "mosolymp-2023-1231"
+ },
+ "144000": {
+ "shortname": "mosolymp-2023-1232"
+ },
+ "144001": {
+ "shortname": "mosolymp-2023-1233"
+ },
+ "144002": {
+ "shortname": "mosolymp-2023-1234"
+ },
+ "144003": {
+ "shortname": "mosolymp-2023-1235"
+ },
+ "144004": {
+ "shortname": "mosolymp-2023-1236"
+ },
+ "144005": {
+ "shortname": "mosolymp-2023-1237"
+ },
+ "144006": {
+ "shortname": "mosolymp-2023-1238"
+ },
+ "144007": {
+ "shortname": "mosolymp-2023-1239"
+ },
+ "144008": {
+ "shortname": "mosolymp-2023-1240"
+ },
+ "144009": {
+ "shortname": "mosolymp-2023-1241"
+ },
+ "144010": {
+ "shortname": "mosolymp-2023-1242"
+ },
+ "144011": {
+ "shortname": "mosolymp-2023-1243"
+ },
+ "144012": {
+ "shortname": "mosolymp-2023-1244"
+ },
+ "144013": {
+ "shortname": "mosolymp-2023-1245"
+ },
+ "144014": {
+ "shortname": "mosolymp-2023-1246"
+ },
+ "144015": {
+ "shortname": "mosolymp-2023-1247"
+ },
+ "144016": {
+ "shortname": "mosolymp-2023-1248"
+ },
+ "144017": {
+ "shortname": "mosolymp-2023-1249"
+ },
+ "144018": {
+ "shortname": "mosolymp-2023-1250"
+ },
+ "144019": {
+ "shortname": "mosolymp-2023-1251"
+ },
+ "144020": {
+ "shortname": "mosolymp-2023-1252"
+ },
+ "144021": {
+ "shortname": "mosolymp-2023-1253"
+ },
+ "144022": {
+ "shortname": "mosolymp-2023-1254"
+ },
+ "144023": {
+ "shortname": "mosolymp-2023-1255"
+ },
+ "144024": {
+ "shortname": "mosolymp-2023-1256"
+ },
+ "144025": {
+ "shortname": "mosolymp-2023-1257"
+ },
+ "144026": {
+ "shortname": "mosolymp-2023-1258"
+ },
+ "144027": {
+ "shortname": "mosolymp-2023-1259"
+ },
+ "144028": {
+ "shortname": "mosolymp-2023-1260"
+ },
+ "144029": {
+ "shortname": "mosolymp-2023-1261"
+ },
+ "144030": {
+ "shortname": "mosolymp-2023-1262"
+ },
+ "144031": {
+ "shortname": "mosolymp-2023-1263"
+ },
+ "144032": {
+ "shortname": "mosolymp-2023-1264"
+ },
+ "144033": {
+ "shortname": "mosolymp-2023-1265"
+ },
+ "144034": {
+ "shortname": "mosolymp-2023-1266"
+ },
+ "144035": {
+ "shortname": "mosolymp-2023-1267"
+ },
+ "144036": {
+ "shortname": "mosolymp-2023-1268"
+ },
+ "144037": {
+ "shortname": "mosolymp-2023-1269"
+ },
+ "144038": {
+ "shortname": "mosolymp-2023-1270"
+ },
+ "144039": {
+ "shortname": "mosolymp-2023-1271"
+ },
+ "144040": {
+ "shortname": "mosolymp-2023-1272"
+ },
+ "144041": {
+ "shortname": "mosolymp-2023-1273"
+ },
+ "144042": {
+ "shortname": "mosolymp-2023-1274"
+ },
+ "144043": {
+ "shortname": "mosolymp-2023-1275"
+ },
+ "144044": {
+ "shortname": "mosolymp-2023-1276"
+ },
+ "144045": {
+ "shortname": "mosolymp-2023-1277"
+ },
+ "144046": {
+ "shortname": "mosolymp-2023-1278"
+ },
+ "144047": {
+ "shortname": "mosolymp-2023-1279"
+ },
+ "144048": {
+ "shortname": "mosolymp-2023-1280"
+ },
+ "144049": {
+ "shortname": "mosolymp-2023-1281"
+ },
+ "144050": {
+ "shortname": "mosolymp-2023-1282"
+ },
+ "144051": {
+ "shortname": "mosolymp-2023-1283"
+ },
+ "144052": {
+ "shortname": "mosolymp-2023-1284"
+ },
+ "144053": {
+ "shortname": "mosolymp-2023-1285"
+ },
+ "144054": {
+ "shortname": "mosolymp-2023-1286"
+ },
+ "144055": {
+ "shortname": "mosolymp-2023-1287"
+ },
+ "144056": {
+ "shortname": "mosolymp-2023-1288"
+ },
+ "144057": {
+ "shortname": "mosolymp-2023-1289"
+ },
+ "144058": {
+ "shortname": "mosolymp-2023-1290"
+ },
+ "144059": {
+ "shortname": "mosolymp-2023-1291"
+ },
+ "144060": {
+ "shortname": "mosolymp-2023-1292"
+ },
+ "144061": {
+ "shortname": "mosolymp-2023-1293"
+ },
+ "144062": {
+ "shortname": "mosolymp-2023-1294"
+ },
+ "144063": {
+ "shortname": "mosolymp-2023-1295"
+ },
+ "144064": {
+ "shortname": "mosolymp-2023-1296"
+ },
+ "144065": {
+ "shortname": "mosolymp-2023-1297"
+ },
+ "144066": {
+ "shortname": "mosolymp-2023-1298"
+ },
+ "144067": {
+ "shortname": "mosolymp-2023-1299"
+ },
+ "144068": {
+ "shortname": "mosolymp-2023-1300"
+ }
+ },
+ "problemOverrides": {
+ "A": {
+ "color": "#e6194b"
+ },
+ "B": {
+ "color": "#3cb44b"
+ },
+ "C": {
+ "color": "#ffe119"
+ },
+ "D": {
+ "color": "#4363d8"
+ },
+ "E": {
+ "color": "#f58231"
+ },
+ "F": {
+ "color": "#42d4f4"
+ }
+ }
+}
\ No newline at end of file
diff --git a/config/mosh/2023/keldysh/events.properties b/config/__tests/ejudge_ioi_virtual/mosh-2023-keldysh/events.properties
similarity index 88%
rename from config/mosh/2023/keldysh/events.properties
rename to config/__tests/ejudge_ioi_virtual/mosh-2023-keldysh/events.properties
index 91e72d8a1..184827209 100644
--- a/config/mosh/2023/keldysh/events.properties
+++ b/config/__tests/ejudge_ioi_virtual/mosh-2023-keldysh/events.properties
@@ -1,5 +1,5 @@
standings.type=EJUDGE
-standings.resultType=IOI
+standings.resultType=ioi
turl2=https://olympiads.ru/aBXA2lMYmx3hNaZW/external.xml
turl3=https://olympiads.ru/LW96bHqAIXmwH1cD/external.xml
url=https://olympiads.ru/GDUvPbXKZ6lXalSG/external.xml
\ No newline at end of file
diff --git a/config/icpc-nef/2022-2023/events.properties b/config/__tests/pcms_icpc_freeze/icpc-nef-2022-2023/events.properties
similarity index 72%
rename from config/icpc-nef/2022-2023/events.properties
rename to config/__tests/pcms_icpc_freeze/icpc-nef-2022-2023/events.properties
index 0439a706e..233a507fe 100644
--- a/config/icpc-nef/2022-2023/events.properties
+++ b/config/__tests/pcms_icpc_freeze/icpc-nef-2022-2023/events.properties
@@ -1,2 +1,2 @@
url=https://nerc.itmo.ru/archive/2022/standings.xml
-standings.type=PCMS
+standings.type=PCMS
\ No newline at end of file
diff --git a/config/__tests/pcms_icpc_overrides/icpc-nef-2021-2022/advanced.json b/config/__tests/pcms_icpc_overrides/icpc-nef-2021-2022/advanced.json
new file mode 100644
index 000000000..b4ce42e7b
--- /dev/null
+++ b/config/__tests/pcms_icpc_overrides/icpc-nef-2021-2022/advanced.json
@@ -0,0 +1,856 @@
+{
+ "problemOverrides": {
+ "A":{"color":"#e6194B"},
+ "B":{"color":"#3cb44b"},
+ "C":{"color":"#ffe119"},
+ "D":{"color":"#4363d8"},
+ "E":{"color":"#f58231"},
+ "F":{"color":"#42d4f4"},
+ "G":{"color":"#f032e6"},
+ "H":{"color":"#fabed4"},
+ "I":{"color":"#469990"},
+ "J":{"color":"#dcbeff"},
+ "K":{"color":"#9A6324"},
+ "L":{"color":"#fffac8"}
+ },
+ "scoreboardOverrides": {
+ "medals": [
+ {
+ "name": "gold",
+ "count": 4
+ },
+ {
+ "name": "silver",
+ "count": 4
+ },
+ {
+ "name": "bronze",
+ "count": 4
+ }
+ ]
+ },
+ "teamOverrides": {
+ "642163": {
+ "shortname": "Novosibirsk SU: Winnie the Pooh"
+ },
+ "661436": {
+ "shortname": "Tomsk PU: 1"
+ },
+ "661437": {
+ "shortname": "SibSUTI: 1 Neutral"
+ },
+ "661438": {
+ "shortname": "OmSU: 3"
+ },
+ "661439": {
+ "shortname": "Novosibirsk SU: Ia-Ia"
+ },
+ "661440": {
+ "shortname": "Altai STU: 2"
+ },
+ "661441": {
+ "shortname": "SibSUTI: 2 Fullstack_Pascal+HTML"
+ },
+ "661442": {
+ "shortname": "NSTU: 5"
+ },
+ "661443": {
+ "shortname": "Altai STU: 1"
+ },
+ "661444": {
+ "shortname": "Novosibirsk SU: Piglet"
+ },
+ "661445": {
+ "shortname": "Novosibirsk SU: Wrong Bees"
+ },
+ "661446": {
+ "shortname": "Novosibirsk SU: Honey Pot"
+ },
+ "661447": {
+ "shortname": "SibSUTI: 10"
+ },
+ "661448": {
+ "shortname": "SibSUTI: 9 Brawl Stars"
+ },
+ "661449": {
+ "shortname": "SibSUTI: 8 Experiment 626"
+ },
+ "661450": {
+ "shortname": "SSTU: 3"
+ },
+ "661451": {
+ "shortname": "NSTU: 1"
+ },
+ "661452": {
+ "shortname": "NSTU: 2"
+ },
+ "661453": {
+ "shortname": "OmSU: 1"
+ },
+ "661454": {
+ "shortname": "OmSU: 2"
+ },
+ "661455": {
+ "shortname": "NSTU: 4"
+ },
+ "661456": {
+ "shortname": "Tomsk PU: 2"
+ },
+ "661457": {
+ "shortname": "Tomsk PU: 3"
+ },
+ "661458": {
+ "shortname": "SSTU: 2"
+ },
+ "663462": {
+ "shortname": "AUCA: 1"
+ },
+ "663463": {
+ "shortname": "KRSU: We_Love_Coffee"
+ },
+ "663464": {
+ "shortname": "IAU: nothing to code"
+ },
+ "663465": {
+ "shortname": "KGiAI: one_more_time"
+ },
+ "663466": {
+ "shortname": "KRSU: 5"
+ },
+ "663467": {
+ "shortname": "UCA: Team1"
+ },
+ "663468": {
+ "shortname": "OshTU: 2"
+ },
+ "663469": {
+ "shortname": "AUCA: MedSons"
+ },
+ "663470": {
+ "shortname": "Kyrgyz-Turkey Manas U: 7"
+ },
+ "663471": {
+ "shortname": "Kyrgyz-Turkey Manas U: 1"
+ },
+ "663472": {
+ "shortname": "Kyrgyz-Turkey Manas U: 5"
+ },
+ "663473": {
+ "shortname": "KRSU: blastMaker"
+ },
+ "663474": {
+ "shortname": "Kyrgyz-Turkey Manas U: 4"
+ },
+ "663475": {
+ "shortname": "AUCA: Dungeon masters"
+ },
+ "663476": {
+ "shortname": "AUCA: dishmans"
+ },
+ "667602": {
+ "shortname": "HSE: trained+Overpressured"
+ },
+ "667603": {
+ "shortname": "MIPT: Log-rank conjecture"
+ },
+ "667604": {
+ "shortname": "HSE: Yandex PTU"
+ },
+ "667605": {
+ "shortname": "MIPT: The Phoenix"
+ },
+ "667606": {
+ "shortname": "MIPT: LinkCat"
+ },
+ "667607": {
+ "shortname": "HSE: Dirizhabl’"
+ },
+ "667608": {
+ "shortname": "HSE: Mystery Machine"
+ },
+ "667609": {
+ "shortname": "Moscow SU: NoNames"
+ },
+ "667610": {
+ "shortname": "MAI: 1"
+ },
+ "667611": {
+ "shortname": "Moscow SU: Johnnie Jack and Jim"
+ },
+ "667612": {
+ "shortname": "MIPT: Never Trained"
+ },
+ "667613": {
+ "shortname": "MIPT: Flying Penguins"
+ },
+ "667614": {
+ "shortname": "MIPT: Wake up"
+ },
+ "667615": {
+ "shortname": "Moscow SU: bebop"
+ },
+ "667616": {
+ "shortname": "Moscow SU: MAN"
+ },
+ "667617": {
+ "shortname": "MAI: 5"
+ },
+ "667618": {
+ "shortname": "MPSU: Matemasters"
+ },
+ "667619": {
+ "shortname": "MEPhI: Sweet Potato"
+ },
+ "667620": {
+ "shortname": "MISiS: Palm_Hop_Selec"
+ },
+ "667621": {
+ "shortname": "MAI: 2"
+ },
+ "667622": {
+ "shortname": "MISiS: ICPC is overrated"
+ },
+ "667623": {
+ "shortname": "MIREA: Team 1"
+ },
+ "667624": {
+ "shortname": "MISiS: Solving meth problems"
+ },
+ "667625": {
+ "shortname": "BMSTU: 30 seconds to parse"
+ },
+ "667626": {
+ "shortname": "MISiS: Flip phone, telefon"
+ },
+ "667627": {
+ "shortname": "MIET: NUM"
+ },
+ "667628": {
+ "shortname": "BNTU: 4294967297"
+ },
+ "667629": {
+ "shortname": "BelarusianSU: 2"
+ },
+ "667630": {
+ "shortname": "BelarusianSU: 1"
+ },
+ "667631": {
+ "shortname": "BelarusianSU: 6"
+ },
+ "667632": {
+ "shortname": "BSUIR: 5 The last one"
+ },
+ "667633": {
+ "shortname": "BSUIR: 9 si4uem s kaifom"
+ },
+ "667634": {
+ "shortname": "BelarusianSU: 7 OSUTeam"
+ },
+ "667635": {
+ "shortname": "GrSU: 1"
+ },
+ "667636": {
+ "shortname": "BSUIR: 7 ugoschaet golubcami"
+ },
+ "667637": {
+ "shortname": "GSU: -2"
+ },
+ "667638": {
+ "shortname": "GSU: -1"
+ },
+ "667639": {
+ "shortname": "BrSU: 1 AP Team"
+ },
+ "667640": {
+ "shortname": "BNTU: FITRx3"
+ },
+ "667641": {
+ "shortname": "GrSU: 2"
+ },
+ "667642": {
+ "shortname": "BelSUT: _1"
+ },
+ "667643": {
+ "shortname": "BelSTU: 1"
+ },
+ "667644": {
+ "shortname": "GSTU: Si vis pacem, para bellum"
+ },
+ "667645": {
+ "shortname": "SPb ITMO: pengzoo"
+ },
+ "667646": {
+ "shortname": "SPb HSE: Lemon Tree"
+ },
+ "667647": {
+ "shortname": "SPb SU: dataVase"
+ },
+ "667648": {
+ "shortname": "SPb SU: Team Chill It"
+ },
+ "667649": {
+ "shortname": "SPb SU: ?5"
+ },
+ "667650": {
+ "shortname": "SPb SU: MCS: Andrew Sergeevich"
+ },
+ "667651": {
+ "shortname": "SPb SU: jazz"
+ },
+ "667652": {
+ "shortname": "SPb ITMO: Cataleptodius"
+ },
+ "667653": {
+ "shortname": "SPb ITMO: Unexpected Value"
+ },
+ "667654": {
+ "shortname": "SPb ITMO: hw"
+ },
+ "667655": {
+ "shortname": "SPb ITMO: TaskAcceptedException"
+ },
+ "667656": {
+ "shortname": "SPb HSE: HS of Abbreviations"
+ },
+ "667657": {
+ "shortname": "SPb HSE: Just4Keks"
+ },
+ "667658": {
+ "shortname": "Petrozavodsk SU: pgt Shya"
+ },
+ "667659": {
+ "shortname": "Budenny MTA: Peacemakers"
+ },
+ "667660": {
+ "shortname": "Petrozavodsk SU: Bukva yu"
+ },
+ "667661": {
+ "shortname": "Polytech: Ab absurdo 4"
+ },
+ "667662": {
+ "shortname": "Petrozavodsk SU: adamant"
+ },
+ "667663": {
+ "shortname": "SUAI: MegaSmetanka"
+ },
+ "667664": {
+ "shortname": "SUAI: 1703"
+ },
+ "667665": {
+ "shortname": "CFUV: Vernadsky"
+ },
+ "667666": {
+ "shortname": "CFUV: Endeavor"
+ },
+ "667667": {
+ "shortname": "CFUV: pod3.14vasniki"
+ },
+ "667668": {
+ "shortname": "CFUV: Team_Pepega"
+ },
+ "667669": {
+ "shortname": "YarSU: 1 Yess we can"
+ },
+ "667670": {
+ "shortname": "NArFU: 2"
+ },
+ "667671": {
+ "shortname": "AFSO: 7"
+ },
+ "667672": {
+ "shortname": "YarSU: 20 LigaDravena"
+ },
+ "667673": {
+ "shortname": "YarSU: 2 chill_owls"
+ },
+ "667674": {
+ "shortname": "RSATU: 4"
+ },
+ "667675": {
+ "shortname": "TverSU: 3 Guerilla Gorillas"
+ },
+ "667676": {
+ "shortname": "BSTU: 1 winx_v3.0"
+ },
+ "667677": {
+ "shortname": "Ural FU: The Last Dance"
+ },
+ "667678": {
+ "shortname": "Ural FU: ReFresh"
+ },
+ "667679": {
+ "shortname": "Ural FU: CheezeKEK"
+ },
+ "667680": {
+ "shortname": "Perm SU: Cats"
+ },
+ "667681": {
+ "shortname": "Ural FU: Raketa & 3 Deda"
+ },
+ "667682": {
+ "shortname": "Ural FU: Cucumber Juice 73"
+ },
+ "667683": {
+ "shortname": "Perm SU: corgi_never_sleep"
+ },
+ "667684": {
+ "shortname": "Ufa SATU: God's Choice"
+ },
+ "667685": {
+ "shortname": "Izhevsk STU: CyTheFu"
+ },
+ "667686": {
+ "shortname": "Perm SU: Plusbl"
+ },
+ "667687": {
+ "shortname": "Izhevsk STU: ZEDbl"
+ },
+ "667688": {
+ "shortname": "Tyumen SU: import.math"
+ },
+ "667689": {
+ "shortname": "Surgut SU: DieHard"
+ },
+ "667690": {
+ "shortname": "Tyumen SU: Permutation Of Lenovo"
+ },
+ "667691": {
+ "shortname": "Perm HSE: pitonishe"
+ },
+ "667692": {
+ "shortname": "Orenburg SU: feel_good"
+ },
+ "667693": {
+ "shortname": "Izhevsk STU: People++"
+ },
+ "667694": {
+ "shortname": "Orenburg SU: How much I love BTS"
+ },
+ "667695": {
+ "shortname": "South Ural SU: Masters of Crosses"
+ },
+ "667696": {
+ "shortname": "South Ural SU: UZI"
+ },
+ "667697": {
+ "shortname": "South Ural SU: 0 div 0"
+ },
+ "667698": {
+ "shortname": "Innopolis: U Q"
+ },
+ "667699": {
+ "shortname": "Penza SU: I"
+ },
+ "667700": {
+ "shortname": "UNN: Lera Retired"
+ },
+ "667701": {
+ "shortname": "UNN: Presskachat"
+ },
+ "667702": {
+ "shortname": "Innopolis: U I"
+ },
+ "667703": {
+ "shortname": "Kazan FU: A"
+ },
+ "667704": {
+ "shortname": "SFedU: E"
+ },
+ "667705": {
+ "shortname": "Saratov SU: Innopolis U 0"
+ },
+ "667706": {
+ "shortname": "Volgograd STU"
+ },
+ "667707": {
+ "shortname": "Kazan FU: V"
+ },
+ "667708": {
+ "shortname": "Saratov SU: H"
+ },
+ "667709": {
+ "shortname": "NRU HSE: NN 1"
+ },
+ "667710": {
+ "shortname": "NRU HSE: NN Brawl Stars"
+ },
+ "667711": {
+ "shortname": "MordSU: D"
+ },
+ "667712": {
+ "shortname": "VoronezhSU: H"
+ },
+ "667713": {
+ "shortname": "SFedU: C"
+ },
+ "667714": {
+ "shortname": "USTU: J"
+ },
+ "667715": {
+ "shortname": "VoronezhSU: B"
+ },
+ "667716": {
+ "shortname": "Saratov SU: P"
+ },
+ "667717": {
+ "shortname": "MordSU: E"
+ },
+ "667718": {
+ "shortname": "Kazan FU: G"
+ },
+ "667719": {
+ "shortname": "Saratov SU: J"
+ },
+ "667720": {
+ "shortname": "ASU: B"
+ },
+ "667769": {
+ "shortname": "MSU Tashkent: 1 Awesome Team"
+ },
+ "667770": {
+ "shortname": "TUIT: pfff"
+ },
+ "667771": {
+ "shortname": "RusTjkSlav: Head_Shot"
+ },
+ "667772": {
+ "shortname": "MGUD: 7"
+ },
+ "667773": {
+ "shortname": "MGUD: 2"
+ },
+ "667774": {
+ "shortname": "MGUD: 1"
+ },
+ "667775": {
+ "shortname": "MSU Tashkent: 2"
+ },
+ "667776": {
+ "shortname": "SamTUIT: SLD Group"
+ },
+ "667777": {
+ "shortname": "TUIT: Lorem Ipsum"
+ },
+ "667778": {
+ "shortname": "RusTjkSlav: NERU"
+ },
+ "667779": {
+ "shortname": "SamTUIT: oVerfitting"
+ },
+ "667780": {
+ "shortname": "TUIT: Falcon"
+ },
+ "667781": {
+ "shortname": "SamTUIT: RUNTIME tERROR"
+ },
+ "667782": {
+ "shortname": "MSU Tashkent: 4 Silent Birds"
+ },
+ "667783": {
+ "shortname": "TUIT: Algo_experts"
+ },
+ "667784": {
+ "shortname": "TUIT Urgench Branch: 1"
+ },
+ "667785": {
+ "shortname": "RusTjkSlav: Silk Way"
+ },
+ "667786": {
+ "shortname": "NUUz: geeksforgeeks"
+ },
+ "667787": {
+ "shortname": "RusTjkSlav: Shakarob"
+ },
+ "667788": {
+ "shortname": "TUIT Urgench Branch: 2"
+ },
+ "667789": {
+ "shortname": "JBNUU: M"
+ },
+ "667790": {
+ "shortname": "NUUz: NUU_10"
+ },
+ "667791": {
+ "shortname": "Namangan SU: 1"
+ },
+ "667792": {
+ "shortname": "SamSU: LifePC Group"
+ },
+ "667793": {
+ "shortname": "MIICTS: _1"
+ },
+ "667794": {
+ "shortname": "SamTUIT: thephaza"
+ },
+ "667795": {
+ "shortname": "JBNUU: Progress"
+ },
+ "667796": {
+ "shortname": "MGUD: 9"
+ },
+ "667797": {
+ "shortname": "SamSU: Dream Team"
+ },
+ "667798": {
+ "shortname": "IIAU: Revengers"
+ },
+ "667799": {
+ "shortname": "AndMII: Heaven"
+ },
+ "667800": {
+ "shortname": "IITU: SuperNoVa"
+ },
+ "667801": {
+ "shortname": "NU: 1"
+ },
+ "667802": {
+ "shortname": "KBTU: Don't panic"
+ },
+ "667803": {
+ "shortname": "AITU: 1"
+ },
+ "667804": {
+ "shortname": "IITU: set"
+ },
+ "667805": {
+ "shortname": "AITU: 2"
+ },
+ "667806": {
+ "shortname": "AITU: 4"
+ },
+ "667807": {
+ "shortname": "KBTU: Sᴬᵁ Bᴼᴸᵂᴵ"
+ },
+ "667808": {
+ "shortname": "NU: 5"
+ },
+ "667809": {
+ "shortname": "NU: 2"
+ },
+ "667810": {
+ "shortname": "IITU: ur mamaso"
+ },
+ "667811": {
+ "shortname": "SDU: 1"
+ },
+ "667812": {
+ "shortname": "KazNU: 1"
+ },
+ "667813": {
+ "shortname": "SDU: 2 Abudyn' DastanKhany"
+ },
+ "667814": {
+ "shortname": "NU: 3"
+ },
+ "667815": {
+ "shortname": "IITU: AbDiAl"
+ },
+ "667816": {
+ "shortname": "KBTU: Kazakh Mafia"
+ },
+ "667817": {
+ "shortname": "KBTU: N^3"
+ },
+ "667818": {
+ "shortname": "AITU: 5"
+ },
+ "667819": {
+ "shortname": "KazNTU: SU1"
+ },
+ "667820": {
+ "shortname": "KazNU: 2"
+ },
+ "667821": {
+ "shortname": "KazNU: 3"
+ },
+ "667822": {
+ "shortname": "KazNTU: SU2"
+ },
+ "667823": {
+ "shortname": "SDU: balmuzdaqtar"
+ },
+ "667824": {
+ "shortname": "KazNU: 4"
+ },
+ "667825": {
+ "shortname": "AIPET: _1"
+ },
+ "667826": {
+ "shortname": "KTU: 1"
+ },
+ "667827": {
+ "shortname": "Far Eastern FU: CODE work"
+ },
+ "667828": {
+ "shortname": "Far Eastern FU: Time Limit"
+ },
+ "667829": {
+ "shortname": "Far Eastern FU: Garbies"
+ },
+ "667830": {
+ "shortname": "Far Eastern FU: FlexBoiz"
+ },
+ "667831": {
+ "shortname": "Far Eastern STU: DevOchka"
+ },
+ "667832": {
+ "shortname": "Far Eastern STU: myTEAmmm"
+ },
+ "667833": {
+ "shortname": "Far Eastern STU: kekadev"
+ },
+ "667834": {
+ "shortname": "VSUES: Videokrolik"
+ },
+ "667835": {
+ "shortname": "VSUES: 8"
+ },
+ "667836": {
+ "shortname": "Irkutsk U: 4 whoami"
+ },
+ "667837": {
+ "shortname": "INRTU: 3 PolyTech"
+ },
+ "667838": {
+ "shortname": "Irkutsk U: 5 take it easy"
+ },
+ "667839": {
+ "shortname": "Irkutsk U: 2 322"
+ },
+ "667840": {
+ "shortname": "esstu: 5 Wolf Auf"
+ },
+ "667841": {
+ "shortname": "BSU: 4 nonremmitalSpiders"
+ },
+ "667842": {
+ "shortname": "IMCS SFU: 1 KlopiTarakani"
+ },
+ "667843": {
+ "shortname": "Khakas TI of SFU: 4 ZXCoders"
+ },
+ "667844": {
+ "shortname": "BSU: 3 soldaP"
+ },
+ "667845": {
+ "shortname": "ISRU: 2 molodie lisyata"
+ },
+ "667846": {
+ "shortname": "Zabaikal SU: 1"
+ },
+ "667847": {
+ "shortname": "BSU: 1 TNT"
+ },
+ "667848": {
+ "shortname": "ISRU: 1 Brainstorm"
+ },
+ "667849": {
+ "shortname": "INRTU: 2Team"
+ },
+ "667850": {
+ "shortname": "Tuvan SU: 1 Achiles Turtles"
+ },
+ "667851": {
+ "shortname": "ESSUTM: 1 ElderlyCoders"
+ },
+ "667852": {
+ "shortname": "ISIT SFU: 2 Systema auto pobedi"
+ },
+ "667853": {
+ "shortname": "Tuvan SU: 2 Akatsuki"
+ },
+ "667854": {
+ "shortname": "ISIT SFU: 4 Super Cookies"
+ },
+ "667855": {
+ "shortname": "Zabaikal SU: 2"
+ },
+ "667856": {
+ "shortname": "BSU: 2 SYAS"
+ },
+ "667857": {
+ "shortname": "Khakas TI of SFU: 1 Real Tigers"
+ },
+ "667872": {
+ "shortname": "SamSU: _ITEG_1"
+ },
+ "667898": {
+ "shortname": "BelarusianSU: 5"
+ },
+ "667899": {
+ "shortname": "BSUIR: 2 Brute Force - Best Force"
+ },
+ "667938": {
+ "shortname": "NU: 4"
+ },
+ "668532": {
+ "shortname": "YarSU: 12 HuRMa"
+ },
+ "668533": {
+ "shortname": "VyatkaGU: 9"
+ },
+ "668534": {
+ "shortname": "OrelSU: 1"
+ },
+ "668536": {
+ "shortname": "MSU Tashkent: 3 Froggg"
+ },
+ "668594": {
+ "shortname": "VoronezhSU: F"
+ },
+ "668693": {
+ "shortname": "BelarusianSU: 3 Mogilev Eagles"
+ },
+ "668694": {
+ "shortname": "HSE: Sovetskiy Soyuz"
+ },
+ "669271": {
+ "shortname": "Yerevan SU: 2813"
+ },
+ "669272": {
+ "shortname": "Yerevan SU: 1"
+ },
+ "669273": {
+ "shortname": "Yerevan SU: bit.ly/2YlU2Si"
+ },
+ "669274": {
+ "shortname": "Yerevan SU: SSD"
+ },
+ "669275": {
+ "shortname": "RAU: 2"
+ },
+ "669276": {
+ "shortname": "RAU: 1"
+ },
+ "669277": {
+ "shortname": "NPUA: polytex"
+ },
+ "669278": {
+ "shortname": "RAU: 3"
+ },
+ "669279": {
+ "shortname": "AUA: 1"
+ },
+ "669280": {
+ "shortname": "Goris SU: We and Our Mountains"
+ },
+ "669281": {
+ "shortname": "EUA: Mercury1"
+ },
+ "669282": {
+ "shortname": "APSU: ASPU"
+ },
+ "669283": {
+ "shortname": "NUACA"
+ },
+ "670017": {
+ "shortname": "KBTU: Permission denied"
+ },
+ "670045": {
+ "shortname": "YarSU: 18 Dead_Inside_Team"
+ },
+ "670108": {
+ "shortname": "NEFU"
+ }
+ }
+}
\ No newline at end of file
diff --git a/config/icpc-nef/2021-2022/main/events.properties b/config/__tests/pcms_icpc_overrides/icpc-nef-2021-2022/events.properties
similarity index 62%
rename from config/icpc-nef/2021-2022/main/events.properties
rename to config/__tests/pcms_icpc_overrides/icpc-nef-2021-2022/events.properties
index 70e1a3438..18daf3a1d 100644
--- a/config/icpc-nef/2021-2022/main/events.properties
+++ b/config/__tests/pcms_icpc_overrides/icpc-nef-2021-2022/events.properties
@@ -1,5 +1,2 @@
url=https://nerc.itmo.ru/archive/2021/standings.xml
standings.type=PCMS
-
-emulation.speed=5
-emulation.startTime=now
diff --git a/config/__tests/pcms_ioi/innopolis-open-2022-2023-final/advanced.json b/config/__tests/pcms_ioi/innopolis-open-2022-2023-final/advanced.json
new file mode 100644
index 000000000..04795ce74
--- /dev/null
+++ b/config/__tests/pcms_ioi/innopolis-open-2022-2023-final/advanced.json
@@ -0,0 +1,9 @@
+{
+ "problemOverrides": {
+ "A":{"color":"#06d50d"},
+ "B":{"color":"#1b2cff"},
+ "C":{"color":"#9d2fff"},
+ "D":{"color":"#fd920e"},
+ "E":{"color":"#ff3821"}
+ }
+}
\ No newline at end of file
diff --git a/config/innopolis-open/2022-2023/final/events.properties b/config/__tests/pcms_ioi/innopolis-open-2022-2023-final/events.properties
similarity index 100%
rename from config/innopolis-open/2022-2023/final/events.properties
rename to config/__tests/pcms_ioi/innopolis-open-2022-2023-final/events.properties
diff --git a/config/__tests/testsys_icpc/spbsu-2023-may/advanced.json b/config/__tests/testsys_icpc/spbsu-2023-may/advanced.json
new file mode 100644
index 000000000..8a2b44960
--- /dev/null
+++ b/config/__tests/testsys_icpc/spbsu-2023-may/advanced.json
@@ -0,0 +1,31 @@
+{
+ "scoreboardOverrides": {
+ "medals": [
+ {"name": "gold", "count": 4},
+ {"name": "silver", "count": 4},
+ {"name": "bronze", "count": 4}
+ ],
+ "showTeamsWithoutSubmissions": true
+ },
+ "problemOverrides": {
+ "A":{"color":"#e6194B"},
+ "B":{"color":"#3cb44b"},
+ "C":{"color":"#ffe119"},
+ "D":{"color":"#4363d8"},
+ "E":{"color":"#f58231"},
+ "F":{"color":"#42d4f4"},
+ "G":{"color":"#f032e6"},
+ "H":{"color":"#fabed4"},
+ "I":{"color":"#469990"},
+ "J":{"color":"#dcbeff"},
+ "K":{"color":"#9A6324"},
+ "L":{"color":"#fffac8"},
+ "M":{"color":"#800000"},
+ "N":{"color":"#aaffc3"},
+ "O":{"color":"#000075"},
+ "P":{"color":"#a9a9a9"},
+ "Q":{"color":"#e6194B"},
+ "R":{"color":"#3cb44b"},
+ "S":{"color":"#ffe119"}
+ }
+}
\ No newline at end of file
diff --git a/config/spbsu/2023-may/main/events.properties b/config/__tests/testsys_icpc/spbsu-2023-may/events.properties
similarity index 60%
rename from config/spbsu/2023-may/main/events.properties
rename to config/__tests/testsys_icpc/spbsu-2023-may/events.properties
index 7842b5b05..54dfead73 100644
--- a/config/spbsu/2023-may/main/events.properties
+++ b/config/__tests/testsys_icpc/spbsu-2023-may/events.properties
@@ -1,3 +1,2 @@
standings.type=TESTSYS
-#url=https://nerc.itmo.ru/jm230514.dat for resolver
url=http://acm.math.spbu.ru/cgi-bin/view.pl/m230514.dat
\ No newline at end of file
diff --git a/config/_examples/_CF/events.properties b/config/_examples/_CF/events.properties
deleted file mode 100644
index 81604ab7b..000000000
--- a/config/_examples/_CF/events.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-cf.api.key=af7612378661287361278368dd
-cf.api.secret=afde128478473784adfffedfff
-contest_id=1600
-standings.type=CF
diff --git a/config/_examples/_CF/settings.json b/config/_examples/_CF/settings.json
new file mode 100644
index 000000000..6d679e42e
--- /dev/null
+++ b/config/_examples/_CF/settings.json
@@ -0,0 +1,6 @@
+{
+ "type": "cf",
+ "apiKey": "$creds.codeforces_key",
+ "apiSecret": "$creds.codeforces_secret",
+ "contestId": 1600
+}
diff --git a/config/_examples/_achievements_simple/advanced.json b/config/_examples/_achievements_simple/advanced.json
index 03af9efb2..ea8dc0648 100644
--- a/config/_examples/_achievements_simple/advanced.json
+++ b/config/_examples/_achievements_simple/advanced.json
@@ -6,7 +6,7 @@
}
},
"teamOverrides": {
-"486860": {"shortname": "SPb HSE 1: Lemon Tree", "groups": ["SPb HSE", "SPb"], "additionalInfo": "Safonov | Gorokhovskii | Fedoseev"},
+"486860": {"shortname": "SPb HSE 1: Lemon Tree", "groups": ["SPb HSE", "SPb"], "customFields": {"svgInfo": "Safonov | Gorokhovskii | Fedoseev"}},
"486908": {"shortname": "Ufa SATU: Electric Funeral", "groups": ["Ufa SATU", "Other"]},
"486910": {"shortname": "Budenny Mil Telecom A: 1", "groups": ["Budenny Mil Telecom A", "SPb"]}
}
diff --git a/config/_examples/_achievements_simple/events.properties b/config/_examples/_achievements_simple/events.properties
deleted file mode 100644
index 24eafd65c..000000000
--- a/config/_examples/_achievements_simple/events.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-url=http://nerc.itmo.ru/archive/2020/standings.xml
-standings.type=PCMS
-
-emulation.speed=1
-emulation.startTime=now
diff --git a/config/_examples/_achievements_simple/settings.json b/config/_examples/_achievements_simple/settings.json
new file mode 100644
index 000000000..18e7d0881
--- /dev/null
+++ b/config/_examples/_achievements_simple/settings.json
@@ -0,0 +1,6 @@
+{
+ "url":"http://nerc.itmo.ru/archive/2020/standings.xml",
+ "type":"pcms",
+
+ "emulation":{"speed":1, "startTime":"now"}
+}
\ No newline at end of file
diff --git a/config/_examples/_cats_icpc/events.properties b/config/_examples/_cats_icpc/events.properties
deleted file mode 100644
index 6587d5931..000000000
--- a/config/_examples/_cats_icpc/events.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-url=https://imcs.dvfu.ru/cats
-cid=5481581
-standings.type=CATS
-timezone=UTC+10
-standings.resultType=ICPC
-login=$creds.cats.login
-password=$creds.cats.password
\ No newline at end of file
diff --git a/config/_examples/_cats_icpc/settings.json b/config/_examples/_cats_icpc/settings.json
new file mode 100644
index 000000000..16a137dcb
--- /dev/null
+++ b/config/_examples/_cats_icpc/settings.json
@@ -0,0 +1,9 @@
+{
+ "type":"cats",
+ "url":"https://imcs.dvfu.ru/cats",
+ "cid":"5481581",
+ "timeZone":"UTC+10",
+ "resultType":"ICPC",
+ "login":"$creds.cats_login",
+ "password":"$creds.cats_password"
+}
\ No newline at end of file
diff --git a/config/_examples/_cats_ioi/events.properties b/config/_examples/_cats_ioi/events.properties
deleted file mode 100644
index 328a5826c..000000000
--- a/config/_examples/_cats_ioi/events.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-url=https://imcs.dvfu.ru/cats
-cid=5974394
-standings.type=CATS
-timezone=UTC+10
-standings.resultType=IOI
-login=$creds.cats.login
-password=$creds.cats.password
diff --git a/config/_examples/_cats_ioi/settings.json b/config/_examples/_cats_ioi/settings.json
new file mode 100644
index 000000000..c9a7a7c4e
--- /dev/null
+++ b/config/_examples/_cats_ioi/settings.json
@@ -0,0 +1,9 @@
+{
+ "url":"https://imcs.dvfu.ru/cats",
+ "cid":"5974394",
+ "type":"cats",
+ "timeZone":"UTC+10",
+ "resultType":"IOI",
+ "login":"$creds.cats_login",
+ "password":"$creds.cats_password"
+}
\ No newline at end of file
diff --git a/config/_examples/_cms/advanced.json b/config/_examples/_cms/advanced.json
new file mode 100644
index 000000000..778c08f8f
--- /dev/null
+++ b/config/_examples/_cms/advanced.json
@@ -0,0 +1,22 @@
+{
+ "problemOverrides": {
+ "SC2022CEOI13prize": {
+ "displayName": "A1"
+ },
+ "SC2022CEOI11abracadabra": {
+ "displayName": "B1"
+ },
+ "SC2022CEOI12homework": {
+ "displayName": "C1"
+ },
+ "SC2022CEOI22measures": {
+ "displayName": "A2"
+ },
+ "SC2022CEOI21drawing": {
+ "displayName": "B2"
+ },
+ "SC2022CEOI23parking": {
+ "displayName": "C2"
+ }
+ }
+}
\ No newline at end of file
diff --git a/config/_examples/_cms/settings.json b/config/_examples/_cms/settings.json
new file mode 100644
index 000000000..2973ef405
--- /dev/null
+++ b/config/_examples/_cms/settings.json
@@ -0,0 +1,6 @@
+{
+ "type": "cms",
+ "activeContest": "ceoi22_5f2",
+ "otherContests": ["ceoi22_5f1"],
+ "url": "https://ceoi.hsin.hr/ranking/"
+}
\ No newline at end of file
diff --git a/config/_examples/_codedrills/settings.json b/config/_examples/_codedrills/settings.json
new file mode 100644
index 000000000..72bb48562
--- /dev/null
+++ b/config/_examples/_codedrills/settings.json
@@ -0,0 +1,7 @@
+{
+ "type": "codedrills",
+ "url": "site.api.prod.codedrills.io",
+ "port": 6565,
+ "authKey": "$creds.codedrills_key",
+ "contestId": "icpc-asia-west-continent-final-contest-2022"
+}
\ No newline at end of file
diff --git a/config/_examples/_domjudge_test1/events.properties b/config/_examples/_domjudge_test1/events.properties
deleted file mode 100644
index 2c3c02504..000000000
--- a/config/_examples/_domjudge_test1/events.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-login=live
-password=$creds.cds_password_pretest_dhaka
-url=https://cds.storm.vu/api/contests/pretest_dhaka
-standings.type=CLICS
\ No newline at end of file
diff --git a/config/_examples/_domjudge_test1/settings.json b/config/_examples/_domjudge_test1/settings.json
new file mode 100644
index 000000000..2284fb75b
--- /dev/null
+++ b/config/_examples/_domjudge_test1/settings.json
@@ -0,0 +1,6 @@
+{
+ "login":"live",
+ "password":"$creds.cds_password_pretest_dhaka",
+ "url":"https://cds.storm.vu/api/contests/pretest_dhaka",
+ "type":"clics"
+}
\ No newline at end of file
diff --git a/config/_examples/_krsu-test/events.properties b/config/_examples/_krsu-test/events.properties
deleted file mode 100644
index 70725ad9c..000000000
--- a/config/_examples/_krsu-test/events.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-standings.type=KRSU
-
-submissions-url = https://olymp.krsu.edu.kg/web/api/contestsubmissions/submissions?apiKey=a1f4d25se3&size=1000000&lowerBound=-1&upperBound=2000000000&contest=772&probe=0&isAdmin=1
-contest-url = https://olymp.krsu.edu.kg/web/api/contestsubmissions/contestinfo?apiKey=a1f4d25se3&id=772
-
-emulation.speed=5
-emulation.startTime=now
-
-
-
-
diff --git a/config/_examples/_krsu-test/settings.json b/config/_examples/_krsu-test/settings.json
new file mode 100644
index 000000000..5d6d957f5
--- /dev/null
+++ b/config/_examples/_krsu-test/settings.json
@@ -0,0 +1,12 @@
+{
+ "type":"krsu",
+
+ "submissionsUrl":"https://olymp.krsu.edu.kg/web/api/contestsubmissions/submissions?apiKey=a1f4d25se3&size=1000000&lowerBound=-1&upperBound=2000000000&contest=772&probe=0&isAdmin=1",
+ "contestUrl":"https://olymp.krsu.edu.kg/web/api/contestsubmissions/contestinfo?apiKey=a1f4d25se3&id=772",
+
+ "emulation":{"speed":5,"startTime":"now"}
+}
+
+
+
+
diff --git a/config/_examples/_pc2/events.properties b/config/_examples/_pc2/events.properties
deleted file mode 100644
index 774888be8..000000000
--- a/config/_examples/_pc2/events.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-url=_examples/_pc2
-feed_version=2020_03
-standings.type=CLICS
-emulation.startTime=now
-emulation.speed=5
diff --git a/config/_examples/_pc2/settings.json b/config/_examples/_pc2/settings.json
new file mode 100644
index 000000000..f912fab59
--- /dev/null
+++ b/config/_examples/_pc2/settings.json
@@ -0,0 +1,8 @@
+{
+ "type":"clics",
+
+ "url":"_examples/_pc2",
+ "feedVersion":"2020_03",
+
+ "emulation":{"speed":5,"startTime":"now"}
+}
diff --git a/config/_examples/_pcms-ioi-test/events-new.xml b/config/_examples/_pcms-ioi-test/events-new.xml
deleted file mode 100644
index 436691123..000000000
--- a/config/_examples/_pcms-ioi-test/events-new.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/config/_examples/_pcms-ioi-test/events.xml b/config/_examples/_pcms-ioi-test/events.xml
deleted file mode 100644
index 6991bafa3..000000000
--- a/config/_examples/_pcms-ioi-test/events.xml
+++ /dev/null
@@ -1,163 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/config/_examples/_pcms-ioi-test/participants.xml b/config/_examples/_pcms-ioi-test/participants.xml
deleted file mode 100644
index 654ffcea0..000000000
--- a/config/_examples/_pcms-ioi-test/participants.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/config/_examples/_pcms-ioi-test/pcms.events.properties b/config/_examples/_pcms-ioi-test/pcms.events.properties
deleted file mode 100644
index 316d99d21..000000000
--- a/config/_examples/_pcms-ioi-test/pcms.events.properties
+++ /dev/null
@@ -1,10 +0,0 @@
-login=admin
-password=adm1n
-url=events.xml
-teams.url=participants.xml
-problems.url=problems.xml
-problems.number=6
-standings.type=IOIPCMS
-
-running.time=18000000
-freeze.time=18000000
\ No newline at end of file
diff --git a/config/_examples/_pcms-ioi-test/pcms.mainscreen.properties b/config/_examples/_pcms-ioi-test/pcms.mainscreen.properties
deleted file mode 100644
index 9c6750b50..000000000
--- a/config/_examples/_pcms-ioi-test/pcms.mainscreen.properties
+++ /dev/null
@@ -1,40 +0,0 @@
-update.wait=500
-backup.persons=persons.txt
-backup.advertisements=advertisements.txt
-breakingnews.time=20000
-breakingnews.runs.number=10
-breakingnews.patterns.filename=patterns.txt
-standings.blinking.time=10000
-advertisement.time=5000
-person.time=5000
-latency.time=2000
-data.update=1000
-data.host=localhost
-data.port=25675
-info.types=photo;screen
-main.type=photo
-info.photo=pics/team.jpg
-info.screen=pics/screen.jpg
-sleep.time=3000
-automated.show.time=20000
-automated.info=screen
-team.double.video=true
-
-queue.show.verdict=false
-
-ticker.rotate.time=1000
-ticker.logo=NEERC 2016;#NEERC2016
-ticker.logo.time=10000
-ticker.logo.change.time=2000
-
-overlayed.delay=3000
-
-width=1280
-height=720
-
-rate=10
-
-top.teams.file=pcms-test/topteams.txt
-onsite.teams=S.*
-
-stylesheet=stylesheets/wf.jss
diff --git a/config/_examples/_pcms-ioi-test/problems.xml b/config/_examples/_pcms-ioi-test/problems.xml
deleted file mode 100644
index 8c1dca878..000000000
--- a/config/_examples/_pcms-ioi-test/problems.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/_examples/_pcms-ioi-test/topteams.txt b/config/_examples/_pcms-ioi-test/topteams.txt
deleted file mode 100644
index b4224e06a..000000000
--- a/config/_examples/_pcms-ioi-test/topteams.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-S101
-S105
\ No newline at end of file
diff --git a/config/_examples/_pcms-test/events-new.xml b/config/_examples/_pcms-test/events-new.xml
deleted file mode 100644
index 086a06fc2..000000000
--- a/config/_examples/_pcms-test/events-new.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/config/_examples/_pcms-test/events.xml b/config/_examples/_pcms-test/events.xml
deleted file mode 100644
index 12dca96a7..000000000
--- a/config/_examples/_pcms-test/events.xml
+++ /dev/null
@@ -1,163 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/config/_examples/_pcms-test/participants.xml b/config/_examples/_pcms-test/participants.xml
deleted file mode 100644
index 5978e6680..000000000
--- a/config/_examples/_pcms-test/participants.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/config/_examples/_pcms-test/pcms.events.properties b/config/_examples/_pcms-test/pcms.events.properties
deleted file mode 100644
index eeb09be7e..000000000
--- a/config/_examples/_pcms-test/pcms.events.properties
+++ /dev/null
@@ -1,10 +0,0 @@
-login=admin
-password=adm1n
-url=events.xml
-participants=participants.xml
-problems.url=problems.xml
-problemsNumber=6
-standings.type=PCMS
-
-running.time=18000000
-freeze.time=14400000
\ No newline at end of file
diff --git a/config/_examples/_pcms-test/pcms.mainscreen.properties b/config/_examples/_pcms-test/pcms.mainscreen.properties
deleted file mode 100644
index 9c6750b50..000000000
--- a/config/_examples/_pcms-test/pcms.mainscreen.properties
+++ /dev/null
@@ -1,40 +0,0 @@
-update.wait=500
-backup.persons=persons.txt
-backup.advertisements=advertisements.txt
-breakingnews.time=20000
-breakingnews.runs.number=10
-breakingnews.patterns.filename=patterns.txt
-standings.blinking.time=10000
-advertisement.time=5000
-person.time=5000
-latency.time=2000
-data.update=1000
-data.host=localhost
-data.port=25675
-info.types=photo;screen
-main.type=photo
-info.photo=pics/team.jpg
-info.screen=pics/screen.jpg
-sleep.time=3000
-automated.show.time=20000
-automated.info=screen
-team.double.video=true
-
-queue.show.verdict=false
-
-ticker.rotate.time=1000
-ticker.logo=NEERC 2016;#NEERC2016
-ticker.logo.time=10000
-ticker.logo.change.time=2000
-
-overlayed.delay=3000
-
-width=1280
-height=720
-
-rate=10
-
-top.teams.file=pcms-test/topteams.txt
-onsite.teams=S.*
-
-stylesheet=stylesheets/wf.jss
diff --git a/config/_examples/_pcms-test/problems.xml b/config/_examples/_pcms-test/problems.xml
deleted file mode 100644
index 8c1dca878..000000000
--- a/config/_examples/_pcms-test/problems.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/_examples/_pcms-test/topteams.txt b/config/_examples/_pcms-test/topteams.txt
deleted file mode 100644
index b4224e06a..000000000
--- a/config/_examples/_pcms-test/topteams.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-S101
-S105
\ No newline at end of file
diff --git a/config/_examples/_testsys/advanced.json b/config/_examples/_testsys/advanced.json
new file mode 100644
index 000000000..6d53d5974
--- /dev/null
+++ b/config/_examples/_testsys/advanced.json
@@ -0,0 +1,23 @@
+{
+ "teamRegexes": {
+ "groupRegex": {
+ "outOfContest": "^\\(вк\\).*",
+ "firstGrade": "^\\(1к\\).*",
+ "school": "^\\(шк\\).*"
+ },
+ "customFields": {
+ "funnyName": "^(?:\\(..\\) )?(.*) \\([^)]*\\)"
+ }
+ },
+ "groupOverrides": {
+ "outOfContest": {
+ "isOutOfContest": true
+ }
+ },
+ "teamOverrideTemplate": {
+ "displayName": "{funnyName}"
+ },
+ "problemOverrides": {
+ "A": { "ordinal": 100 }
+ }
+}
\ No newline at end of file
diff --git a/config/_examples/_testsys/events.properties b/config/_examples/_testsys/events.properties
deleted file mode 100644
index 69ec7be9f..000000000
--- a/config/_examples/_testsys/events.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-standings.type=TESTSYS
-url=http://acm.math.spbu.ru/cgi-bin/view.pl/n201206.dat
\ No newline at end of file
diff --git a/config/_examples/_testsys/settings.json5 b/config/_examples/_testsys/settings.json5
new file mode 100644
index 000000000..f17d58f03
--- /dev/null
+++ b/config/_examples/_testsys/settings.json5
@@ -0,0 +1,5 @@
+{
+ // comment": "This line is ignored"
+ type: "testsys",
+ url: "http://acm.math.spbu.ru/cgi-bin/view.pl/n201206.dat",
+}
\ No newline at end of file
diff --git a/config/_examples/_yandex/events.properties b/config/_examples/_yandex/events.properties
deleted file mode 100644
index 49589ef18..000000000
--- a/config/_examples/_yandex/events.properties
+++ /dev/null
@@ -1,9 +0,0 @@
-# 1. Register an application here: https://oauth.yandex.ru/client/new
-# - Choose «Web services»
-# - Tap «Set URL for development»
-# - Add permission «Manage contests and participants (contest:manage)»
-# 2. Get «debug» token: https://yandex.ru/dev/id/doc/dg/oauth/tasks/get-oauth-token.html
-yandex.token=$creds.yandex
-yandex.contest_id=37430
-yandex.login_prefix=(^rucode5\-team\-0.*|^mw\-prefinals\-.*|^mrc2021\-.*)
-standings.type=YANDEX
diff --git a/config/_examples/_yandex/settings.json5 b/config/_examples/_yandex/settings.json5
new file mode 100644
index 000000000..12f7a2506
--- /dev/null
+++ b/config/_examples/_yandex/settings.json5
@@ -0,0 +1,13 @@
+{
+ /*
+ 1. Register an application here: https://oauth.yandex.ru/client/new
+ - Choose «Web services»
+ - Tap «Set URL for development»
+ - Add permission «Manage contests and participants (contest:manage)»
+ 2. Get «debug» token: https://yandex.ru/dev/id/doc/dg/oauth/tasks/get-oauth-token.html
+*/
+ type: "yandex",
+ apiKey: "$creds.yandex",
+ contestId: 37430,
+ loginRegex: "(^rucode5-team-0.*|^mw-prefinals-.*|^mrc2021-.*)",
+}
\ No newline at end of file
diff --git a/config/atcoder/abc317/advanced.json b/config/atcoder/abc317/advanced.json
new file mode 100644
index 000000000..5b07cfa3e
--- /dev/null
+++ b/config/atcoder/abc317/advanced.json
@@ -0,0 +1,11 @@
+{ "problemOverrides": {
+ "A": {"color": "#FF00FE"},
+ "B": {"color": "#FFFFFF"},
+ "C": {"color": "#9B01FF"},
+ "D": {"color": "#FE0000"},
+ "E": {"color": "#FFFF00"},
+ "F": {"color": "#0000FE"},
+ "G": {"color": "#761946"},
+ "Ex": {"color": "#04FF00"}
+ }
+}
\ No newline at end of file
diff --git a/config/atcoder/abc317/settings.json b/config/atcoder/abc317/settings.json
new file mode 100644
index 000000000..63e50bc23
--- /dev/null
+++ b/config/atcoder/abc317/settings.json
@@ -0,0 +1,7 @@
+{
+ "contestId": "abc317",
+ "type": "atcoder",
+ "startTime": "2023-08-26 08:00",
+ "contestLengthSeconds": 6000,
+ "sessionCookie": "$creds.atcoder_cookie"
+}
\ No newline at end of file
diff --git a/config/atcoder/wtf22-day1/advanced.json b/config/atcoder/wtf22-day1/advanced.json
new file mode 100644
index 000000000..1dfaf425f
--- /dev/null
+++ b/config/atcoder/wtf22-day1/advanced.json
@@ -0,0 +1,33 @@
+{
+ "problemOverrides": {
+ "wtf22_day1_a": {"color": "#FF00FE"},
+ "wtf22_day1_b": {"color": "#FFFFFF"},
+ "wtf22_day1_c": {"color": "#9B01FF"},
+ "wtf22_day1_d": {"color": "#FE0000"},
+ "wtf22_day1_e": {"color": "#FFFF00"}
+ },
+ "scoreboardOverrides": {
+ "medals": [
+ {"name": "gold", "count": 1},
+ {"name": "silver", "count": 1},
+ {"name": "bronze", "count": 1}
+ ]
+ },
+ "teamMediaTemplate": {
+ "achievement": {
+ "type": "Photo",
+ "url": "/media/achievement/{teamId}.svg"
+ }
+ },
+ "teamOverrides": {
+ "tourist": {"medias": {"camera": { "type": "WebRTCGrabberConnection", "url": "https://grabber.kbats.ru", "peerName": "001", "streamType": "webcam", "credential": "" }}},
+ "ecnerwala": {"medias": {"camera": { "type": "WebRTCGrabberConnection", "url": "https://grabber.kbats.ru", "peerName": "002", "streamType": "webcam", "credential": "" }}},
+ "ksun48": {"medias": {"camera": { "type": "WebRTCGrabberConnection", "url": "https://grabber.kbats.ru", "peerName": "004", "streamType": "webcam", "credential": "" }}},
+ "LHiC": {"medias": {"camera": { "type": "WebRTCGrabberConnection", "url": "https://grabber.kbats.ru", "peerName": "007", "streamType": "webcam", "credential": "" }}},
+ "mnbvmar": {"medias": {"camera": { "type": "WebRTCGrabberConnection", "url": "https://grabber.kbats.ru", "peerName": "008", "streamType": "webcam", "credential": "" }}},
+ "heno239": {"medias": {"camera": { "type": "WebRTCGrabberConnection", "url": "https://grabber.kbats.ru", "peerName": "014", "streamType": "webcam", "credential": "" }}},
+ "mulgokizary": {"medias": {"camera": { "type": "WebRTCGrabberConnection", "url": "https://grabber.kbats.ru", "peerName": "015", "streamType": "webcam", "credential": "" }}},
+ "Mr_Eight": {"medias": {"camera": { "type": "WebRTCGrabberConnection", "url": "https://grabber.kbats.ru", "peerName": "016", "streamType": "webcam", "credential": "" }}},
+ "zhoukangyang": {"medias": {"camera": { "type": "WebRTCGrabberConnection", "url": "https://grabber.kbats.ru", "peerName": "017", "streamType": "webcam", "credential": "" }}}
+ }
+}
\ No newline at end of file
diff --git a/config/atcoder/wtf22-day1/media/achievement/Benq.svg b/config/atcoder/wtf22-day1/media/achievement/Benq.svg
new file mode 100644
index 000000000..0d84580c2
--- /dev/null
+++ b/config/atcoder/wtf22-day1/media/achievement/Benq.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day1/media/achievement/LHiC.svg b/config/atcoder/wtf22-day1/media/achievement/LHiC.svg
new file mode 100644
index 000000000..d3bf1765d
--- /dev/null
+++ b/config/atcoder/wtf22-day1/media/achievement/LHiC.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day1/media/achievement/Mr_Eight.svg b/config/atcoder/wtf22-day1/media/achievement/Mr_Eight.svg
new file mode 100644
index 000000000..91afb0463
--- /dev/null
+++ b/config/atcoder/wtf22-day1/media/achievement/Mr_Eight.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day1/media/achievement/Petr.svg b/config/atcoder/wtf22-day1/media/achievement/Petr.svg
new file mode 100644
index 000000000..5193d2419
--- /dev/null
+++ b/config/atcoder/wtf22-day1/media/achievement/Petr.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day1/media/achievement/Stonefeang.svg b/config/atcoder/wtf22-day1/media/achievement/Stonefeang.svg
new file mode 100644
index 000000000..2039d4b5a
--- /dev/null
+++ b/config/atcoder/wtf22-day1/media/achievement/Stonefeang.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day1/media/achievement/Um_nik.svg b/config/atcoder/wtf22-day1/media/achievement/Um_nik.svg
new file mode 100644
index 000000000..cfad5ac35
--- /dev/null
+++ b/config/atcoder/wtf22-day1/media/achievement/Um_nik.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day1/media/achievement/apiad.svg b/config/atcoder/wtf22-day1/media/achievement/apiad.svg
new file mode 100644
index 000000000..e62e9528d
--- /dev/null
+++ b/config/atcoder/wtf22-day1/media/achievement/apiad.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day1/media/achievement/ecnerwala.svg b/config/atcoder/wtf22-day1/media/achievement/ecnerwala.svg
new file mode 100644
index 000000000..f48dcce7f
--- /dev/null
+++ b/config/atcoder/wtf22-day1/media/achievement/ecnerwala.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day1/media/achievement/endagorion.svg b/config/atcoder/wtf22-day1/media/achievement/endagorion.svg
new file mode 100644
index 000000000..5615f9648
--- /dev/null
+++ b/config/atcoder/wtf22-day1/media/achievement/endagorion.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day1/media/achievement/heno239.svg b/config/atcoder/wtf22-day1/media/achievement/heno239.svg
new file mode 100644
index 000000000..80a88f34d
--- /dev/null
+++ b/config/atcoder/wtf22-day1/media/achievement/heno239.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day1/media/achievement/jiangly.svg b/config/atcoder/wtf22-day1/media/achievement/jiangly.svg
new file mode 100644
index 000000000..cd0ce94ad
--- /dev/null
+++ b/config/atcoder/wtf22-day1/media/achievement/jiangly.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day1/media/achievement/ksun48.svg b/config/atcoder/wtf22-day1/media/achievement/ksun48.svg
new file mode 100644
index 000000000..d560f3b14
--- /dev/null
+++ b/config/atcoder/wtf22-day1/media/achievement/ksun48.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day1/media/achievement/mnbvmar.svg b/config/atcoder/wtf22-day1/media/achievement/mnbvmar.svg
new file mode 100644
index 000000000..a08a4cc17
--- /dev/null
+++ b/config/atcoder/wtf22-day1/media/achievement/mnbvmar.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day1/media/achievement/mulgokizary.svg b/config/atcoder/wtf22-day1/media/achievement/mulgokizary.svg
new file mode 100644
index 000000000..f0b97c035
--- /dev/null
+++ b/config/atcoder/wtf22-day1/media/achievement/mulgokizary.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day1/media/achievement/newbiedmy.svg b/config/atcoder/wtf22-day1/media/achievement/newbiedmy.svg
new file mode 100644
index 000000000..e1acae268
--- /dev/null
+++ b/config/atcoder/wtf22-day1/media/achievement/newbiedmy.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day1/media/achievement/peti1234.svg b/config/atcoder/wtf22-day1/media/achievement/peti1234.svg
new file mode 100644
index 000000000..d61344a12
--- /dev/null
+++ b/config/atcoder/wtf22-day1/media/achievement/peti1234.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day1/media/achievement/tourist.svg b/config/atcoder/wtf22-day1/media/achievement/tourist.svg
new file mode 100644
index 000000000..7c9207876
--- /dev/null
+++ b/config/atcoder/wtf22-day1/media/achievement/tourist.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day1/media/achievement/zhoukangyang.svg b/config/atcoder/wtf22-day1/media/achievement/zhoukangyang.svg
new file mode 100644
index 000000000..e4d278a51
--- /dev/null
+++ b/config/atcoder/wtf22-day1/media/achievement/zhoukangyang.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day1/settings.json b/config/atcoder/wtf22-day1/settings.json
new file mode 100644
index 000000000..7a3062545
--- /dev/null
+++ b/config/atcoder/wtf22-day1/settings.json
@@ -0,0 +1,7 @@
+{
+ "contestId": "wtf22-day1",
+ "type": "atcoder",
+ "startTime": "2023-09-08 13:00",
+ "contestLengthSeconds": 18000,
+ "sessionCookie": "$creds.atcoder_cookie"
+}
\ No newline at end of file
diff --git a/config/atcoder/wtf22-day2/advanced.json b/config/atcoder/wtf22-day2/advanced.json
new file mode 100644
index 000000000..cbe4503b9
--- /dev/null
+++ b/config/atcoder/wtf22-day2/advanced.json
@@ -0,0 +1,33 @@
+{
+ "problemOverrides": {
+ "wtf22_day2_a": {"color": "#FF00FE"},
+ "wtf22_day2_b": {"color": "#FFFFFF"},
+ "wtf22_day2_c": {"color": "#9B01FF"},
+ "wtf22_day2_d": {"color": "#FE0000"},
+ "wtf22_day2_e": {"color": "#FFFF00"}
+ },
+ "scoreboardOverrides": {
+ "medals": [
+ {"name": "gold", "count": 1},
+ {"name": "silver", "count": 1},
+ {"name": "bronze", "count": 1}
+ ]
+ },
+ "teamMediaTemplate": {
+ "achievement": {
+ "type": "Photo",
+ "url": "/media/achievement/{teamId}.svg"
+ }
+ },
+ "teamOverrides": {
+ "tourist": {"medias": {"camera": { "type": "WebRTCGrabberConnection", "url": "https://grabber.kbats.ru", "peerName": "001", "streamType": "webcam", "credential": "" }}},
+ "ecnerwala": {"medias": {"camera": { "type": "WebRTCGrabberConnection", "url": "https://grabber.kbats.ru", "peerName": "002", "streamType": "webcam", "credential": "" }}},
+ "ksun48": {"medias": {"camera": { "type": "WebRTCGrabberConnection", "url": "https://grabber.kbats.ru", "peerName": "004", "streamType": "webcam", "credential": "" }}},
+ "LHiC": {"medias": {"camera": { "type": "WebRTCGrabberConnection", "url": "https://grabber.kbats.ru", "peerName": "007", "streamType": "webcam", "credential": "" }}},
+ "mnbvmar": {"medias": {"camera": { "type": "WebRTCGrabberConnection", "url": "https://grabber.kbats.ru", "peerName": "008", "streamType": "webcam", "credential": "" }}},
+ "heno239": {"medias": {"camera": { "type": "WebRTCGrabberConnection", "url": "https://grabber.kbats.ru", "peerName": "014", "streamType": "webcam", "credential": "" }}},
+ "mulgokizary": {"medias": {"camera": { "type": "WebRTCGrabberConnection", "url": "https://grabber.kbats.ru", "peerName": "015", "streamType": "webcam", "credential": "" }}},
+ "Mr_Eight": {"medias": {"camera": { "type": "WebRTCGrabberConnection", "url": "https://grabber.kbats.ru", "peerName": "016", "streamType": "webcam", "credential": "" }}},
+ "zhoukangyang": {"medias": {"camera": { "type": "WebRTCGrabberConnection", "url": "https://grabber.kbats.ru", "peerName": "017", "streamType": "webcam", "credential": "" }}}
+ }
+}
\ No newline at end of file
diff --git a/config/atcoder/wtf22-day2/media/achievement/Benq.svg b/config/atcoder/wtf22-day2/media/achievement/Benq.svg
new file mode 100644
index 000000000..0d84580c2
--- /dev/null
+++ b/config/atcoder/wtf22-day2/media/achievement/Benq.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day2/media/achievement/LHiC.svg b/config/atcoder/wtf22-day2/media/achievement/LHiC.svg
new file mode 100644
index 000000000..d3bf1765d
--- /dev/null
+++ b/config/atcoder/wtf22-day2/media/achievement/LHiC.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day2/media/achievement/Mr_Eight.svg b/config/atcoder/wtf22-day2/media/achievement/Mr_Eight.svg
new file mode 100644
index 000000000..91afb0463
--- /dev/null
+++ b/config/atcoder/wtf22-day2/media/achievement/Mr_Eight.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day2/media/achievement/Petr.svg b/config/atcoder/wtf22-day2/media/achievement/Petr.svg
new file mode 100644
index 000000000..5193d2419
--- /dev/null
+++ b/config/atcoder/wtf22-day2/media/achievement/Petr.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day2/media/achievement/Stonefeang.svg b/config/atcoder/wtf22-day2/media/achievement/Stonefeang.svg
new file mode 100644
index 000000000..2039d4b5a
--- /dev/null
+++ b/config/atcoder/wtf22-day2/media/achievement/Stonefeang.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day2/media/achievement/Um_nik.svg b/config/atcoder/wtf22-day2/media/achievement/Um_nik.svg
new file mode 100644
index 000000000..cfad5ac35
--- /dev/null
+++ b/config/atcoder/wtf22-day2/media/achievement/Um_nik.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day2/media/achievement/apiad.svg b/config/atcoder/wtf22-day2/media/achievement/apiad.svg
new file mode 100644
index 000000000..e62e9528d
--- /dev/null
+++ b/config/atcoder/wtf22-day2/media/achievement/apiad.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day2/media/achievement/ecnerwala.svg b/config/atcoder/wtf22-day2/media/achievement/ecnerwala.svg
new file mode 100644
index 000000000..f48dcce7f
--- /dev/null
+++ b/config/atcoder/wtf22-day2/media/achievement/ecnerwala.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day2/media/achievement/endagorion.svg b/config/atcoder/wtf22-day2/media/achievement/endagorion.svg
new file mode 100644
index 000000000..5615f9648
--- /dev/null
+++ b/config/atcoder/wtf22-day2/media/achievement/endagorion.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day2/media/achievement/heno239.svg b/config/atcoder/wtf22-day2/media/achievement/heno239.svg
new file mode 100644
index 000000000..80a88f34d
--- /dev/null
+++ b/config/atcoder/wtf22-day2/media/achievement/heno239.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day2/media/achievement/jiangly.svg b/config/atcoder/wtf22-day2/media/achievement/jiangly.svg
new file mode 100644
index 000000000..cd0ce94ad
--- /dev/null
+++ b/config/atcoder/wtf22-day2/media/achievement/jiangly.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day2/media/achievement/ksun48.svg b/config/atcoder/wtf22-day2/media/achievement/ksun48.svg
new file mode 100644
index 000000000..d560f3b14
--- /dev/null
+++ b/config/atcoder/wtf22-day2/media/achievement/ksun48.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day2/media/achievement/mnbvmar.svg b/config/atcoder/wtf22-day2/media/achievement/mnbvmar.svg
new file mode 100644
index 000000000..a08a4cc17
--- /dev/null
+++ b/config/atcoder/wtf22-day2/media/achievement/mnbvmar.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day2/media/achievement/mulgokizary.svg b/config/atcoder/wtf22-day2/media/achievement/mulgokizary.svg
new file mode 100644
index 000000000..f0b97c035
--- /dev/null
+++ b/config/atcoder/wtf22-day2/media/achievement/mulgokizary.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day2/media/achievement/newbiedmy.svg b/config/atcoder/wtf22-day2/media/achievement/newbiedmy.svg
new file mode 100644
index 000000000..e1acae268
--- /dev/null
+++ b/config/atcoder/wtf22-day2/media/achievement/newbiedmy.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day2/media/achievement/peti1234.svg b/config/atcoder/wtf22-day2/media/achievement/peti1234.svg
new file mode 100644
index 000000000..d61344a12
--- /dev/null
+++ b/config/atcoder/wtf22-day2/media/achievement/peti1234.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day2/media/achievement/tourist.svg b/config/atcoder/wtf22-day2/media/achievement/tourist.svg
new file mode 100644
index 000000000..7c9207876
--- /dev/null
+++ b/config/atcoder/wtf22-day2/media/achievement/tourist.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day2/media/achievement/zhoukangyang.svg b/config/atcoder/wtf22-day2/media/achievement/zhoukangyang.svg
new file mode 100644
index 000000000..e4d278a51
--- /dev/null
+++ b/config/atcoder/wtf22-day2/media/achievement/zhoukangyang.svg
@@ -0,0 +1,45 @@
+
diff --git a/config/atcoder/wtf22-day2/settings.json b/config/atcoder/wtf22-day2/settings.json
new file mode 100644
index 000000000..3617df76d
--- /dev/null
+++ b/config/atcoder/wtf22-day2/settings.json
@@ -0,0 +1,7 @@
+{
+ "contestId": "wtf22-day2",
+ "type": "atcoder",
+ "startTime": "2023-09-09 13:00",
+ "contestLengthSeconds": 18000,
+ "sessionCookie": "$creds.atcoder_cookie"
+}
\ No newline at end of file
diff --git a/config/bsuir/2022/events.properties b/config/bsuir/2022/events.properties
deleted file mode 100644
index ba56e3dce..000000000
--- a/config/bsuir/2022/events.properties
+++ /dev/null
@@ -1,10 +0,0 @@
-# 1. Register an application here: https://oauth.yandex.ru
-# - Choose Web services
-# - Tap Set URL for development
-# - Add permission Yandex Contest -> Send and evaluate submissions in contests (contest:submit)
-# 2. Get debug token: https://yandex.ru/dev/id/doc/dg/oauth/tasks/get-oauth-token.html
-
-yandex.token=$creds.yandex
-yandex.contest_id=37013
-yandex.login_prefix=(^open-x-reload-.*)
-standings.type=YANDEX
\ No newline at end of file
diff --git a/config/bsuir/2022/settings.json b/config/bsuir/2022/settings.json
new file mode 100644
index 000000000..0d6eae968
--- /dev/null
+++ b/config/bsuir/2022/settings.json
@@ -0,0 +1,8 @@
+{
+ "type": "yandex",
+ "apiKey": "$creds.yandex",
+ "contestId": 37013,
+ "loginRegex": "^open-x-reload-.*"
+}
+
+
diff --git a/config/ceoi/2022/advanced.json b/config/ceoi/2022/advanced.json
new file mode 100644
index 000000000..93b934890
--- /dev/null
+++ b/config/ceoi/2022/advanced.json
@@ -0,0 +1,44 @@
+{
+ "problemOverrides": {
+ "SC2022CEOI13prize": {
+ "displayName": "A1"
+ },
+ "SC2022CEOI11abracadabra": {
+ "displayName": "B1"
+ },
+ "SC2022CEOI12homework": {
+ "displayName": "C1"
+ },
+ "SC2022CEOI22measures": {
+ "displayName": "A2"
+ },
+ "SC2022CEOI21drawing": {
+ "displayName": "B2"
+ },
+ "SC2022CEOI23parking": {
+ "displayName": "C2"
+ }
+ },
+ "scoreboardOverrides": {
+ "medals": [
+ {
+ "name": "gold",
+ "count": 5,
+ "tiebreakMode": "ALL"
+ },
+ {
+ "name": "silver",
+ "count": 8,
+ "tiebreakMode": "ALL"
+ },
+ {
+ "name": "bronze",
+ "count": 12,
+ "tiebreakMode": "NONE"
+ }
+ ]
+ },
+ "teamOverrideTemplate": {
+ "displayName": "[{country}] {first_name} {last_name}"
+ }
+}
\ No newline at end of file
diff --git a/config/ceoi/2022/settings.json b/config/ceoi/2022/settings.json
new file mode 100644
index 000000000..1bedcc8a4
--- /dev/null
+++ b/config/ceoi/2022/settings.json
@@ -0,0 +1,10 @@
+{
+ "type": "cms",
+ "activeContest": "ceoi22_5f2",
+ "otherContests": ["ceoi22_5f1"],
+ "url": "https://ceoi.hsin.hr/ranking/",
+ "emulation": {
+ "speed": 3,
+ "startTime": "now"
+ }
+ }
\ No newline at end of file
diff --git a/config/cf/1778/events.properties b/config/cf/1778/events.properties
deleted file mode 100644
index 6975ee29a..000000000
--- a/config/cf/1778/events.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-cf.api.key=$creds.codeforces_key
-cf.api.secret=$creds.codeforces_secret
-contest_id=1778
-standings.type=CF
diff --git a/config/cf/1778/settings.json b/config/cf/1778/settings.json
new file mode 100644
index 000000000..9863a3d9d
--- /dev/null
+++ b/config/cf/1778/settings.json
@@ -0,0 +1,6 @@
+{
+ "type": "cf",
+ "apiKey": "$creds.codeforces_key",
+ "apiSecret": "$creds.codeforces_secret",
+ "contestId": 1778
+}
\ No newline at end of file
diff --git a/config/chu/2023/d1/events.properties b/config/chu/2023/d1/events.properties
deleted file mode 100644
index a80fb42fe..000000000
--- a/config/chu/2023/d1/events.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-standings.type=EJUDGE
-url=https://timus.online/admin/spacelog.aspx/log-2.xml?space=1499&action=getejudgelog
-timusSessionId=123
\ No newline at end of file
diff --git a/config/chu/2023/d1/settings.json b/config/chu/2023/d1/settings.json
new file mode 100644
index 000000000..4de6886be
--- /dev/null
+++ b/config/chu/2023/d1/settings.json
@@ -0,0 +1,5 @@
+{
+ "type":"ejudge",
+ "url":"https://timus.online/admin/spacelog.aspx/log-2.xml?space=1499&action=getejudgelog",
+ "#timusSessionId":"123"
+}
\ No newline at end of file
diff --git a/config/chu/2023/d2/events.properties b/config/chu/2023/d2/events.properties
deleted file mode 100644
index 22cbfe2b8..000000000
--- a/config/chu/2023/d2/events.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-standings.type=EJUDGE
-url=https://timus.online/admin/spacelog.aspx/log-2.xml?space=1500&action=getejudgelog
-timusSessionId=123
\ No newline at end of file
diff --git a/config/chu/2023/d2/settings.json b/config/chu/2023/d2/settings.json
new file mode 100644
index 000000000..5eb882881
--- /dev/null
+++ b/config/chu/2023/d2/settings.json
@@ -0,0 +1,5 @@
+{
+ "type":"ejudge",
+ "url":"https://timus.online/admin/spacelog.aspx/log-2.xml?space=1500&action=getejudgelog",
+ "#timusSessionId":"123"
+}
\ No newline at end of file
diff --git a/config/chu/2023/dress/events.properties b/config/chu/2023/dress/events.properties
deleted file mode 100644
index 7955cc2b0..000000000
--- a/config/chu/2023/dress/events.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-standings.type=EJUDGE
-url=https://timus.online/admin/spacelog.aspx/log-2.xml?space=1498&action=getejudgelog
-timusSessionId=123
\ No newline at end of file
diff --git a/config/chu/2023/dress/settings.json b/config/chu/2023/dress/settings.json
new file mode 100644
index 000000000..383e5b155
--- /dev/null
+++ b/config/chu/2023/dress/settings.json
@@ -0,0 +1,5 @@
+{
+ "type":"ejudge",
+ "url":"https://timus.online/admin/spacelog.aspx/log-2.xml?space=1498&action=getejudgelog",
+ "#timusSessionId":"123"
+}
\ No newline at end of file
diff --git a/config/code-work/2023/main-tour/advanced.json b/config/code-work/2023/main-tour/advanced.json
index 6e2ac11e7..dbea2f3bf 100644
--- a/config/code-work/2023/main-tour/advanced.json
+++ b/config/code-work/2023/main-tour/advanced.json
@@ -41,4 +41,4 @@
"color": "#45BEC6"
}
}
-},
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/config/code-work/2023/main-tour/events.properties b/config/code-work/2023/main-tour/events.properties
deleted file mode 100644
index 574afc1af..000000000
--- a/config/code-work/2023/main-tour/events.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-url=https://imcs.dvfu.ru/cats
-cid=6715954
-standings.type=CATS
-timezone=UTC+10
-standings.resultType=ICPC
-login=$creds.cats.login
-password=$creds.cats.password
diff --git a/config/code-work/2023/main-tour/settings.json b/config/code-work/2023/main-tour/settings.json
new file mode 100644
index 000000000..52db22cde
--- /dev/null
+++ b/config/code-work/2023/main-tour/settings.json
@@ -0,0 +1,9 @@
+{
+ "type":"cats",
+ "url":"https://imcs.dvfu.ru/cats",
+ "cid":"6715954",
+ "timeZone":"UTC+10",
+ "resultType":"ICPC",
+ "login":"$creds.cats_login",
+ "password":"$creds.cats_password"
+}
\ No newline at end of file
diff --git a/config/code-work/2023/test/events.properties b/config/code-work/2023/test/events.properties
deleted file mode 100644
index 31f040ef0..000000000
--- a/config/code-work/2023/test/events.properties
+++ /dev/null
@@ -1,10 +0,0 @@
-url=https://imcs.dvfu.ru/cats
-cid=6715945
-standings.type=CATS
-timezone=UTC+9
-standings.resultType=ICPC
-login=$creds.cats.login
-password=$creds.cats.password
-
-emulation.speed=10
-emulation.startTime=now
diff --git a/config/code-work/2023/test/settings.json b/config/code-work/2023/test/settings.json
new file mode 100644
index 000000000..806988230
--- /dev/null
+++ b/config/code-work/2023/test/settings.json
@@ -0,0 +1,10 @@
+{
+ "type":"cats",
+ "url":"https://imcs.dvfu.ru/cats",
+ "cid":"6715945",
+ "timeZone":"UTC+10",
+ "resultType":"ICPC",
+ "login":"$creds.cats_login",
+ "password":"$creds.cats_password"
+}
+
diff --git a/config/code-work/2023/testTour/events.properties b/config/code-work/2023/testTour/events.properties
deleted file mode 100644
index 5460aac27..000000000
--- a/config/code-work/2023/testTour/events.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-url=https://imcs.dvfu.ru/cats
-cid=6747059
-standings.type=CATS
-timezone=UTC+9
-standings.resultType=ICPC
-login=$creds.cats.login
-password=$creds.cats.password
diff --git a/config/code-work/2023/testTour/settings.json b/config/code-work/2023/testTour/settings.json
new file mode 100644
index 000000000..df4910e91
--- /dev/null
+++ b/config/code-work/2023/testTour/settings.json
@@ -0,0 +1,10 @@
+{
+ "type":"cats",
+ "url":"https://imcs.dvfu.ru/cats",
+ "cid":"6747059",
+ "timeZone":"UTC+10",
+ "resultType":"ICPC",
+ "login":"$creds.cats_login",
+ "password":"$creds.cats_password"
+}
+
\ No newline at end of file
diff --git a/config/cpfed-kz/2023-singles/advanced.json b/config/cpfed-kz/2023-singles/advanced.json
new file mode 100644
index 000000000..dc43aaa4f
--- /dev/null
+++ b/config/cpfed-kz/2023-singles/advanced.json
@@ -0,0 +1,63 @@
+{
+
+ "problemOverrides": {
+ "A":{"color":"#e6194B"},
+ "B":{"color":"#3cb44b"},
+ "C":{"color":"#ffe119"},
+ "D":{"color":"#4363d8"},
+ "E":{"color":"#f58231"},
+ "F":{"color":"#42d4f4"},
+ "G":{"color":"#f032e6"},
+ "H":{"color":"#fabed4"},
+ "I":{"color":"#469990"}
+ },
+ "scoreboardOverrides": {
+ "medals": [
+ {"name": "gold", "count": 1},
+ {"name": "silver", "count": 3},
+ {"name": "bronze", "count": 11}
+ ]
+ },
+ "teamOverrides": {
+ "g20812=user01": {"groups": ["Алматы"]},
+ "g20812=user02": {"groups": ["Астана"]},
+ "g20812=user03": {"groups": ["Алматы"]},
+ "g20812=user04": {"groups": ["не в Казахстане"]},
+ "g20812=user05": {"groups": ["Астана"]},
+ "g20812=user06": {"groups": ["Астана"]},
+ "g20812=user07": {"groups": ["Алматы"]},
+ "g20812=user08": {"groups": ["Астана"]},
+ "g20812=user09": {"groups": ["Абайская область"]},
+ "g20812=user10": {"groups": ["Карагандинская область"]},
+ "g20812=user11": {"groups": ["Алматы"]},
+ "g20812=user12": {"groups": ["Алматы"]},
+ "g20812=user13": {"groups": ["Алматы"]},
+ "g20812=user14": {"groups": ["Астана"]},
+ "g20812=user15": {"groups": ["Астана"]},
+ "g20812=user16": {"groups": ["Алматы"]},
+ "g20812=user17": {"groups": ["не в Казахстане"]},
+ "g20812=user18": {"groups": ["Алматы"]},
+ "g20812=user19": {"groups": ["Алматы"]},
+ "g20812=user20": {"groups": ["Алматы"]},
+ "g20812=user21": {"groups": ["Алматы"]},
+ "g20812=user22": {"groups": ["Алматы"]},
+ "g20812=user23": {"groups": ["Алматы"]},
+ "g20812=user24": {"groups": ["Алматы"]},
+ "g20812=user25": {"groups": ["Алматы"]},
+ "g20812=user26": {"groups": ["не в Казахстане"]},
+ "g20812=user27": {"groups": ["Алматы"]},
+ "g20812=user28": {"groups": ["Астана"]},
+ "g20812=user29": {"groups": ["Алматы"]},
+ "g20812=user30": {"groups": ["Атырауская область"]},
+ "g20812=user31": {"groups": ["Мангистауская область"]},
+ "g20812=user32": {"groups": ["Алматинская область"]},
+ "g20812=user33": {"groups": ["Кызылординская область"]},
+ "g20812=user34": {"groups": ["Павлодарская область"]},
+ "g20812=user35": {"groups": ["Павлодарская область"]},
+ "g20812=user36": {"groups": ["Карагандинская область"]},
+ "g20812=user37": {"groups": ["Карагандинская область"]},
+ "g20812=user38": {"groups": ["Астана"]},
+ "g20812=user39": {"groups": ["Астана"]},
+ "g20812=user40": {"groups": ["Алматы"]}
+ }
+}
\ No newline at end of file
diff --git a/config/cpfed-kz/2023-singles/settings.json b/config/cpfed-kz/2023-singles/settings.json
new file mode 100644
index 000000000..e76bdba33
--- /dev/null
+++ b/config/cpfed-kz/2023-singles/settings.json
@@ -0,0 +1,7 @@
+{
+ "type": "cf",
+ "#comment":"Insert api key and secret from https://codeforces.com/settings/api below",
+ "apiKey": "$creds.codeforces_key",
+ "apiSecret": "$creds.codeforces_secret",
+ "contestId": 466369
+}
diff --git a/config/fed/2023-voronezh/advanced.json b/config/fed/2023-voronezh/advanced.json
index 83e3eeb22..58bd6ee65 100644
--- a/config/fed/2023-voronezh/advanced.json
+++ b/config/fed/2023-voronezh/advanced.json
@@ -1,218 +1,218 @@
{
- "startTime": "Thu Apr 27 10:50:00 MSK 2023",
+ "startTime": "2023-04-27 10:50:00",
"freezeTimeSeconds": 14400,
"teamOverrides": {
"7001": {
- "name": "ВолгГТУ 1 (Чупинин, Сафошкин, Олейников))",
- "shortname": "ВолгГТУ 1",
+ "fullName": "ВолгГТУ 1 (Чупинин, Сафошкин, Олейников))",
+ "displayName": "ВолгГТУ 1",
"groups": [
],
"medias": {
}
},
"7002": {
- "name": "ВолгГТУ 2 (Железняков, Ковальчук, Никонов)",
- "shortname": "ВолгГТУ 2",
+ "fullName": "ВолгГТУ 2 (Железняков, Ковальчук, Никонов)",
+ "displayName": "ВолгГТУ 2",
"groups": [
],
"medias": {
}
},
"7003": {
- "name": "УУНиТ (Парфенов, Татьянин, Зайцев)",
- "shortname": "УУНиТ",
+ "fullName": "УУНиТ (Парфенов, Татьянин, Зайцев)",
+ "displayName": "УУНиТ",
"groups": [
],
"medias": {
}
},
"7004": {
- "name": "ЮФУ (Жуйков, Лавшонок)",
- "shortname": "ЮФУ",
+ "fullName": "ЮФУ (Жуйков, Лавшонок)",
+ "displayName": "ЮФУ",
"groups": [
],
"medias": {
}
},
"7005": {
- "name": "СмолГУ (Гращенков, Солдатов, Моторин)",
- "shortname": "СмолГУ",
+ "fullName": "СмолГУ (Гращенков, Солдатов, Моторин)",
+ "displayName": "СмолГУ",
"groups": [
],
"medias": {
}
},
"7006": {
- "name": "ОрёлГУ (Каширин, Никулин, Яковлев)",
- "shortname": "ОрёлГУ",
+ "fullName": "ОрёлГУ (Каширин, Никулин, Яковлев)",
+ "displayName": "ОрёлГУ",
"groups": [
],
"medias": {
}
},
"7007": {
- "name": "СурГУ (Бородин, Куанчилеев, Бельтюков)",
- "shortname": "СурГУ",
+ "fullName": "СурГУ (Бородин, Куанчилеев, Бельтюков)",
+ "displayName": "СурГУ",
"groups": [
],
"medias": {
}
},
"7008": {
- "name": "ИТМО (Кутасин, Сенькин, Хритоненко)",
- "shortname": "ИТМО",
+ "fullName": "ИТМО (Кутасин, Сенькин, Хритоненко)",
+ "displayName": "ИТМО",
"groups": [
],
"medias": {
}
},
"7009": {
- "name": "ПенГУ 1 (Калугин, Свинарев, Кареев)",
- "shortname": "ПенГУ 1",
+ "fullName": "ПенГУ 1 (Калугин, Свинарев, Кареев)",
+ "displayName": "ПенГУ 1",
"groups": [
],
"medias": {
}
},
"7010": {
- "name": "ПенГУ 2 (Гришин, Дорофеев, Абузяров)",
- "shortname": "ПенГУ 2",
+ "fullName": "ПенГУ 2 (Гришин, Дорофеев, Абузяров)",
+ "displayName": "ПенГУ 2",
"groups": [
],
"medias": {
}
},
"7011": {
- "name": "ВУНЦ ВВА 1 (Ижан, Золотов, Орочко)",
- "shortname": "ВУНЦ ВВА 1",
+ "fullName": "ВУНЦ ВВА 1 (Ижан, Золотов, Орочко)",
+ "displayName": "ВУНЦ ВВА 1",
"groups": [
],
"medias": {
}
},
"7012": {
- "name": "ВУНЦ ВВА 2 (Порядин, Шемко, Шерстяных)",
- "shortname": "ВУНЦ ВВА 2",
+ "fullName": "ВУНЦ ВВА 2 (Порядин, Шемко, Шерстяных)",
+ "displayName": "ВУНЦ ВВА 2",
"groups": [
],
"medias": {
}
},
"7013": {
- "name": "ВГТУ 1 (Дедов, Цурихин, Чередников)",
- "shortname": "ВГТУ 1",
+ "fullName": "ВГТУ 1 (Дедов, Цурихин, Чередников)",
+ "displayName": "ВГТУ 1",
"groups": [
],
"medias": {
}
},
"7014": {
- "name": "ВГУ 1 (Бережнов, Новоточинов, Шишко)",
- "shortname": "ВГУ 1",
+ "fullName": "ВГУ 1 (Бережнов, Новоточинов, Шишко)",
+ "displayName": "ВГУ 1",
"groups": [
],
"medias": {
}
},
"7015": {
- "name": "ВГУ 2 (Скарга, Рогачёв, Улезько)",
- "shortname": "ВГУ 2",
+ "fullName": "ВГУ 2 (Скарга, Рогачёв, Улезько)",
+ "displayName": "ВГУ 2",
"groups": [
],
"medias": {
}
},
"7016": {
- "name": "МелГУ (Тимиров, Чепурной)",
- "shortname": "МелГУ",
+ "fullName": "МелГУ (Тимиров, Чепурной)",
+ "displayName": "МелГУ",
"groups": [
],
"medias": {
}
},
"7017": {
- "name": "Иннополис ИУ (Печерский, Хайруллин, Дюдин)",
- "shortname": "Иннополис ИУ",
+ "fullName": "Иннополис ИУ (Печерский, Хайруллин, Дюдин)",
+ "displayName": "Иннополис ИУ",
"groups": [
],
"medias": {
}
},
"7018": {
- "name": "ТверГУ (Герасимов, Дёмин, Новиков)",
- "shortname": "ТверГУ",
+ "fullName": "ТверГУ (Герасимов, Дёмин, Новиков)",
+ "displayName": "ТверГУ",
"groups": [
],
"medias": {
}
},
"7019": {
- "name": "МФТИ (Агох, Бобров, Дивильковский)",
- "shortname": "МФТИ",
+ "fullName": "МФТИ (Агох, Бобров, Дивильковский)",
+ "displayName": "МФТИ",
"groups": [
],
"medias": {
}
},
"7020": {
- "name": "СГУ (Родин, Москвитин, Сухова)",
- "shortname": "СГУ",
+ "fullName": "СГУ (Родин, Москвитин, Сухова)",
+ "displayName": "СГУ",
"groups": [
],
"medias": {
}
},
"7021": {
- "name": "РГРГУ (Харитонов, Воробьёв, Двойнин)",
- "shortname": "РГРГУ",
+ "fullName": "РГРГУ (Харитонов, Воробьёв, Двойнин)",
+ "displayName": "РГРГУ",
"groups": [
],
"medias": {
}
},
"7022": {
- "name": "ОГУ (Курынов, Белый, Сукманюк)",
- "shortname": "ОГУ",
+ "fullName": "ОГУ (Курынов, Белый, Сукманюк)",
+ "displayName": "ОГУ",
"groups": [
],
"medias": {
}
},
"7023": {
- "name": "НовГУ (Антонов, Тенькаев, Михайлов)",
- "shortname": "НовГУ",
+ "fullName": "НовГУ (Антонов, Тенькаев, Михайлов)",
+ "displayName": "НовГУ",
"groups": [
],
"medias": {
}
},
"7024": {
- "name": "МИСиС 1 (Лёвшин, Фёдоров, Шалимов)",
- "shortname": "МИСиС 1",
+ "fullName": "МИСиС 1 (Лёвшин, Фёдоров, Шалимов)",
+ "displayName": "МИСиС 1",
"groups": [
],
"medias": {
}
},
"7025": {
- "name": "МИСиС 2 (Акманов, Волков, Стрючков)",
- "shortname": "МИСиС 2",
+ "fullName": "МИСиС 2 (Акманов, Волков, Стрючков)",
+ "displayName": "МИСиС 2",
"groups": [
],
"medias": {
}
},
"7026": {
- "name": "МИФИ (Боголюбов, Гуков, Захаров)",
- "shortname": "МИФИ",
+ "fullName": "МИФИ (Боголюбов, Гуков, Захаров)",
+ "displayName": "МИФИ",
"groups": [
],
"medias": {
}
},
"7027": {
- "name": "ЧГУ (Уматкереев, Гишлакаев, Асабаев)",
- "shortname": "ЧГУ",
+ "fullName": "ЧГУ (Уматкереев, Гишлакаев, Асабаев)",
+ "displayName": "ЧГУ",
"groups": [
],
"medias": {
@@ -221,28 +221,28 @@
},
"problemOverrides": {
"A": {
- "name": "Аналитические выкладки"
+ "fullName": "Аналитические выкладки"
},
"B": {
- "name": "Бросаем на заказ"
+ "fullName": "Бросаем на заказ"
},
"C": {
- "name": "Выбор нумерации"
+ "fullName": "Выбор нумерации"
},
"D": {
- "name": "Гольф"
+ "fullName": "Гольф"
},
"E": {
- "name": "Двигайся оптимально"
+ "fullName": "Двигайся оптимально"
},
"F": {
- "name": "Есть ли простое продолжение?"
+ "fullName": "Есть ли простое продолжение?"
},
"G": {
- "name": "Ёлки... Забыл пароль..."
+ "fullName": "Ёлки... Забыл пароль..."
},
"H": {
- "name": "Журналистское расследование"
+ "fullName": "Журналистское расследование"
}
},
"scoreboardOverrides": {
diff --git a/config/fed/2023-voronezh/settings.json b/config/fed/2023-voronezh/settings.json
new file mode 100644
index 000000000..07c7c3f45
--- /dev/null
+++ b/config/fed/2023-voronezh/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"ejudge",
+ "url":"http://ioi-russia.vdi.mipt.ru/~ejudge/voronezh2023day1.xml"
+}
diff --git a/config/icpc-bapc/2022/events.properties b/config/icpc-bapc/2022/events.properties
deleted file mode 100644
index 29ae339d9..000000000
--- a/config/icpc-bapc/2022/events.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-login=$creds.login
-password=$creds.password
-url=https://cds.gehack.nl/api/contests/bapc2022
-standings.type=CLICS
diff --git a/config/icpc-bapc/2022/settings.json b/config/icpc-bapc/2022/settings.json
new file mode 100644
index 000000000..1d2821a86
--- /dev/null
+++ b/config/icpc-bapc/2022/settings.json
@@ -0,0 +1,6 @@
+{
+ "type":"clics",
+ "login":"$creds.login",
+ "password":"$creds.password",
+ "url":"https://cds.gehack.nl/api/contests/bapc2022"
+}
diff --git a/config/icpc-challenge/2022/events.properties b/config/icpc-challenge/2022/events.properties
deleted file mode 100644
index dbf48ee98..000000000
--- a/config/icpc-challenge/2022/events.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-cf.api.key=$creds.codeforces_key
-cf.api.secret=$creds.codeforces_secret
-contest_id=1757
-standings.type=CF
diff --git a/config/icpc-challenge/2022/settings.json b/config/icpc-challenge/2022/settings.json
new file mode 100644
index 000000000..d4206aa9a
--- /dev/null
+++ b/config/icpc-challenge/2022/settings.json
@@ -0,0 +1,6 @@
+{
+ "type": "cf",
+ "apiKey": "$creds.codeforces_key",
+ "apiSecret": "$creds.codeforces_secret",
+ "contestId": 1757
+}
diff --git a/config/icpc-challenge/2023-spring/events.properties b/config/icpc-challenge/2023-spring/events.properties
deleted file mode 100644
index 8d9c1cb44..000000000
--- a/config/icpc-challenge/2023-spring/events.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-cf.api.key=$creds.codeforces_key
-cf.api.secret=$creds.codeforces_secret
-contest_id=1813
-standings.type=CF
diff --git a/config/icpc-challenge/2023-spring/settings.json b/config/icpc-challenge/2023-spring/settings.json
new file mode 100644
index 000000000..ff45ad4f1
--- /dev/null
+++ b/config/icpc-challenge/2023-spring/settings.json
@@ -0,0 +1,6 @@
+{
+ "type": "cf",
+ "apiKey": "$creds.codeforces_key",
+ "apiSecret": "$creds.codeforces_secret",
+ "contestId": 1813
+}
\ No newline at end of file
diff --git a/config/icpc-mrc/2021/events.properties b/config/icpc-mrc/2021/events.properties
deleted file mode 100644
index b0600b1b0..000000000
--- a/config/icpc-mrc/2021/events.properties
+++ /dev/null
@@ -1,9 +0,0 @@
-# 1. Register an application here: https://oauth.yandex.ru
-# - Choose Web services
-# - Tap Set URL for development
-# - Add permission Yandex Contest -> Send and evaluate submissions in contests (contest:submit)
-# 2. Get debug token: https://yandex.ru/dev/id/doc/dg/oauth/tasks/get-oauth-token.html
-yandex.token=$creds.yandex
-yandex.contest_id=37430
-yandex.login_prefix=(^mrc2021-team.*)
-standings.type=YANDEX
\ No newline at end of file
diff --git a/config/icpc-mrc/2021/settings.json b/config/icpc-mrc/2021/settings.json
new file mode 100644
index 000000000..d168d926c
--- /dev/null
+++ b/config/icpc-mrc/2021/settings.json
@@ -0,0 +1,6 @@
+{
+ "type": "yandex",
+ "apiKey": "$creds.yandex",
+ "contestId": 37430,
+ "loginRegex": "(^mrc2021-team.*)"
+}
diff --git a/config/icpc-mrc/2022/events.properties b/config/icpc-mrc/2022/events.properties
deleted file mode 100644
index 18125236d..000000000
--- a/config/icpc-mrc/2022/events.properties
+++ /dev/null
@@ -1,9 +0,0 @@
-# 1. Register an application here: https://oauth.yandex.ru
-# - Choose Web services
-# - Tap Set URL for development
-# - Add permission Yandex Contest -> Send and evaluate submissions in contests (contest:submit)
-# 2. Get debug token: https://yandex.ru/dev/id/doc/dg/oauth/tasks/get-oauth-token.html
-yandex.token=$creds.yandex
-yandex.contest_id=42753
-yandex.login_prefix=(^mrc2022finals-.*)
-standings.type=YANDEX
\ No newline at end of file
diff --git a/config/icpc-mrc/2022/settings.json b/config/icpc-mrc/2022/settings.json
new file mode 100644
index 000000000..412530c95
--- /dev/null
+++ b/config/icpc-mrc/2022/settings.json
@@ -0,0 +1,6 @@
+{
+ "type": "yandex",
+ "apiKey": "$creds.yandex",
+ "contestId": 42753,
+ "loginRegex": "(^mrc2022finals-.*)"
+}
diff --git a/config/icpc-nac/2022/practice4/events.properties b/config/icpc-nac/2022/practice4/events.properties
deleted file mode 100644
index 131b57458..000000000
--- a/config/icpc-nac/2022/practice4/events.properties
+++ /dev/null
@@ -1,8 +0,0 @@
-login=$creds.kattis_login
-password=$creds.kattis_token
-url=https://open.kattis.com/clics-api/contests/nac22practice4
-standings.type=CLICS
-feed_version=2020_03
-
-#emulation.speed=10
-#emulation.startTime=now
\ No newline at end of file
diff --git a/config/icpc-nac/2022/practice4/settings.json b/config/icpc-nac/2022/practice4/settings.json
new file mode 100644
index 000000000..b3a1a59f5
--- /dev/null
+++ b/config/icpc-nac/2022/practice4/settings.json
@@ -0,0 +1,8 @@
+{
+ "login":"$creds.kattis_login",
+ "password":"$creds.kattis_token",
+ "url":"https://open.kattis.com/clics-api/contests/nac22practice4",
+ "type":"clics",
+ "feedVersion":"2020_03",
+ "emulation": { "speed": 10, "startTime": "now"}
+}
\ No newline at end of file
diff --git a/config/icpc-nac/2023/contest/events.properties b/config/icpc-nac/2023/contest/events.properties
deleted file mode 100644
index 1954f52e9..000000000
--- a/config/icpc-nac/2023/contest/events.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-login=$creds.cds_login
-password=$creds.cds_password
-url=https://10.3.3.207/api/contests/NAC-2023-real
-standings.type=CLICS
-use_team_names=false
-
-#media_base_url=http://10.3.3.207/api
\ No newline at end of file
diff --git a/config/icpc-nac/2023/contest/settings.json b/config/icpc-nac/2023/contest/settings.json
new file mode 100644
index 000000000..0a67829d5
--- /dev/null
+++ b/config/icpc-nac/2023/contest/settings.json
@@ -0,0 +1,9 @@
+{
+ "type":"clics",
+ "login":"$creds.cds_login",
+ "password":"$creds.cds_password",
+ "url":"https://10.3.3.207/api/contests/NAC-2023-real",
+ "useTeamNames":false,
+
+ "#media_base_url":"http://10.3.3.207/api"
+}
\ No newline at end of file
diff --git a/config/icpc-nac/2023/dr/events.properties b/config/icpc-nac/2023/dr/events.properties
deleted file mode 100644
index d69a087ff..000000000
--- a/config/icpc-nac/2023/dr/events.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-login=$creds.cds_login
-password=$creds.cds_password
-url=https://10.3.3.207/api/contests/NAC-2023-dress
-standings.type=CLICS
-use_team_names=false
-
-#media_base_url=http://10.3.3.207/api
\ No newline at end of file
diff --git a/config/icpc-nac/2023/dr/settings.json b/config/icpc-nac/2023/dr/settings.json
new file mode 100644
index 000000000..8d9c8ca8b
--- /dev/null
+++ b/config/icpc-nac/2023/dr/settings.json
@@ -0,0 +1,10 @@
+{
+ "type":"clics",
+ "login":"$creds.cds_login",
+ "password":"$creds.cds_password",
+ "url":"https://10.3.3.207/api/contests/NAC-2023-dress",
+ "useTeamNames": false,
+
+ "#media_base_url":"http://10.3.3.207/api"
+}
+
diff --git a/config/icpc-nac/2023/test1/events.properties b/config/icpc-nac/2023/test1/events.properties
deleted file mode 100644
index bf4007989..000000000
--- a/config/icpc-nac/2023/test1/events.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-login=$creds.cds_login
-password=$creds.cds_password
-url=https://10.3.3.207/api/contests/NAC-2023-test1
-standings.type=CLICS
-
-#emulation.speed=10
-#emulation.startTime=now
\ No newline at end of file
diff --git a/config/icpc-nac/2023/test1/settings.json b/config/icpc-nac/2023/test1/settings.json
new file mode 100644
index 000000000..b477b0a1f
--- /dev/null
+++ b/config/icpc-nac/2023/test1/settings.json
@@ -0,0 +1,8 @@
+{
+ "type": "clics",
+ "login": "$creds.cds_login",
+ "password": "$creds.cds_password",
+ "url": "https://10.3.3.207/api/contests/NAC-2023-test1",
+ "useTeamNames": false,
+ "#media_base_url": "http://10.3.3.207/api"
+}
diff --git a/config/icpc-nac/2023/test2/events.properties b/config/icpc-nac/2023/test2/events.properties
deleted file mode 100644
index d4d96005d..000000000
--- a/config/icpc-nac/2023/test2/events.properties
+++ /dev/null
@@ -1,8 +0,0 @@
-login=$creds.cds_login
-password=$creds.cds_password
-url=https://10.3.3.207/api/contests/NAC-2023-test2
-standings.type=CLICS
-media_base_url=http://10.3.3.207/api
-
-#emulation.speed=10
-#emulation.startTime=now
\ No newline at end of file
diff --git a/config/icpc-nac/2023/test2/settings.json b/config/icpc-nac/2023/test2/settings.json
new file mode 100644
index 000000000..20f8d8d74
--- /dev/null
+++ b/config/icpc-nac/2023/test2/settings.json
@@ -0,0 +1,10 @@
+{
+ "type":"clics",
+ "login":"$creds.cds_login",
+ "password":"$creds.cds_password",
+ "url":"https://10.3.3.207/api/contests/NAC-2023-test2",
+ "useTeamNames":false,
+
+ "#media_base_url":"http://10.3.3.207/api"
+}
+
diff --git a/config/icpc-nef/2016-2017/events.properties b/config/icpc-nef/2016-2017/events.properties
deleted file mode 100644
index cadf4903e..000000000
--- a/config/icpc-nef/2016-2017/events.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-login=test
-password=test
-url=http://neerc.ifmo.ru/information/standings.xml
-participants=parties.xml
-problems.url=problems.xml
-problemsNumber=3
-standings.type=PCMS
-
-contest.length=5400000
-#18000000
-freeze.time=14400000
\ No newline at end of file
diff --git a/config/icpc-nef/2016-2017/mainscreen.properties b/config/icpc-nef/2016-2017/mainscreen.properties
deleted file mode 100644
index 3a15ba66c..000000000
--- a/config/icpc-nef/2016-2017/mainscreen.properties
+++ /dev/null
@@ -1,40 +0,0 @@
-update.wait=1000
-backup.persons=persons.txt
-backup.advertisements=advertisements.txt
-breakingnews.time=20000
-breakingnews.runs.number=10
-breakingnews.patterns.filename=patterns.txt
-standings.blinking.time=10000
-advertisement.time=5000
-person.time=5000
-latency.time=2000
-data.update=1000
-data.host=192.168.1.181
-data.port=25675
-info.types=photo;screen
-main.type=photo
-info.photo=pics/team.jpg
-info.screen=http://192.168.0.8/%d/%d
-sleep.time=10000
-automated.show.time=20000
-automated.info=screen
-team.double.video=false
-
-queue.show.verdict=true
-
-ticker.rotate.time=10000
-ticker.logo=NEERC 2016;#NEERC
-ticker.logo.time=10000
-ticker.logo.change.time=10000
-
-overlayed.delay=3000
-
-width=1280
-height=720
-
-rate=25
-
-top.teams.file=neerc-2016/topteams.txt
-onsite.teams=S.*
-
-stylesheet=stylesheets/wf.jss
diff --git a/config/icpc-nef/2016-2017/problems.xml b/config/icpc-nef/2016-2017/problems.xml
deleted file mode 100644
index cf3136ad9..000000000
--- a/config/icpc-nef/2016-2017/problems.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/icpc-nef/2016-2017/settings.json b/config/icpc-nef/2016-2017/settings.json
new file mode 100644
index 000000000..5325c3837
--- /dev/null
+++ b/config/icpc-nef/2016-2017/settings.json
@@ -0,0 +1,5 @@
+{
+ "type":"pcms",
+ "url":"https://nerc.itmo.ru/archive/2016/standings.xml"
+}
+
diff --git a/config/icpc-nef/2016-2017/topteams.txt b/config/icpc-nef/2016-2017/topteams.txt
deleted file mode 100644
index f9e1cc9c1..000000000
--- a/config/icpc-nef/2016-2017/topteams.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-S520
-S502
\ No newline at end of file
diff --git a/config/icpc-nef/2017-2018/events.properties b/config/icpc-nef/2017-2018/events.properties
deleted file mode 100644
index eaf2ac6a8..000000000
--- a/config/icpc-nef/2017-2018/events.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-login=test
-password=test
-url=http://neerc.ifmo.ru/information/standings.xml
-teams.url=parties.xml
-problems.url=problems.xml
-problems.number=12
-standings.type=PCMS
-
-contest.length=18000000
-#18000000
-freeze.time=14400000
\ No newline at end of file
diff --git a/config/icpc-nef/2017-2018/mainscreen.properties b/config/icpc-nef/2017-2018/mainscreen.properties
deleted file mode 100644
index baa80ad43..000000000
--- a/config/icpc-nef/2017-2018/mainscreen.properties
+++ /dev/null
@@ -1,57 +0,0 @@
-update.wait=1000
-backup.persons=persons.txt
-backup.advertisements=advertisements.txt
-breakingnews.time=20000
-breakingnews.runs.number=10
-breakingnews.patterns.filename=patterns.txt
-standings.blinking.time=10000
-advertisement.time=5000
-person.time=5000
-latency.time=2000
-data.update=1000
-data.host=192.168.1.188
-data.port=25675
-info.types=screen
-main.type=screen
-info.screen=http://192.168.0.8/%d/%d
-sleep.time=10000
-automated.show.time=20000
-automated.info=screen
-team.double.video=false
-
-queue.show.verdict=true
-
-ticker.rotate.time=10000
-ticker.logo=#Clock#,NEERC 2017;#NEERC
-ticker.logo.time=5000
-ticker.clock.time=20000
-ticker.logo.change.time=1000
-
-overlayed.delay=3000
-
-width=1280
-height=720
-
-rate=25
-
-top.teams.file=neerc-2017/topteams.txt
-onsite.teams=S.*
-
-stylesheet=stylesheets/wf.jss
-
-polls.backup.file=polls.txt
-poll.show.time=20000
-poll.top.teams=5
-
-twitch.chat.server=irc.chat.twitch.tv
-twitch.chat.username=aksenov239
-twitch.chat.password=oauth:8yb7ygy3ey2wdwmlkvd7bs2o8guwf3
-twitch.chat.channel=#aksenov239;#icpclive1;#icpclive_ru
-
-twitter.hashtag=#NEERC2017
-
-word.statistics.backup.file=words-statistics.txt
-word.statistics.words=tweets
-word.statistics.tweets.text=$tweets$
-
-outputFile=d:/work/image.bin
diff --git a/config/icpc-nef/2017-2018/problems.xml b/config/icpc-nef/2017-2018/problems.xml
deleted file mode 100644
index 2056efdf0..000000000
--- a/config/icpc-nef/2017-2018/problems.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/icpc-nef/2017-2018/settings.json b/config/icpc-nef/2017-2018/settings.json
new file mode 100644
index 000000000..950322d55
--- /dev/null
+++ b/config/icpc-nef/2017-2018/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"pcms",
+ "url":"https://nerc.itmo.ru/archive/2017/standings.xml"
+}
diff --git a/config/icpc-nef/2017-2018/topteams.txt b/config/icpc-nef/2017-2018/topteams.txt
deleted file mode 100644
index f9e1cc9c1..000000000
--- a/config/icpc-nef/2017-2018/topteams.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-S520
-S502
\ No newline at end of file
diff --git a/config/icpc-nef/2018-2019/problems-practice.xml b/config/icpc-nef/2018-2019/problems-practice.xml
deleted file mode 100644
index 44dee15cf..000000000
--- a/config/icpc-nef/2018-2019/problems-practice.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/config/icpc-nef/2018-2019/problems.xml b/config/icpc-nef/2018-2019/problems.xml
deleted file mode 100644
index 2ecffb2ef..000000000
--- a/config/icpc-nef/2018-2019/problems.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/icpc-nef/2018-2019/settings.json b/config/icpc-nef/2018-2019/settings.json
new file mode 100644
index 000000000..4e34dd75f
--- /dev/null
+++ b/config/icpc-nef/2018-2019/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"pcms",
+ "url":"https://nerc.itmo.ru/archive/2018/standings.xml"
+}
diff --git a/config/icpc-nef/2020-2021/onsite/advanced.json b/config/icpc-nef/2020-2021/onsite/advanced.json
index 98d9c8dda..4ccfcf8cc 100644
--- a/config/icpc-nef/2020-2021/onsite/advanced.json
+++ b/config/icpc-nef/2020-2021/onsite/advanced.json
@@ -1,5 +1,5 @@
{
- "freezeTimeSeconds": 14400,
+ "freezeTimeSeconds": 18000,
"teamMediaTemplate": {
"screen": {
"type": "Video",
diff --git a/config/icpc-nef/2020-2021/onsite/events.properties b/config/icpc-nef/2020-2021/onsite/events.properties
deleted file mode 100644
index fd0552a5f..000000000
--- a/config/icpc-nef/2020-2021/onsite/events.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-url=http://nerc.itmo.ru/archive/2020/standings.xml
-#url=/nerc-onsite-2020/standings.xml
-standings.type=PCMS
-
-emulation.speed=10
-emulation.startTime=2023-05-28 13:50
-#emulation.startTime=now
diff --git a/config/icpc-nef/2020-2021/onsite/settings.json b/config/icpc-nef/2020-2021/onsite/settings.json
new file mode 100644
index 000000000..61c24ea9f
--- /dev/null
+++ b/config/icpc-nef/2020-2021/onsite/settings.json
@@ -0,0 +1,5 @@
+{
+ "type":"pcms",
+ "url":"https://nerc.itmo.ru/archive/2020/standings.xml"
+}
+
diff --git a/config/icpc-nef/2020-2021/onsite/social.properties b/config/icpc-nef/2020-2021/onsite/social.properties
deleted file mode 100644
index 8799c3e59..000000000
--- a/config/icpc-nef/2020-2021/onsite/social.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-twitch.chat.username=$creds.twitch_api_username
-twitch.chat.token=$creds.twitch_api_token
-twitch.chat.channel=#icpclive1;#icpclive_ru
\ No newline at end of file
diff --git a/config/icpc-nef/2021-2022/main/mainscreen.properties b/config/icpc-nef/2021-2022/main/mainscreen.properties
deleted file mode 100644
index 1cebdbf6c..000000000
--- a/config/icpc-nef/2021-2022/main/mainscreen.properties
+++ /dev/null
@@ -1,79 +0,0 @@
-#width=1280
-#height=720
-width=1920
-height=1080
-rate=25
-output.file=d:/work/image.bin
-output.mode=file
-#output.mode=window
-
-update.wait=500
-backup.persons=persons.txt
-backup.advertisements=advertisements.txt
-breakingnews.time=20000
-breakingnews.runs.number=10
-breakingnews.patterns.filename=patterns.txt
-standings.blinking.time=10000
-advertisement.time=50000
-person.time=50000
-latency.time=2000
-data.update=1000
-data.host=localhost
-data.port=25675
-
-info.types=screen;camera
-#info.screen=http://192.168.1.207:9080/video/screen/%d
-#info.camera=http://192.168.1.207:9080/video/camera/%d
-#info.record=http://192.168.1.207:9080/video/reaction/%d
-info.screen=http://192.168.18.38:80%02d
-info.camera=http://192.168.18.38:81%02d
-#info.camera=https://live:evMUzdqM@192.168.1.207/video/webcam/%s
-#info.video=teamVideos/%s.mp4
-#info.record=pics/team.jpg
-#info.types=photo;screen
-#info.video=teamVideos/%03d.mp4
-#pics/BigBuckBunny_320x180.mp4
-#pics/team.jpg
-#info.screen=pics/BigBuckBunny_320x180.mp4
-#pics/screen.png
-
-sleep.time=20000
-automated.show.time=40000
-automated.info=screen
-team.double.video=false
-
-ticker.rotate.time=10000
-ticker.logo=#Clock#;NERC 2020
-ticker.logo.time=5000
-ticker.clock.time=20000
-ticker.logo.change.time=1000
-
-queue.show.verdict=true
-
-overlayed.delay=3000
-
-top.teams=S077,S118,S113,S089,S128,S099,S012,S086,S007,S050,S121,S110,S062
-onsite.teams=.*
-
-stylesheet=stylesheets/wf.jss
-
-polls.backup.file=polls.txt
-poll.show.time=20000
-poll.top.teams=5
-
-twitch.chat.server=irc.chat.twitch.tv
-twitch.chat.username=aksenov239
-twitch.chat.password=oauth:8yb7ygy3ey2wdwmlkvd7bs2o8guwf3
-twitch.chat.channel=#aksenov239;#icpclive1;#icpclive_ru
-
-twitter.hashtag=#NERC2020
-
-word.statistics.backup.file=words-statistics.txt
-word.statistics.words=tweets;goose;energy
-word.statistics.tweets.text=$tweets$
-word.statistics.tweets.picture=
-word.statistics.goose.text=(*)>
-word.statistics.goose.picture=pics/goose.jpg
-word.statistics.energy.text=ί-- ??φ Π?_Π? ί-ι??φ
-word.statistics.energy.picture=pics/energy.jpg
-word.statistics.word.show.time=10000
diff --git a/config/icpc-nef/2021-2022/main/problems-practice.xml b/config/icpc-nef/2021-2022/main/problems-practice.xml
deleted file mode 100644
index 6b5adebef..000000000
--- a/config/icpc-nef/2021-2022/main/problems-practice.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/config/icpc-nef/2021-2022/main/problems.xml b/config/icpc-nef/2021-2022/main/problems.xml
deleted file mode 100644
index dd1e672f0..000000000
--- a/config/icpc-nef/2021-2022/main/problems.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/icpc-nef/2021-2022/main/settings.json b/config/icpc-nef/2021-2022/main/settings.json
new file mode 100644
index 000000000..deebe0508
--- /dev/null
+++ b/config/icpc-nef/2021-2022/main/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"pcms",
+ "url":"https://nerc.itmo.ru/archive/2021/standings.xml"
+}
diff --git a/config/icpc-nef/2021-2022/test/events.properties b/config/icpc-nef/2021-2022/test/events.properties
deleted file mode 100644
index d992d142d..000000000
--- a/config/icpc-nef/2021-2022/test/events.properties
+++ /dev/null
@@ -1,10 +0,0 @@
-url=https://nerc.itmo.ru/archive/2021/standings.xml
-teams.url=participants.xml
-problems.url=problems.xml
-standings.type=PCMS
-
-running.time=18000000
-freeze.time=14400000
-
-emulation.speed=5
-emulation.startTime=2022-05-28 10:10
diff --git a/config/icpc-nef/2021-2022/test/medals.properties b/config/icpc-nef/2021-2022/test/medals.properties
deleted file mode 100644
index 84efc971d..000000000
--- a/config/icpc-nef/2021-2022/test/medals.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-order=gold,silver,bronze
-gold.count=4
-silver.count=4
-bronze.count=4
\ No newline at end of file
diff --git a/config/icpc-nef/2021-2022/test/problems.xml b/config/icpc-nef/2021-2022/test/problems.xml
deleted file mode 100644
index dd1e672f0..000000000
--- a/config/icpc-nef/2021-2022/test/problems.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/icpc-nef/2021-2022/test/settings.json b/config/icpc-nef/2021-2022/test/settings.json
new file mode 100644
index 000000000..deebe0508
--- /dev/null
+++ b/config/icpc-nef/2021-2022/test/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"pcms",
+ "url":"https://nerc.itmo.ru/archive/2021/standings.xml"
+}
diff --git a/config/icpc-nef/2022-2023/settings.json b/config/icpc-nef/2022-2023/settings.json
new file mode 100644
index 000000000..4b0efb763
--- /dev/null
+++ b/config/icpc-nef/2022-2023/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"pcms",
+ "url":"https://nerc.itmo.ru/archive/2022/standings.xml"
+}
\ No newline at end of file
diff --git a/config/icpc-nwerc/2018/cds/events.properties b/config/icpc-nwerc/2018/cds/events.properties
deleted file mode 100644
index ca5507332..000000000
--- a/config/icpc-nwerc/2018/cds/events.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-login=$creds.nwerc18_login_cds
-password=$creds.nwerc18_password_cds
-url=https://cds.gehack.nl/api/contests/nwerc18
-standings.type=CLICS
\ No newline at end of file
diff --git a/config/icpc-nwerc/2018/cds/settings.json b/config/icpc-nwerc/2018/cds/settings.json
new file mode 100644
index 000000000..b5d873c91
--- /dev/null
+++ b/config/icpc-nwerc/2018/cds/settings.json
@@ -0,0 +1,6 @@
+{
+ "type":"clics",
+ "login":"$creds.nwerc18_login_cds",
+ "password":"$creds.nwerc18_password_cds",
+ "url":"https://cds.gehack.nl/api/contests/nwerc18"
+}
diff --git a/config/icpc-nwerc/2018/native/events.properties b/config/icpc-nwerc/2018/native/events.properties
deleted file mode 100644
index d820eb1e3..000000000
--- a/config/icpc-nwerc/2018/native/events.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-login=$creds.nwerc18_login
-password=$creds.nwerc18_password
-url=https://www.domjudge.org/demoweb/api/contests/nwerc18
-standings.type=CLICS
\ No newline at end of file
diff --git a/config/icpc-nwerc/2018/native/settings.json b/config/icpc-nwerc/2018/native/settings.json
new file mode 100644
index 000000000..4f5eb2dbb
--- /dev/null
+++ b/config/icpc-nwerc/2018/native/settings.json
@@ -0,0 +1,6 @@
+{
+ "type":"clics",
+ "login":"$creds.nwerc18_login",
+ "password":"$creds.nwerc18_password",
+ "url":"https://www.domjudge.org/demoweb/api/contests/nwerc18"
+}
\ No newline at end of file
diff --git a/config/icpc-nwerc/2019/events.properties b/config/icpc-nwerc/2019/events.properties
deleted file mode 100644
index fedf7f087..000000000
--- a/config/icpc-nwerc/2019/events.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-login=live
-password=monger-lawless-hymn-inhaler
-url=https://judge.gehack.nl:8443/api/contests/3
-standings.type=WFRegionals
diff --git a/config/icpc-nwerc/2019/mainscreen.properties b/config/icpc-nwerc/2019/mainscreen.properties
deleted file mode 100644
index f07d9bcab..000000000
--- a/config/icpc-nwerc/2019/mainscreen.properties
+++ /dev/null
@@ -1,81 +0,0 @@
-update.wait=500
-backup.persons=persons.txt
-backup.advertisements=advertisements.txt
-breakingnews.time=20000
-breakingnews.runs.number=10
-breakingnews.patterns.filename=patterns.txt
-standings.blinking.time=10000
-advertisement.time=5000
-person.time=5000
-latency.time=2000
-data.update=1000
-data.host=localhost
-data.port=25675
-
-info.types=screen;camera;video
-info.screen=http://live:cdspor41@192.168.1.207/video/desktop/%s
-info.camera=http://live:cdspor41@192.168.1.207/video/webcam/%s
-info.record=http://192.168.1.207:9080/video/reaction/%s
-#info.screen=pics/screen.png
-#info.camera=pics/team.jpg
-#info.record=pics/team.jpg
-#info.types=photo;screen
-info.video=D:\\work\\icpclive-2018\\teamVideos\\%s.mp4
-#pics/BigBuckBunny_320x180.mp4
-#pics/team.jpg
-#info.screen=pics/BigBuckBunny_320x180.mp4
-#pics/screen.png
-
-sleep.time=10000
-automated.show.time=20000
-automated.info=screen
-team.double.video=true
-
-ticker.rotate.time=10000
-ticker.logo=NWERC 2019;#NWERC2019
-ticker.logo.time=10000
-ticker.logo.change.time=2000
-
-queue.show.verdict=true
-
-overlayed.delay=3000
-
-width=1920
-height=1080
-rate=25
-
-top.teams=
-onsite.teams=.*
-
-stylesheet=stylesheets/wf.jss
-
-polls.backup.file=polls.txt
-poll.show.time=20000
-poll.top.teams=5
-poll.hashtag=#ICPC2019Vote
-
-twitch.chat.server=irc.chat.twitch.tv
-twitch.chat.username=aksenov239
-twitch.chat.password=oauth:8yb7ygy3ey2wdwmlkvd7bs2o8guwf3
-twitch.chat.channel=#aksenov239;#icpclive1;#icpclive_ru
-
-twitter.hashtag=#ICPC2019
-
-word.statistics.backup.file=words-statistics.txt
-word.statistics.words=tweets;goose;energy
-word.statistics.tweets.text=$tweets$
-word.statistics.tweets.picture=
-word.statistics.goose.text=(*)>
-word.statistics.goose.picture=pics/goose.jpg
-word.statistics.energy.text=ί-- ρ?φ Π_Π ί-ιρ?φ
-word.statistics.energy.picture=pics/energy.jpg
-word.statistics.word.show.time=10000
-
-backup.pictures=pictures.txt
-
-output.mode=file
-outputFile=c:/work/image.bin
-
-locator.cameras=10.250.25.111,10.250.25.112,10.250.25.113
-locator.inputfile=input.txt
-locator.coordinates=coordinates-1.txt,coordinates-2.txt,coordinates-3.txt
diff --git a/config/icpc-nwerc/2019/settings.json b/config/icpc-nwerc/2019/settings.json
new file mode 100644
index 000000000..e0628da69
--- /dev/null
+++ b/config/icpc-nwerc/2019/settings.json
@@ -0,0 +1,6 @@
+{
+ "type":"clics",
+ "login":"live",
+ "password":"monger-lawless-hymn-inhaler",
+ "url":"https://judge.gehack.nl:8443/api/contests/3"
+}
diff --git a/config/icpc-nwerc/2022/events.properties b/config/icpc-nwerc/2022/events.properties
deleted file mode 100644
index e3fe18ced..000000000
--- a/config/icpc-nwerc/2022/events.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-login=$creds.login
-password=$creds.password
-url=https://cds.chipcie.ch.tudelft.nl/api/contests/nwerc2022
-standings.type=CLICS
-media_base_url=https://cds.chipcie.ch.tudelft.nl/api
\ No newline at end of file
diff --git a/config/icpc-nwerc/2022/settings.json b/config/icpc-nwerc/2022/settings.json
new file mode 100644
index 000000000..caff37e1e
--- /dev/null
+++ b/config/icpc-nwerc/2022/settings.json
@@ -0,0 +1,7 @@
+{
+ "type":"clics",
+ "login":"$creds.login",
+ "password":"$creds.password",
+ "url":"https://cds.chipcie.ch.tudelft.nl/api/contests/nwerc2022",
+ "mediaBaseUrl":"https://cds.chipcie.ch.tudelft.nl/api"
+}
\ No newline at end of file
diff --git a/config/icpc-nwq/2021/events.properties b/config/icpc-nwq/2021/events.properties
deleted file mode 100644
index 7176e20ab..000000000
--- a/config/icpc-nwq/2021/events.properties
+++ /dev/null
@@ -1,10 +0,0 @@
-login=admin
-password=adm1n
-url=http://nerc.itmo.ru/archive/2021/northern/nwq-2021.xml
-teams.url=participants.xml
-problems.url=problems.xml
-problems.number=15
-standings.type=PCMS
-
-running.time=18000000
-freeze.time=14400000
diff --git a/config/icpc-nwq/2021/mainscreen.properties b/config/icpc-nwq/2021/mainscreen.properties
deleted file mode 100644
index 3cd2a7b56..000000000
--- a/config/icpc-nwq/2021/mainscreen.properties
+++ /dev/null
@@ -1,78 +0,0 @@
-#width=1280
-#height=720
-width=1920
-height=1080
-rate=25
-output.file=c:/work/image.bin
-output.mode=file
-#output.mode=window
-
-update.wait=500
-backup.persons=persons.txt
-backup.advertisements=advertisements.txt
-breakingnews.time=20000
-breakingnews.runs.number=10
-breakingnews.patterns.filename=patterns.txt
-standings.blinking.time=10000
-advertisement.time=50000
-person.time=50000
-latency.time=2000
-data.update=1000
-data.host=localhost
-data.port=25675
-
-info.types=screen;
-#info.screen=http://192.168.1.207:9080/video/screen/%d
-#info.camera=http://192.168.1.207:9080/video/camera/%d
-#info.record=http://192.168.1.207:9080/video/reaction/%d
-info.screen=http://192.168.0.8:8008/%d/%d
-#info.camera=https://live:evMUzdqM@192.168.1.207/video/webcam/%s
-#info.video=teamVideos/%s.mp4
-#info.record=pics/team.jpg
-#info.types=photo;screen
-#info.video=teamVideos/%03d.mp4
-#pics/BigBuckBunny_320x180.mp4
-#pics/team.jpg
-#info.screen=pics/BigBuckBunny_320x180.mp4
-#pics/screen.png
-
-sleep.time=20000
-automated.show.time=40000
-automated.info=screen
-team.double.video=false
-
-ticker.rotate.time=10000
-ticker.logo=#Clock#;NWQ2021
-ticker.logo.time=5000
-ticker.clock.time=20000
-ticker.logo.change.time=1000
-
-queue.show.verdict=true
-
-overlayed.delay=3000
-
-top.teams=101,111,306,105
-onsite.teams=.*
-
-stylesheet=stylesheets/wf.jss
-
-polls.backup.file=polls.txt
-poll.show.time=20000
-poll.top.teams=5
-
-twitch.chat.server=irc.chat.twitch.tv
-twitch.chat.username=aksenov239
-twitch.chat.password=oauth:8yb7ygy3ey2wdwmlkvd7bs2o8guwf3
-twitch.chat.channel=#aksenov239;#icpclive1;#icpclive_ru
-
-twitter.hashtag=#NWQ2021
-
-word.statistics.backup.file=words-statistics.txt
-word.statistics.words=tweets;goose;energy
-word.statistics.tweets.text=$tweets$
-word.statistics.tweets.picture=
-word.statistics.goose.text=(*)>
-word.statistics.goose.picture=pics/goose.jpg
-word.statistics.energy.text=ί-- ??φ Π?_Π? ί-ι??φ
-word.statistics.energy.picture=pics/energy.jpg
-word.statistics.word.show.time=10000
diff --git a/config/icpc-nwq/2021/problems b/config/icpc-nwq/2021/problems
deleted file mode 100644
index 8b1378917..000000000
--- a/config/icpc-nwq/2021/problems
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/config/icpc-nwq/2021/problems-practice.xml b/config/icpc-nwq/2021/problems-practice.xml
deleted file mode 100644
index ba533848a..000000000
--- a/config/icpc-nwq/2021/problems-practice.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/icpc-nwq/2021/problems.xml b/config/icpc-nwq/2021/problems.xml
deleted file mode 100644
index eecdfc3aa..000000000
--- a/config/icpc-nwq/2021/problems.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/icpc-nwq/2021/settings.json b/config/icpc-nwq/2021/settings.json
new file mode 100644
index 000000000..bcf9e3383
--- /dev/null
+++ b/config/icpc-nwq/2021/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"pcms",
+ "url":"http://nerc.itmo.ru/archive/2021/northern/nwq-2021.xml"
+}
diff --git a/config/icpc-nwq/2022/events.properties b/config/icpc-nwq/2022/events.properties
deleted file mode 100644
index 151241f39..000000000
--- a/config/icpc-nwq/2022/events.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-url=http://nerc.itmo.ru/archive/2022/northern/nwq-2022.xml
-standings.type=PCMS
-
diff --git a/config/icpc-nwq/2022/settings.json b/config/icpc-nwq/2022/settings.json
new file mode 100644
index 000000000..989ff9475
--- /dev/null
+++ b/config/icpc-nwq/2022/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"pcms",
+ "url":"http://nerc.itmo.ru/archive/2022/northern/nwq-2022.xml"
+}
diff --git a/config/icpc-nwrrc/2018/events.properties b/config/icpc-nwrrc/2018/events.properties
deleted file mode 100644
index 373fa4184..000000000
--- a/config/icpc-nwrrc/2018/events.properties
+++ /dev/null
@@ -1,10 +0,0 @@
-login=admin
-password=adm1n
-url=http://neerc.ifmo.ru/archive/2018/northern/standings.xml
-teams.url=participants.xml
-problems.url=problems.xml
-problems.number=12
-standings.type=PCMS
-
-running.time=18000000
-freeze.time=14400000
diff --git a/config/icpc-nwrrc/2018/mainscreen.properties b/config/icpc-nwrrc/2018/mainscreen.properties
deleted file mode 100644
index 083f305c3..000000000
--- a/config/icpc-nwrrc/2018/mainscreen.properties
+++ /dev/null
@@ -1,78 +0,0 @@
-#width=1280
-#height=720
-width=1920
-height=1080
-rate=25
-output.file=c:/work/image.bin
-output.mode=file
-#output.mode=window
-
-update.wait=500
-backup.persons=persons.txt
-backup.advertisements=advertisements.txt
-breakingnews.time=20000
-breakingnews.runs.number=10
-breakingnews.patterns.filename=patterns.txt
-standings.blinking.time=10000
-advertisement.time=50000
-person.time=50000
-latency.time=2000
-data.update=1000
-data.host=localhost
-data.port=25675
-
-info.types=screen;
-#info.screen=http://192.168.1.207:9080/video/screen/%d
-#info.camera=http://192.168.1.207:9080/video/camera/%d
-#info.record=http://192.168.1.207:9080/video/reaction/%d
-info.screen=http://192.168.0.8:8008/%d/%d
-#info.camera=https://live:evMUzdqM@192.168.1.207/video/webcam/%s
-#info.video=teamVideos/%s.mp4
-#info.record=pics/team.jpg
-#info.types=photo;screen
-#info.video=teamVideos/%03d.mp4
-#pics/BigBuckBunny_320x180.mp4
-#pics/team.jpg
-#info.screen=pics/BigBuckBunny_320x180.mp4
-#pics/screen.png
-
-sleep.time=20000
-automated.show.time=40000
-automated.info=screen
-team.double.video=false
-
-ticker.rotate.time=10000
-ticker.logo=#Clock#;NSNEERC 2018
-ticker.logo.time=5000
-ticker.clock.time=20000
-ticker.logo.change.time=1000
-
-queue.show.verdict=true
-
-overlayed.delay=3000
-
-top.teams=101,111,306,105
-onsite.teams=.*
-
-stylesheet=stylesheets/wf.jss
-
-polls.backup.file=polls.txt
-poll.show.time=20000
-poll.top.teams=5
-
-twitch.chat.server=irc.chat.twitch.tv
-twitch.chat.username=aksenov239
-twitch.chat.password=oauth:8yb7ygy3ey2wdwmlkvd7bs2o8guwf3
-twitch.chat.channel=#aksenov239;#icpclive1;#icpclive_ru
-
-twitter.hashtag=#NSNEERC2018
-
-word.statistics.backup.file=words-statistics.txt
-word.statistics.words=tweets;goose;energy
-word.statistics.tweets.text=$tweets$
-word.statistics.tweets.picture=
-word.statistics.goose.text=(*)>
-word.statistics.goose.picture=pics/goose.jpg
-word.statistics.energy.text=ί-- ??φ Π?_Π? ί-ι??φ
-word.statistics.energy.picture=pics/energy.jpg
-word.statistics.word.show.time=10000
diff --git a/config/icpc-nwrrc/2018/problems-practice.xml b/config/icpc-nwrrc/2018/problems-practice.xml
deleted file mode 100644
index 44dee15cf..000000000
--- a/config/icpc-nwrrc/2018/problems-practice.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/config/icpc-nwrrc/2018/problems.xml b/config/icpc-nwrrc/2018/problems.xml
deleted file mode 100644
index dfee9b0db..000000000
--- a/config/icpc-nwrrc/2018/problems.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/icpc-nwrrc/2018/settings.json b/config/icpc-nwrrc/2018/settings.json
new file mode 100644
index 000000000..73390c759
--- /dev/null
+++ b/config/icpc-nwrrc/2018/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"pcms",
+ "url":"http://neerc.ifmo.ru/archive/2018/northern/standings.xml"
+}
\ No newline at end of file
diff --git a/config/icpc-nwrrc/2019/events.properties b/config/icpc-nwrrc/2019/events.properties
deleted file mode 100644
index 3e710a248..000000000
--- a/config/icpc-nwrrc/2019/events.properties
+++ /dev/null
@@ -1,10 +0,0 @@
-login=admin
-password=adm1n
-url=http://neerc.ifmo.ru/archive/2019/northern/standings.xml
-teams.url=participants.xml
-problems.url=problems.xml
-problems.number=13
-standings.type=PCMS
-
-running.time=18000000
-freeze.time=14400000
diff --git a/config/icpc-nwrrc/2019/mainscreen.properties b/config/icpc-nwrrc/2019/mainscreen.properties
deleted file mode 100644
index 1b3a67815..000000000
--- a/config/icpc-nwrrc/2019/mainscreen.properties
+++ /dev/null
@@ -1,78 +0,0 @@
-#width=1280
-#height=720
-width=1920
-height=1080
-rate=25
-output.file=c:/work/image.bin
-output.mode=file
-#output.mode=window
-
-update.wait=500
-backup.persons=persons.txt
-backup.advertisements=advertisements.txt
-breakingnews.time=20000
-breakingnews.runs.number=10
-breakingnews.patterns.filename=patterns.txt
-standings.blinking.time=10000
-advertisement.time=50000
-person.time=50000
-latency.time=2000
-data.update=1000
-data.host=localhost
-data.port=25675
-
-info.types=screen;
-#info.screen=http://192.168.1.207:9080/video/screen/%d
-#info.camera=http://192.168.1.207:9080/video/camera/%d
-#info.record=http://192.168.1.207:9080/video/reaction/%d
-info.screen=http://192.168.0.8:8008/%d/%d
-#info.camera=https://live:evMUzdqM@192.168.1.207/video/webcam/%s
-#info.video=teamVideos/%s.mp4
-#info.record=pics/team.jpg
-#info.types=photo;screen
-#info.video=teamVideos/%03d.mp4
-#pics/BigBuckBunny_320x180.mp4
-#pics/team.jpg
-#info.screen=pics/BigBuckBunny_320x180.mp4
-#pics/screen.png
-
-sleep.time=20000
-automated.show.time=40000
-automated.info=screen
-team.double.video=false
-
-ticker.rotate.time=10000
-ticker.logo=#Clock#;NSNEERC 2019
-ticker.logo.time=5000
-ticker.clock.time=20000
-ticker.logo.change.time=1000
-
-queue.show.verdict=true
-
-overlayed.delay=3000
-
-top.teams=101,111,306,105
-onsite.teams=.*
-
-stylesheet=stylesheets/wf.jss
-
-polls.backup.file=polls.txt
-poll.show.time=20000
-poll.top.teams=5
-
-twitch.chat.server=irc.chat.twitch.tv
-twitch.chat.username=aksenov239
-twitch.chat.password=oauth:8yb7ygy3ey2wdwmlkvd7bs2o8guwf3
-twitch.chat.channel=#aksenov239;#icpclive1;#icpclive_ru
-
-twitter.hashtag=#NSNEERC2018
-
-word.statistics.backup.file=words-statistics.txt
-word.statistics.words=tweets;goose;energy
-word.statistics.tweets.text=$tweets$
-word.statistics.tweets.picture=
-word.statistics.goose.text=(*)>
-word.statistics.goose.picture=pics/goose.jpg
-word.statistics.energy.text=ί-- ??φ Π?_Π? ί-ι??φ
-word.statistics.energy.picture=pics/energy.jpg
-word.statistics.word.show.time=10000
diff --git a/config/icpc-nwrrc/2019/problems-practice.xml b/config/icpc-nwrrc/2019/problems-practice.xml
deleted file mode 100644
index 427d48937..000000000
--- a/config/icpc-nwrrc/2019/problems-practice.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
diff --git a/config/icpc-nwrrc/2019/problems.xml b/config/icpc-nwrrc/2019/problems.xml
deleted file mode 100644
index 2ecffb2ef..000000000
--- a/config/icpc-nwrrc/2019/problems.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/icpc-nwrrc/2019/settings.json b/config/icpc-nwrrc/2019/settings.json
new file mode 100644
index 000000000..719c43c1d
--- /dev/null
+++ b/config/icpc-nwrrc/2019/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"pcms",
+ "url":"http://neerc.ifmo.ru/archive/2019/northern/standings.xml"
+}
diff --git a/config/icpc-nwrrc/2020/events.properties b/config/icpc-nwrrc/2020/events.properties
deleted file mode 100644
index f4de4f8c5..000000000
--- a/config/icpc-nwrrc/2020/events.properties
+++ /dev/null
@@ -1,10 +0,0 @@
-login=admin
-password=adm1n
-url=http://nerc.itmo.ru/archive/2020/northern/standings.xml
-teams.url=participants.xml
-problems.url=problems-practice.xml
-problems.number=3
-standings.type=PCMS
-
-running.time=18000000
-freeze.time=14400000
diff --git a/config/icpc-nwrrc/2020/mainscreen.properties b/config/icpc-nwrrc/2020/mainscreen.properties
deleted file mode 100644
index 8466b4449..000000000
--- a/config/icpc-nwrrc/2020/mainscreen.properties
+++ /dev/null
@@ -1,78 +0,0 @@
-#width=1280
-#height=720
-width=1920
-height=1080
-rate=25
-output.file=d:/work/image.bin
-output.mode=file
-#output.mode=window
-
-update.wait=500
-backup.persons=persons.txt
-backup.advertisements=advertisements.txt
-breakingnews.time=20000
-breakingnews.runs.number=10
-breakingnews.patterns.filename=patterns.txt
-standings.blinking.time=10000
-advertisement.time=50000
-person.time=50000
-latency.time=2000
-data.update=1000
-data.host=localhost
-data.port=25675
-
-info.types=screen;
-#info.screen=http://192.168.1.207:9080/video/screen/%d
-#info.camera=http://192.168.1.207:9080/video/camera/%d
-#info.record=http://192.168.1.207:9080/video/reaction/%d
-info.screen=http://192.168.0.8:8008/%d/%d
-#info.camera=https://live:evMUzdqM@192.168.1.207/video/webcam/%s
-#info.video=teamVideos/%s.mp4
-#info.record=pics/team.jpg
-#info.types=photo;screen
-#info.video=teamVideos/%03d.mp4
-#pics/BigBuckBunny_320x180.mp4
-#pics/team.jpg
-#info.screen=pics/BigBuckBunny_320x180.mp4
-#pics/screen.png
-
-sleep.time=20000
-automated.show.time=40000
-automated.info=screen
-team.double.video=false
-
-ticker.rotate.time=10000
-ticker.logo=#Clock#;NWRRC2020
-ticker.logo.time=5000
-ticker.clock.time=20000
-ticker.logo.change.time=1000
-
-queue.show.verdict=true
-
-overlayed.delay=3000
-
-top.teams=101,111,306,105
-onsite.teams=.*
-
-stylesheet=stylesheets/wf.jss
-
-polls.backup.file=polls.txt
-poll.show.time=20000
-poll.top.teams=5
-
-twitch.chat.server=irc.chat.twitch.tv
-twitch.chat.username=aksenov239
-twitch.chat.password=oauth:8yb7ygy3ey2wdwmlkvd7bs2o8guwf3
-twitch.chat.channel=#aksenov239;#icpclive1;#icpclive_ru
-
-twitter.hashtag=#NWRRC2020
-
-word.statistics.backup.file=words-statistics.txt
-word.statistics.words=tweets;goose;energy
-word.statistics.tweets.text=$tweets$
-word.statistics.tweets.picture=
-word.statistics.goose.text=(*)>
-word.statistics.goose.picture=pics/goose.jpg
-word.statistics.energy.text=ί-- ??φ Π?_Π? ί-ι??φ
-word.statistics.energy.picture=pics/energy.jpg
-word.statistics.word.show.time=10000
diff --git a/config/icpc-nwrrc/2020/problems-practice.xml b/config/icpc-nwrrc/2020/problems-practice.xml
deleted file mode 100644
index 3da9fd2c1..000000000
--- a/config/icpc-nwrrc/2020/problems-practice.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/config/icpc-nwrrc/2020/problems.xml b/config/icpc-nwrrc/2020/problems.xml
deleted file mode 100644
index 6620b2032..000000000
--- a/config/icpc-nwrrc/2020/problems.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/icpc-nwrrc/2020/settings.json b/config/icpc-nwrrc/2020/settings.json
new file mode 100644
index 000000000..52a6b2f47
--- /dev/null
+++ b/config/icpc-nwrrc/2020/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"pcms",
+ "url":"http://nerc.itmo.ru/archive/2020/northern/standings.xml"
+}
\ No newline at end of file
diff --git a/config/icpc-nwrrc/2022/events.properties b/config/icpc-nwrrc/2022/events.properties
deleted file mode 100644
index 5d9cd6966..000000000
--- a/config/icpc-nwrrc/2022/events.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-url=http://nerc.itmo.ru/archive/2022/northern/standings.xml
-standings.type=PCMS
diff --git a/config/icpc-nwrrc/2022/settings.json b/config/icpc-nwrrc/2022/settings.json
new file mode 100644
index 000000000..c28468784
--- /dev/null
+++ b/config/icpc-nwrrc/2022/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"pcms",
+ "url":"http://nerc.itmo.ru/archive/2022/northern/standings.xml"
+}
\ No newline at end of file
diff --git a/config/icpc-rmc/2021/advanced.json b/config/icpc-rmc/2021/advanced.json
index 119443ad7..67fbe03a2 100644
--- a/config/icpc-rmc/2021/advanced.json
+++ b/config/icpc-rmc/2021/advanced.json
@@ -65,9 +65,11 @@
"O":{"color":"#000075"},
"P":{"color":"#a9a9a9"}
},
- "medals": [
- {"name": "gold", "count": 4},
- {"name": "silver", "count": 4},
- {"name": "bronze", "count": 4}
- ]
+ "scoreboardOverrides": {
+ "medals": [
+ {"name": "gold", "count": 4},
+ {"name": "silver", "count": 4},
+ {"name": "bronze", "count": 4}
+ ]
+ }
}
\ No newline at end of file
diff --git a/config/icpc-rmc/2021/events.properties b/config/icpc-rmc/2021/events.properties
deleted file mode 100644
index 17f9c02ee..000000000
--- a/config/icpc-rmc/2021/events.properties
+++ /dev/null
@@ -1,8 +0,0 @@
-login=$creds.kattis_login
-password=$creds.kattis_token
-url=https://open.kattis.com/clics-api/contests/rmc21
-standings.type=CLICS
-feed_version=2020_03
-
-emulation.startTime=2022-05-11 22:40
-emulation.speed=5
\ No newline at end of file
diff --git a/config/icpc-rmc/2021/settings.json b/config/icpc-rmc/2021/settings.json
new file mode 100644
index 000000000..973e0e6bf
--- /dev/null
+++ b/config/icpc-rmc/2021/settings.json
@@ -0,0 +1,9 @@
+{
+ "type":"clics",
+ "login":"$creds.kattis_login",
+ "password":"$creds.kattis_token",
+ "url":"https://open.kattis.com/clics-api/contests/rmc21",
+ "feedVersion":"2020_03",
+
+ "emulation":{"speed":5,"startTime":"2022-05-11 22:40"}
+}
\ No newline at end of file
diff --git a/config/icpc-southern-rc/events.properties b/config/icpc-southern-rc/events.properties
deleted file mode 100644
index e521fe08d..000000000
--- a/config/icpc-southern-rc/events.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-url=https://contest.sgu.ru/api/standings/1
-standings.type=PCMS
diff --git a/config/icpc-southern-rc/settings.json b/config/icpc-southern-rc/settings.json
new file mode 100644
index 000000000..571ede954
--- /dev/null
+++ b/config/icpc-southern-rc/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"pcms",
+ "url":"https://contest.sgu.ru/api/standings/1"
+}
diff --git a/config/icpc-swerc/2021/dress/events.properties b/config/icpc-swerc/2021/dress/events.properties
deleted file mode 100644
index bda8c2647..000000000
--- a/config/icpc-swerc/2021/dress/events.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-login=live
-password=SECRET
-url=https://cds.swerc.eu/api/contests/demo
-standings.type=CLICS
-feed_version=2020_03
\ No newline at end of file
diff --git a/config/icpc-swerc/2021/dress/settings.json b/config/icpc-swerc/2021/dress/settings.json
new file mode 100644
index 000000000..ddad5f045
--- /dev/null
+++ b/config/icpc-swerc/2021/dress/settings.json
@@ -0,0 +1,7 @@
+{
+ "type":"clics",
+ "login":"live",
+ "password":"SECRET",
+ "url":"https://cds.swerc.eu/api/contests/demo",
+ "feedVersion":"2020_03"
+}
\ No newline at end of file
diff --git a/config/vkcup/2022/final/events.properties b/config/icpc-swerc/2022/mirror/events.properties
similarity index 85%
rename from config/vkcup/2022/final/events.properties
rename to config/icpc-swerc/2022/mirror/events.properties
index a87629ebb..5f8535e4c 100644
--- a/config/vkcup/2022/final/events.properties
+++ b/config/icpc-swerc/2022/mirror/events.properties
@@ -1,5 +1,5 @@
cf.api.key=$creds.codeforces_key
cf.api.secret=$creds.codeforces_secret
-contest_id=1784
+contest_id=1776
standings.type=CF
diff --git a/config/icpc-wf/2020/advanced.json b/config/icpc-wf/2020/advanced.json
index 0aaa5812f..cef254bda 100644
--- a/config/icpc-wf/2020/advanced.json
+++ b/config/icpc-wf/2020/advanced.json
@@ -3,6 +3,10 @@
"showTeamsWithoutSubmissions": true
},
"teamMediaTemplate": {
+ "photo": {
+ "type": "Photo",
+ "url": "http://localhost:8080/media/photos/{teamId}.jpg"
+ },
"screen": {
"type": "Photo",
"url": "http://localhost:8080/media/screen/screen{teamId}.svg"
diff --git a/config/icpc-wf/2020/events.properties b/config/icpc-wf/2020/events.properties
deleted file mode 100644
index 35e56e0c6..000000000
--- a/config/icpc-wf/2020/events.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-standings.type=CLICS
-url=icpc-wf/2020
-emulation.speed=10
-emulation.startTime=now
-feed_version=2020_03
-use_team_names=false
diff --git a/config/icpc-wf/2020/settings.json b/config/icpc-wf/2020/settings.json
new file mode 100644
index 000000000..b087b5290
--- /dev/null
+++ b/config/icpc-wf/2020/settings.json
@@ -0,0 +1,10 @@
+{
+ "type": "clics",
+ "url": "icpc-wf/2020",
+ "useTeamNames": false,
+ "feedVersion": "2020_03",
+ "emulation": {
+ "speed": 10,
+ "startTime": "now"
+ }
+}
diff --git a/config/icpc-wf/2021/finals/media/animation-bouncing-icpclive-logo.svg b/config/icpc-wf/2021/finals/media/animation-bouncing-icpclive-logo.svg
new file mode 100644
index 000000000..ccff58c2d
--- /dev/null
+++ b/config/icpc-wf/2021/finals/media/animation-bouncing-icpclive-logo.svg
@@ -0,0 +1,19 @@
+
\ No newline at end of file
diff --git a/config/icpc-wf/2021/finals/presets/title.json b/config/icpc-wf/2021/finals/presets/title.json
index ab1a26e26..32970e2e0 100644
--- a/config/icpc-wf/2021/finals/presets/title.json
+++ b/config/icpc-wf/2021/finals/presets/title.json
@@ -88,5 +88,18 @@
"data": {
"t": "University of Warsaw"
}
+ },
+ {
+ "preset": "animation-dynamic-right.svg",
+ "data": {
+ "name": "Azat Ismagiov",
+ "role": "bebra aboba"
+ }
+ },
+ {
+ "preset": "animation-bouncing-icpclive-logo.svg",
+ "data": {
+ "url": "https://avatars.githubusercontent.com/u/5224374?v=4"
+ }
}
]
\ No newline at end of file
diff --git a/config/innopolis-open/2022-2023/final/settings.json b/config/innopolis-open/2022-2023/final/settings.json
new file mode 100644
index 000000000..591a8b5a3
--- /dev/null
+++ b/config/innopolis-open/2022-2023/final/settings.json
@@ -0,0 +1,5 @@
+{
+ "type":"pcms",
+ "url":"https://pcms.university.innopolis.ru/results/innopolis/2022-2023/final-main.xml",
+ "resultType":"IOI"
+}
\ No newline at end of file
diff --git a/config/io-personal/2023/events.properties b/config/io-personal/2023/events.properties
deleted file mode 100644
index 7c2cade04..000000000
--- a/config/io-personal/2023/events.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-url=https://neerc.ifmo.ru/school/io/today/standings-personal.xml
-standings.type=PCMS
-standings.resultType=ioi
-
-standings.minScore = 0
-standings.maxScore = 100
diff --git a/config/io-personal/2023/settings.json b/config/io-personal/2023/settings.json
new file mode 100644
index 000000000..56e0aba90
--- /dev/null
+++ b/config/io-personal/2023/settings.json
@@ -0,0 +1,5 @@
+{
+ "type":"pcms",
+ "url":"https://neerc.ifmo.ru/school/io/today/standings-personal.xml",
+ "resultType":"IOI"
+}
diff --git a/config/ioi/2023/day1/advanced.json b/config/ioi/2023/day1/advanced.json
new file mode 100644
index 000000000..4f6dedb29
--- /dev/null
+++ b/config/ioi/2023/day1/advanced.json
@@ -0,0 +1,38 @@
+{
+ "teamOverrides": {
+ "HUN5" : {"isOutOfContest": true },
+ "HUN6" : {"isOutOfContest": true },
+ "HUN7" : {"isOutOfContest": true },
+ "HUN8" : {"isOutOfContest": true }
+ },
+ "scoreboardOverrides": {
+ "medals": [
+ {
+ "name": "gold",
+ "count": 30,
+ "tiebreakMode": "ALL"
+ },
+ {
+ "name": "silver",
+ "count": 59,
+ "tiebreakMode": "ALL"
+ },
+ {
+ "name": "bronze",
+ "count": 89,
+ "tiebreakMode": "NONE"
+ }
+ ]
+ },
+ "problemOverrides": {
+ "closing": {
+ "displayName": "A1"
+ },
+ "longesttrip": {
+ "displayName": "B1"
+ },
+ "soccer": {
+ "displayName": "C1"
+ }
+ }
+}
\ No newline at end of file
diff --git a/config/ioi/2023/day1/settings.json b/config/ioi/2023/day1/settings.json
new file mode 100644
index 000000000..19adb6ea2
--- /dev/null
+++ b/config/ioi/2023/day1/settings.json
@@ -0,0 +1,6 @@
+{
+ "type": "cms",
+ "activeContest": "day1",
+ "otherContests": [],
+ "url": "https://ranking.cmsioi2023.hu/day1_v2"
+}
\ No newline at end of file
diff --git a/config/ioi/2023/day2/advanced.json b/config/ioi/2023/day2/advanced.json
new file mode 100644
index 000000000..7018d492e
--- /dev/null
+++ b/config/ioi/2023/day2/advanced.json
@@ -0,0 +1,56 @@
+{
+ "teamOverrides": {
+ "HUN5" : {"isOutOfContest": true },
+ "HUN6" : {"isOutOfContest": true },
+ "HUN7" : {"isOutOfContest": true },
+ "HUN8" : {"isOutOfContest": true }
+ },
+ "scoreboardOverrides": {
+ "medals": [
+ {
+ "name": "gold",
+ "count": 30,
+ "tiebreakMode": "ALL"
+ },
+ {
+ "name": "silver",
+ "count": 58,
+ "tiebreakMode": "ALL"
+ },
+ {
+ "name": "bronze",
+ "count": 88,
+ "tiebreakMode": "NONE"
+ }
+ ]
+ },
+ "problemOverrides": {
+ "closing": {
+ "displayName": "A1",
+ "ordinal": 0
+ },
+ "longesttrip": {
+ "displayName": "B1",
+ "ordinal": 1
+ },
+ "soccer": {
+ "displayName": "C1",
+ "ordinal": 2
+ },
+ "beechtree": {
+ "displayName": "A2",
+ "ordinal": 3
+ },
+ "robot": {
+ "displayName": "С2",
+ "ordinal": 5
+ },
+ "overtaking": {
+ "displayName": "B2",
+ "ordinal": 4
+ }
+ },
+ "teamOverrideTemplate": {
+ "displayName": "[{country}] {first_name} {last_name}"
+ }
+}
\ No newline at end of file
diff --git a/config/ioi/2023/day2/settings.json b/config/ioi/2023/day2/settings.json
new file mode 100644
index 000000000..e3caa0335
--- /dev/null
+++ b/config/ioi/2023/day2/settings.json
@@ -0,0 +1,6 @@
+{
+ "type": "cms",
+ "activeContest": "day2",
+ "otherContests": ["day1"],
+ "url": "https://ranking.cmsioi2023.hu/live"
+}
\ No newline at end of file
diff --git a/config/ioip/2022/events.properties b/config/ioip/2022/events.properties
deleted file mode 100644
index 556b5e281..000000000
--- a/config/ioip/2022/events.properties
+++ /dev/null
@@ -1,9 +0,0 @@
-url=https://nerc.itmo.ru/school/ioip/ioip-2022.xml
-standings.type=PCMS
-standings.resultType=ioi
-
-emulation.startTime=2022-12-22 18:35
-emulation.speed=1
-
-standings.minScore = 0
-standings.maxScore = 100
diff --git a/config/ioip/2022/settings.json b/config/ioip/2022/settings.json
new file mode 100644
index 000000000..19e8028e9
--- /dev/null
+++ b/config/ioip/2022/settings.json
@@ -0,0 +1,5 @@
+{
+ "type":"pcms",
+ "url":"https://nerc.itmo.ru/school/ioip/ioip-2022.xml",
+ "resultType":"IOI"
+}
\ No newline at end of file
diff --git a/config/lscpc/2022/events.properties b/config/lscpc/2022/events.properties
deleted file mode 100644
index 9412fdbe0..000000000
--- a/config/lscpc/2022/events.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-standings.type=EJUDGE
-url=https://ejudge.strategy48.ru/lscpc_external_inikoteni.xml
diff --git a/config/lscpc/2022/settings.json b/config/lscpc/2022/settings.json
new file mode 100644
index 000000000..f4824c86a
--- /dev/null
+++ b/config/lscpc/2022/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"ejudge",
+ "url":"https://ejudge.strategy48.ru/lscpc_external_inikoteni.xml"
+}
diff --git a/config/mkoshp/2022/events.properties b/config/mkoshp/2022/events.properties
deleted file mode 100644
index 53b66a6ec..000000000
--- a/config/mkoshp/2022/events.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-standings.type=EJUDGE
-url=https://olympiads.ru/5wHVSnHiVb7kArvh.xml
diff --git a/config/mkoshp/2022/settings.json b/config/mkoshp/2022/settings.json
new file mode 100644
index 000000000..fad236469
--- /dev/null
+++ b/config/mkoshp/2022/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"ejudge",
+ "url":"https://olympiads.ru/5wHVSnHiVb7kArvh.xml"
+}
diff --git a/config/mosh/2023/1-6/events.properties b/config/mosh/2023/1-6/events.properties
deleted file mode 100644
index 93580c373..000000000
--- a/config/mosh/2023/1-6/events.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-standings.type=EJUDGE
-standings.resultType=IOI
-url=https://olympiads.ru/eTkwBY9KRVgtLVzq/external.xml
-
diff --git a/config/mosh/2023/1-6/settings.json b/config/mosh/2023/1-6/settings.json
new file mode 100644
index 000000000..fd4b36d5f
--- /dev/null
+++ b/config/mosh/2023/1-6/settings.json
@@ -0,0 +1,6 @@
+{
+ "type":"ejudge",
+ "resultType":"IOI",
+ "url":"https://olympiads.ru/eTkwBY9KRVgtLVzq/external.xml"
+}
+
diff --git a/config/mosh/2023/7-8/events.properties b/config/mosh/2023/7-8/events.properties
deleted file mode 100644
index d4e3ad48b..000000000
--- a/config/mosh/2023/7-8/events.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-standings.type=EJUDGE
-standings.resultType=IOI
-url=https://olympiads.ru/aBXA2lMYmx3hNaZW/external.xml
-
diff --git a/config/mosh/2023/7-8/settings.json b/config/mosh/2023/7-8/settings.json
new file mode 100644
index 000000000..fce81b710
--- /dev/null
+++ b/config/mosh/2023/7-8/settings.json
@@ -0,0 +1,6 @@
+{
+ "type":"ejudge",
+ "resultType":"IOI",
+ "url":"https://olympiads.ru/aBXA2lMYmx3hNaZW/external.xml"
+}
+
diff --git a/config/mosh/2023/9/events.properties b/config/mosh/2023/9/events.properties
deleted file mode 100644
index a6a179ffa..000000000
--- a/config/mosh/2023/9/events.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-standings.type=EJUDGE
-standings.resultType=IOI
-url=https://olympiads.ru/LW96bHqAIXmwH1cD/external.xml
-
diff --git a/config/mosh/2023/9/settings.json b/config/mosh/2023/9/settings.json
new file mode 100644
index 000000000..8f2d22bf4
--- /dev/null
+++ b/config/mosh/2023/9/settings.json
@@ -0,0 +1,6 @@
+{
+ "type":"ejudge",
+ "resultType":"IOI",
+ "url":"https://olympiads.ru/LW96bHqAIXmwH1cD/external.xml"
+}
+
diff --git a/config/mosh/2023/keldysh/settings.json b/config/mosh/2023/keldysh/settings.json
new file mode 100644
index 000000000..4d794469f
--- /dev/null
+++ b/config/mosh/2023/keldysh/settings.json
@@ -0,0 +1,7 @@
+{
+ "type":"ejudge",
+ "resultType":"IOI",
+ "#turl2":"https://olympiads.ru/aBXA2lMYmx3hNaZW/external.xml",
+ "#url3":"https://olympiads.ru/LW96bHqAIXmwH1cD/external.xml",
+ "url":"https://olympiads.ru/GDUvPbXKZ6lXalSG/external.xml"
+}
\ No newline at end of file
diff --git a/config/ptz/2022-summer/events.properties b/config/ptz/2022-summer/events.properties
deleted file mode 100644
index 9b87a38b1..000000000
--- a/config/ptz/2022-summer/events.properties
+++ /dev/null
@@ -1,9 +0,0 @@
-# 1. Register an application here: https://oauth.yandex.ru
-# - Choose Web services
-# - Tap Set URL for development
-# - Add permission Yandex Contest -> Send and evaluate submissions in contests (contest:submit)
-# 2. Get debug token: https://yandex.ru/dev/id/doc/dg/oauth/tasks/get-oauth-token.html
-yandex.token=$creds.yandex
-yandex.contest_id=39551
-yandex.login_prefix=(^karelia22s.*)
-standings.type=YANDEX
\ No newline at end of file
diff --git a/config/ptz/2022-summer/settings.json b/config/ptz/2022-summer/settings.json
new file mode 100644
index 000000000..ecd72008e
--- /dev/null
+++ b/config/ptz/2022-summer/settings.json
@@ -0,0 +1,7 @@
+{
+ "type": "yandex",
+ "apiKey": "$creds.yandex",
+ "contestId": 39551,
+ "loginRegex": "(^karelia22s.*)"
+}
+
diff --git a/config/ptz/2023-winter/day2/events.properties b/config/ptz/2023-winter/day2/events.properties
deleted file mode 100644
index cfe8c709f..000000000
--- a/config/ptz/2023-winter/day2/events.properties
+++ /dev/null
@@ -1,9 +0,0 @@
-# 1. Register an application here: https://oauth.yandex.ru
-# - Choose Web services
-# - Tap Set URL for development
-# - Add permission Yandex Contest -> Send and evaluate submissions in contests (contest:submit)
-# 2. Get debug token: https://yandex.ru/dev/id/doc/dg/oauth/tasks/get-oauth-token.html
-yandex.token=$creds.yandex
-yandex.contest_id=45822
-yandex.login_prefix=(^karelia23w.*)
-standings.type=YANDEX
\ No newline at end of file
diff --git a/config/ptz/2023-winter/day2/settings.json b/config/ptz/2023-winter/day2/settings.json
new file mode 100644
index 000000000..4c1d4648e
--- /dev/null
+++ b/config/ptz/2023-winter/day2/settings.json
@@ -0,0 +1,7 @@
+{
+ "type": "yandex",
+ "apiKey": "$creds.yandex",
+ "contestId": 45822,
+ "loginRegex": "(^karelia23w.*)"
+}
+
diff --git a/config/ptz/2023-winter/day4/events.properties b/config/ptz/2023-winter/day4/events.properties
deleted file mode 100644
index a31871dda..000000000
--- a/config/ptz/2023-winter/day4/events.properties
+++ /dev/null
@@ -1,9 +0,0 @@
-# 1. Register an application here: https://oauth.yandex.ru
-# - Choose Web services
-# - Tap Set URL for development
-# - Add permission Yandex Contest -> Send and evaluate submissions in contests (contest:submit)
-# 2. Get debug token: https://yandex.ru/dev/id/doc/dg/oauth/tasks/get-oauth-token.html
-yandex.token=$creds.yandex
-yandex.contest_id=45824
-yandex.login_prefix=(^karelia23w.*)
-standings.type=YANDEX
\ No newline at end of file
diff --git a/config/ptz/2023-winter/day4/settings.json b/config/ptz/2023-winter/day4/settings.json
new file mode 100644
index 000000000..ae69f63ee
--- /dev/null
+++ b/config/ptz/2023-winter/day4/settings.json
@@ -0,0 +1,6 @@
+{
+ "type": "yandex",
+ "apiKey": "$creds.yandex",
+ "contestId": 45824,
+ "loginRegex": "(^karelia23w.*)"
+}
diff --git a/config/ptz/2023-winter/day7/events.properties b/config/ptz/2023-winter/day7/events.properties
deleted file mode 100644
index 68c87770f..000000000
--- a/config/ptz/2023-winter/day7/events.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-standings.type=EJUDGE
-url=http://ejudge.opencup.org/~ejudge/feed/icpccamp2023day2.xml
-
-
diff --git a/config/ptz/2023-winter/day7/settings.json b/config/ptz/2023-winter/day7/settings.json
new file mode 100644
index 000000000..8a21fd35d
--- /dev/null
+++ b/config/ptz/2023-winter/day7/settings.json
@@ -0,0 +1,6 @@
+{
+ "type":"ejudge",
+ "url":"http://ejudge.opencup.org/~ejudge/feed/icpccamp2023day2.xml"
+}
+
+
diff --git a/config/regionalroi/lpk-2021-d1/settings.json b/config/regionalroi/lpk-2021-d1/settings.json
new file mode 100644
index 000000000..8e4f6e8b8
--- /dev/null
+++ b/config/regionalroi/lpk-2021-d1/settings.json
@@ -0,0 +1,5 @@
+{
+ "type":"ejudge",
+ "resultType":"IOI",
+ "url":"https://ejudge.strategy48.ru/regional-2021-d1.xml"
+}
\ No newline at end of file
diff --git a/config/regionalroi/saratov-2023-d1/events.properties b/config/regionalroi/saratov-2023-d1/events.properties
deleted file mode 100644
index 1f61415ca..000000000
--- a/config/regionalroi/saratov-2023-d1/events.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-cf.api.key=$creds.codeforces_key
-cf.api.secret=$creds.codeforces_secret
-contest_id=422359
-standings.type=CF
-
diff --git a/config/regionalroi/saratov-2023-d1/settings.json b/config/regionalroi/saratov-2023-d1/settings.json
new file mode 100644
index 000000000..0329c4ac0
--- /dev/null
+++ b/config/regionalroi/saratov-2023-d1/settings.json
@@ -0,0 +1,7 @@
+{
+ "type": "cf",
+ "apiKey": "$creds.codeforces_key",
+ "apiSecret": "$creds.codeforces_secret",
+ "contestId": 422359
+}
+
diff --git a/config/regionalroi/spb-2022-d1/events.properties b/config/regionalroi/spb-2022-d1/events.properties
deleted file mode 100644
index d4c27199d..000000000
--- a/config/regionalroi/spb-2022-d1/events.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-url=regionalroi/spb-2022-d1/ru-olymp-spb-2022-standings-day1-groups.xml
-standings.type=PCMS
-standings.resultType=ioi
-
-emulation.startTime=2022-12-29 09:00
-emulation.speed=3
\ No newline at end of file
diff --git a/config/regionalroi/spb-2022-d1/settings.json b/config/regionalroi/spb-2022-d1/settings.json
new file mode 100644
index 000000000..ab1f8bb3d
--- /dev/null
+++ b/config/regionalroi/spb-2022-d1/settings.json
@@ -0,0 +1,5 @@
+{
+ "type": "pcms",
+ "url": "regionalroi/spb-2022-d1/ru-olymp-spb-2022-standings-day1-groups.xml",
+ "resultType": "IOI"
+}
diff --git a/config/regionalroi/spb-2023-d1/events.properties b/config/regionalroi/spb-2023-d1/events.properties
deleted file mode 100644
index 2d73dd9f5..000000000
--- a/config/regionalroi/spb-2023-d1/events.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-url=http://nerc.itmo.ru/school/archive/2022-2023/ru-olymp-spb-2023-standings-day1.xml
-standings.type=PCMS
-standings.resultType=ioi
diff --git a/config/regionalroi/spb-2023-d1/settings.json b/config/regionalroi/spb-2023-d1/settings.json
new file mode 100644
index 000000000..d24504fa6
--- /dev/null
+++ b/config/regionalroi/spb-2023-d1/settings.json
@@ -0,0 +1,6 @@
+{
+ "type":"pcms",
+ "url":"http://nerc.itmo.ru/school/archive/2022-2023/ru-olymp-spb-2023-standings-day1.xml",
+ "resultType":"IOI"
+}
+
diff --git a/config/regionalroi/spb-2023-d2/events.properties b/config/regionalroi/spb-2023-d2/events.properties
deleted file mode 100644
index a5e9fba5a..000000000
--- a/config/regionalroi/spb-2023-d2/events.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-url=http://nerc.itmo.ru/school/archive/2022-2023/ru-olymp-spb-2023-standings-day2.xml
-standings.type=PCMS
-standings.resultType=ioi
diff --git a/config/regionalroi/spb-2023-d2/settings.json b/config/regionalroi/spb-2023-d2/settings.json
new file mode 100644
index 000000000..3fba5d9e5
--- /dev/null
+++ b/config/regionalroi/spb-2023-d2/settings.json
@@ -0,0 +1,6 @@
+{
+ "type":"pcms",
+ "url":"http://nerc.itmo.ru/school/archive/2022-2023/ru-olymp-spb-2023-standings-day2.xml",
+ "resultType":"IOI"
+}
+
diff --git a/config/regionalroi/tomsk-2016-d1/events.properties b/config/regionalroi/tomsk-2016-d1/events.properties
deleted file mode 100644
index ca9d22fd5..000000000
--- a/config/regionalroi/tomsk-2016-d1/events.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-yandex.token=$creds.yandex
-yandex.contest_id=2121
-yandex.login_prefix=(^roi16-.*)
-standings.type=YANDEX
-standings.resultType=IOI
\ No newline at end of file
diff --git a/config/regionalroi/tomsk-2016-d1/settings.json b/config/regionalroi/tomsk-2016-d1/settings.json
new file mode 100644
index 000000000..4c9d556e9
--- /dev/null
+++ b/config/regionalroi/tomsk-2016-d1/settings.json
@@ -0,0 +1,8 @@
+{
+ "type": "yandex",
+ "apiKey": "$creds.yandex",
+ "contestId": 2121,
+ "resultType": "IOI",
+ "loginRegex": "(^roi16-.*)"
+}
+
diff --git a/config/roi/2021/events.properties b/config/roi/2021/events.properties
deleted file mode 100644
index 8dfe2c4ff..000000000
--- a/config/roi/2021/events.properties
+++ /dev/null
@@ -1,10 +0,0 @@
-login=admin
-password=adm1n
-url=http://10.10.0.3/standings/standings-live.xml
-teams.url=participants.xml
-problems.url=problems.xml
-problems.number=8
-standings.type=IOIPCMS
-
-running.time=18000000
-freeze.time=18000000
\ No newline at end of file
diff --git a/config/roi/2021/mainscreen.properties b/config/roi/2021/mainscreen.properties
deleted file mode 100644
index 1cebdbf6c..000000000
--- a/config/roi/2021/mainscreen.properties
+++ /dev/null
@@ -1,79 +0,0 @@
-#width=1280
-#height=720
-width=1920
-height=1080
-rate=25
-output.file=d:/work/image.bin
-output.mode=file
-#output.mode=window
-
-update.wait=500
-backup.persons=persons.txt
-backup.advertisements=advertisements.txt
-breakingnews.time=20000
-breakingnews.runs.number=10
-breakingnews.patterns.filename=patterns.txt
-standings.blinking.time=10000
-advertisement.time=50000
-person.time=50000
-latency.time=2000
-data.update=1000
-data.host=localhost
-data.port=25675
-
-info.types=screen;camera
-#info.screen=http://192.168.1.207:9080/video/screen/%d
-#info.camera=http://192.168.1.207:9080/video/camera/%d
-#info.record=http://192.168.1.207:9080/video/reaction/%d
-info.screen=http://192.168.18.38:80%02d
-info.camera=http://192.168.18.38:81%02d
-#info.camera=https://live:evMUzdqM@192.168.1.207/video/webcam/%s
-#info.video=teamVideos/%s.mp4
-#info.record=pics/team.jpg
-#info.types=photo;screen
-#info.video=teamVideos/%03d.mp4
-#pics/BigBuckBunny_320x180.mp4
-#pics/team.jpg
-#info.screen=pics/BigBuckBunny_320x180.mp4
-#pics/screen.png
-
-sleep.time=20000
-automated.show.time=40000
-automated.info=screen
-team.double.video=false
-
-ticker.rotate.time=10000
-ticker.logo=#Clock#;NERC 2020
-ticker.logo.time=5000
-ticker.clock.time=20000
-ticker.logo.change.time=1000
-
-queue.show.verdict=true
-
-overlayed.delay=3000
-
-top.teams=S077,S118,S113,S089,S128,S099,S012,S086,S007,S050,S121,S110,S062
-onsite.teams=.*
-
-stylesheet=stylesheets/wf.jss
-
-polls.backup.file=polls.txt
-poll.show.time=20000
-poll.top.teams=5
-
-twitch.chat.server=irc.chat.twitch.tv
-twitch.chat.username=aksenov239
-twitch.chat.password=oauth:8yb7ygy3ey2wdwmlkvd7bs2o8guwf3
-twitch.chat.channel=#aksenov239;#icpclive1;#icpclive_ru
-
-twitter.hashtag=#NERC2020
-
-word.statistics.backup.file=words-statistics.txt
-word.statistics.words=tweets;goose;energy
-word.statistics.tweets.text=$tweets$
-word.statistics.tweets.picture=
-word.statistics.goose.text=(*)>
-word.statistics.goose.picture=pics/goose.jpg
-word.statistics.energy.text=ί-- ??φ Π?_Π? ί-ι??φ
-word.statistics.energy.picture=pics/energy.jpg
-word.statistics.word.show.time=10000
diff --git a/config/roi/2021/problems.xml b/config/roi/2021/problems.xml
deleted file mode 100644
index 0b850cc46..000000000
--- a/config/roi/2021/problems.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/roi/2021/settings.json b/config/roi/2021/settings.json
new file mode 100644
index 000000000..45c3c4b94
--- /dev/null
+++ b/config/roi/2021/settings.json
@@ -0,0 +1,7 @@
+{
+ "type":"pcms",
+ "login":"admin",
+ "password":"adm1n",
+ "url":"http://10.10.0.3/standings/standings-live.xml",
+ "resultType":"IOI"
+}
diff --git a/config/roi/2022/day1/events.properties b/config/roi/2022/day1/events.properties
deleted file mode 100644
index 8ab85eab5..000000000
--- a/config/roi/2022/day1/events.properties
+++ /dev/null
@@ -1,15 +0,0 @@
-login=admin
-password=adm1n
-url=roi-2022-day1/standings-live-day1.xml
-teams.url=roi-2022-day1/participants.xml
-problems.url=roi-2022-day1/problems.xml
-problems.number=4
-standings.type=PCMS
-standings.resultType=ioi
-standings.maxScore=100
-
-running.time=18000000
-freeze.time=18000000
-
-emulation.speed=15
-emulation.startTime=now
diff --git a/config/roi/2022/day1/mainscreen.properties b/config/roi/2022/day1/mainscreen.properties
deleted file mode 100644
index 433d8fa8b..000000000
--- a/config/roi/2022/day1/mainscreen.properties
+++ /dev/null
@@ -1,79 +0,0 @@
-#width=1280
-#height=720
-width=1920
-height=1080
-rate=25
-output.file=c:/work/image.bin
-output.mode=file
-#output.mode=window
-
-update.wait=500
-backup.persons=persons.txt
-backup.advertisements=advertisements.txt
-breakingnews.time=20000
-breakingnews.runs.number=10
-breakingnews.patterns.filename=patterns.txt
-standings.blinking.time=10000
-advertisement.time=50000
-person.time=50000
-latency.time=2000
-data.update=1000
-data.host=localhost
-data.port=25675
-
-info.types=screen;camera
-#info.screen=http://192.168.1.207:9080/video/screen/%d
-#info.camera=http://192.168.1.207:9080/video/camera/%d
-#info.record=http://192.168.1.207:9080/video/reaction/%d
-info.screen=http://192.168.18.38:80%02d
-info.camera=http://192.168.18.38:81%02d
-#info.camera=https://live:evMUzdqM@192.168.1.207/video/webcam/%s
-#info.video=teamVideos/%s.mp4
-#info.record=pics/team.jpg
-#info.types=photo;screen
-#info.video=teamVideos/%03d.mp4
-#pics/BigBuckBunny_320x180.mp4
-#pics/team.jpg
-#info.screen=pics/BigBuckBunny_320x180.mp4
-#pics/screen.png
-
-sleep.time=20000
-automated.show.time=40000
-automated.info=screen
-team.double.video=false
-
-ticker.rotate.time=10000
-ticker.logo=#Clock#;ВсОШ 2022
-ticker.logo.time=5000
-ticker.clock.time=20000
-ticker.logo.change.time=1000
-
-queue.show.verdict=true
-
-overlayed.delay=3000
-
-top.teams=S077,S118,S113,S089,S128,S099,S012,S086,S007,S050,S121,S110,S062
-onsite.teams=.*
-
-stylesheet=stylesheets/wf.jss
-
-polls.backup.file=polls.txt
-poll.show.time=20000
-poll.top.teams=5
-
-twitch.chat.server=irc.chat.twitch.tv
-twitch.chat.username=aksenov239
-twitch.chat.password=oauth:8yb7ygy3ey2wdwmlkvd7bs2o8guwf3
-twitch.chat.channel=#aksenov239;#icpclive1;#icpclive_ru
-
-twitter.hashtag=#ВсОШ2022
-
-word.statistics.backup.file=words-statistics.txt
-word.statistics.words=tweets;goose;energy
-word.statistics.tweets.text=$tweets$
-word.statistics.tweets.picture=
-word.statistics.goose.text=(*)>
-word.statistics.goose.picture=pics/goose.jpg
-word.statistics.energy.text=ί-- ??φ Π?_Π? ί-ι??φ
-word.statistics.energy.picture=pics/energy.jpg
-word.statistics.word.show.time=10000
diff --git a/config/roi/2022/day1/problems.xml b/config/roi/2022/day1/problems.xml
deleted file mode 100644
index 75e4e9316..000000000
--- a/config/roi/2022/day1/problems.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/roi/2022/day1/settings.json b/config/roi/2022/day1/settings.json
new file mode 100644
index 000000000..2cfa630a3
--- /dev/null
+++ b/config/roi/2022/day1/settings.json
@@ -0,0 +1,7 @@
+{
+ "type": "pcms",
+ "login": "admin",
+ "password": "adm1n",
+ "url": "roi-2022-day1/standings-live-day1.xml",
+ "resultType": "IOI"
+}
diff --git a/config/roi/2022/day2/events.properties b/config/roi/2022/day2/events.properties
deleted file mode 100644
index f3a52b49e..000000000
--- a/config/roi/2022/day2/events.properties
+++ /dev/null
@@ -1,10 +0,0 @@
-login=admin
-password=adm1n
-url=http://10.10.0.3/standings/standings-live.xml
-teams.url=archive/roi-2022-day2/participants.xml
-problems.url=archive/roi-2022-day2/problems.xml
-problems.number=8
-standings.type=IOIPCMS
-
-running.time=18000000
-freeze.time=18000000
\ No newline at end of file
diff --git a/config/roi/2022/day2/mainscreen.properties b/config/roi/2022/day2/mainscreen.properties
deleted file mode 100644
index ac3c1a3a1..000000000
--- a/config/roi/2022/day2/mainscreen.properties
+++ /dev/null
@@ -1,79 +0,0 @@
-#width=1280
-#height=720
-width=1920
-height=1080
-rate=25
-output.file=c:/work/image.bin
-output.mode=file
-#output.mode=window
-
-update.wait=500
-backup.persons=persons.txt
-backup.advertisements=advertisements.txt
-breakingnews.time=20000
-breakingnews.runs.number=10
-breakingnews.patterns.filename=patterns.txt
-standings.blinking.time=10000
-advertisement.time=50000
-person.time=50000
-latency.time=2000
-data.update=1000
-data.host=localhost
-data.port=25675
-
-info.types=screen;camera
-#info.screen=http://192.168.1.207:9080/video/screen/%d
-#info.camera=http://192.168.1.207:9080/video/camera/%d
-#info.record=http://192.168.1.207:9080/video/reaction/%d
-info.screen=http://192.168.18.38:80%02d
-info.camera=http://192.168.18.38:81%02d
-#info.camera=https://live:evMUzdqM@192.168.1.207/video/webcam/%s
-#info.video=teamVideos/%s.mp4
-#info.record=pics/team.jpg
-#info.types=photo;screen
-#info.video=teamVideos/%03d.mp4
-#pics/BigBuckBunny_320x180.mp4
-#pics/team.jpg
-#info.screen=pics/BigBuckBunny_320x180.mp4
-#pics/screen.png
-
-sleep.time=20000
-automated.show.time=40000
-automated.info=screen
-team.double.video=false
-
-ticker.rotate.time=10000
-ticker.logo=#Clock#;NERC 2020
-ticker.logo.time=5000
-ticker.clock.time=20000
-ticker.logo.change.time=1000
-
-queue.show.verdict=true
-
-overlayed.delay=3000
-
-top.teams=S077,S118,S113,S089,S128,S099,S012,S086,S007,S050,S121,S110,S062
-onsite.teams=.*
-
-stylesheet=stylesheets/wf.jss
-
-polls.backup.file=polls.txt
-poll.show.time=20000
-poll.top.teams=5
-
-twitch.chat.server=irc.chat.twitch.tv
-twitch.chat.username=aksenov239
-twitch.chat.password=oauth:8yb7ygy3ey2wdwmlkvd7bs2o8guwf3
-twitch.chat.channel=#aksenov239;#icpclive1;#icpclive_ru
-
-twitter.hashtag=#NERC2020
-
-word.statistics.backup.file=words-statistics.txt
-word.statistics.words=tweets;goose;energy
-word.statistics.tweets.text=$tweets$
-word.statistics.tweets.picture=
-word.statistics.goose.text=(*)>
-word.statistics.goose.picture=pics/goose.jpg
-word.statistics.energy.text=ί-- ??φ Π?_Π? ί-ι??φ
-word.statistics.energy.picture=pics/energy.jpg
-word.statistics.word.show.time=10000
diff --git a/config/roi/2022/day2/problems.xml b/config/roi/2022/day2/problems.xml
deleted file mode 100644
index 149dbe26c..000000000
--- a/config/roi/2022/day2/problems.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/roi/2022/day2/settings.json b/config/roi/2022/day2/settings.json
new file mode 100644
index 000000000..dd2266b03
--- /dev/null
+++ b/config/roi/2022/day2/settings.json
@@ -0,0 +1,7 @@
+{
+ "type":"pcms",
+ "login":"admin",
+ "password":"adm1n",
+ "url":"http://10.10.0.3/standings/standings-live.xml",
+ "resultType":"IOI"
+}
diff --git a/config/roi/2022/test/events.properties b/config/roi/2022/test/events.properties
deleted file mode 100644
index 074750773..000000000
--- a/config/roi/2022/test/events.properties
+++ /dev/null
@@ -1,10 +0,0 @@
-login=admin
-password=adm1n
-url=http://172.18.1.253/standings/standings-live.xml
-teams.url=archive/roi-2022-test/participants.xml
-problems.url=archive/roi-2022-test/problems.xml
-problems.number=6
-standings.type=IOIPCMS
-
-running.time=18000000
-freeze.time=18000000
\ No newline at end of file
diff --git a/config/roi/2022/test/mainscreen.properties b/config/roi/2022/test/mainscreen.properties
deleted file mode 100644
index 433d8fa8b..000000000
--- a/config/roi/2022/test/mainscreen.properties
+++ /dev/null
@@ -1,79 +0,0 @@
-#width=1280
-#height=720
-width=1920
-height=1080
-rate=25
-output.file=c:/work/image.bin
-output.mode=file
-#output.mode=window
-
-update.wait=500
-backup.persons=persons.txt
-backup.advertisements=advertisements.txt
-breakingnews.time=20000
-breakingnews.runs.number=10
-breakingnews.patterns.filename=patterns.txt
-standings.blinking.time=10000
-advertisement.time=50000
-person.time=50000
-latency.time=2000
-data.update=1000
-data.host=localhost
-data.port=25675
-
-info.types=screen;camera
-#info.screen=http://192.168.1.207:9080/video/screen/%d
-#info.camera=http://192.168.1.207:9080/video/camera/%d
-#info.record=http://192.168.1.207:9080/video/reaction/%d
-info.screen=http://192.168.18.38:80%02d
-info.camera=http://192.168.18.38:81%02d
-#info.camera=https://live:evMUzdqM@192.168.1.207/video/webcam/%s
-#info.video=teamVideos/%s.mp4
-#info.record=pics/team.jpg
-#info.types=photo;screen
-#info.video=teamVideos/%03d.mp4
-#pics/BigBuckBunny_320x180.mp4
-#pics/team.jpg
-#info.screen=pics/BigBuckBunny_320x180.mp4
-#pics/screen.png
-
-sleep.time=20000
-automated.show.time=40000
-automated.info=screen
-team.double.video=false
-
-ticker.rotate.time=10000
-ticker.logo=#Clock#;ВсОШ 2022
-ticker.logo.time=5000
-ticker.clock.time=20000
-ticker.logo.change.time=1000
-
-queue.show.verdict=true
-
-overlayed.delay=3000
-
-top.teams=S077,S118,S113,S089,S128,S099,S012,S086,S007,S050,S121,S110,S062
-onsite.teams=.*
-
-stylesheet=stylesheets/wf.jss
-
-polls.backup.file=polls.txt
-poll.show.time=20000
-poll.top.teams=5
-
-twitch.chat.server=irc.chat.twitch.tv
-twitch.chat.username=aksenov239
-twitch.chat.password=oauth:8yb7ygy3ey2wdwmlkvd7bs2o8guwf3
-twitch.chat.channel=#aksenov239;#icpclive1;#icpclive_ru
-
-twitter.hashtag=#ВсОШ2022
-
-word.statistics.backup.file=words-statistics.txt
-word.statistics.words=tweets;goose;energy
-word.statistics.tweets.text=$tweets$
-word.statistics.tweets.picture=
-word.statistics.goose.text=(*)>
-word.statistics.goose.picture=pics/goose.jpg
-word.statistics.energy.text=ί-- ??φ Π?_Π? ί-ι??φ
-word.statistics.energy.picture=pics/energy.jpg
-word.statistics.word.show.time=10000
diff --git a/config/roi/2022/test/problems.xml b/config/roi/2022/test/problems.xml
deleted file mode 100644
index dd06c7d1b..000000000
--- a/config/roi/2022/test/problems.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/roi/2022/test/settings.json b/config/roi/2022/test/settings.json
new file mode 100644
index 000000000..1d7766e6e
--- /dev/null
+++ b/config/roi/2022/test/settings.json
@@ -0,0 +1,7 @@
+{
+ "type":"pcms",
+ "login":"admin",
+ "password":"adm1n",
+ "url":"http://172.18.1.253/standings/standings-live.xml",
+ "resultType":"IOI"
+}
diff --git a/config/roi/2023/day1/events.properties b/config/roi/2023/day1/events.properties
deleted file mode 100644
index 4911c49eb..000000000
--- a/config/roi/2023/day1/events.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-#url=http://192.168.90.248/standings/standings-live.xml
-url=roi/2023/day1/day1.xml
-standings.type=PCMS
-standings.resultType=ioi
diff --git a/config/roi/2023/day1/settings.json b/config/roi/2023/day1/settings.json
new file mode 100644
index 000000000..91fabe8a6
--- /dev/null
+++ b/config/roi/2023/day1/settings.json
@@ -0,0 +1,6 @@
+{
+ "type":"pcms",
+ "#url":"http://192.168.90.248/standings/standings-live.xml",
+ "url":"roi/2023/day1/day1.xml",
+ "resultType":"IOI"
+}
\ No newline at end of file
diff --git a/config/roi/2023/day2/advanced.json b/config/roi/2023/day2/advanced.json
index c6e928ff2..a38c3f4dc 100644
--- a/config/roi/2023/day2/advanced.json
+++ b/config/roi/2023/day2/advanced.json
@@ -1,5 +1,5 @@
{
- "startTime": "2023-04-05 9:57:00",
+ "startTime": "2023-04-05 09:57:00",
"problemOverrides": {
"1":{"color":"#e6194B"},
"2":{"color":"#3cb44b"},
diff --git a/config/roi/2023/day2/events.properties b/config/roi/2023/day2/events.properties
deleted file mode 100644
index 2b0b099f2..000000000
--- a/config/roi/2023/day2/events.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-url=roi/2023/day2/day2.xml
-#url=http://192.168.90.248/standings/standings-live.xml
-standings.type=PCMS
-standings.resultType=ioi
diff --git a/config/roi/2023/day2/settings.json b/config/roi/2023/day2/settings.json
new file mode 100644
index 000000000..31379391e
--- /dev/null
+++ b/config/roi/2023/day2/settings.json
@@ -0,0 +1,6 @@
+{
+ "type": "pcms",
+ "#url": "http://192.168.90.248/standings/standings-live.xml",
+ "url": "roi/2023/day2/day2.xml",
+ "resultType": "IOI"
+}
diff --git a/config/roi/2023/it-sequel/events.properties b/config/roi/2023/it-sequel/events.properties
deleted file mode 100644
index a4c9a8926..000000000
--- a/config/roi/2023/it-sequel/events.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-url=roi/2023/it-sequel/it-sequel.xml
-#url=http://192.168.90.248/standings/standings-live.xml
-standings.type=PCMS
-standings.resultType=ioi
diff --git a/config/roi/2023/it-sequel/settings.json b/config/roi/2023/it-sequel/settings.json
new file mode 100644
index 000000000..f9c77a561
--- /dev/null
+++ b/config/roi/2023/it-sequel/settings.json
@@ -0,0 +1,7 @@
+{
+ "type": "pcms",
+ "#url": "http://192.168.90.248/standings/standings-live.xml",
+ "url": "roi/2023/it-sequel/it-sequel.xml",
+ "resultType": "IOI"
+}
+
diff --git a/config/roi/2023/test/events.properties b/config/roi/2023/test/events.properties
deleted file mode 100644
index a23b6a8c6..000000000
--- a/config/roi/2023/test/events.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-url=roi/2023/test/standings-live.xml
-standings.type=PCMS
-standings.resultType=ioi
-
-emulation.startTime=now
-emulation.speed=1
diff --git a/config/roi/2023/test/settings.json b/config/roi/2023/test/settings.json
new file mode 100644
index 000000000..9bb80f5d4
--- /dev/null
+++ b/config/roi/2023/test/settings.json
@@ -0,0 +1,5 @@
+{
+ "type":"pcms",
+ "url":"roi/2023/test/standings-live.xml",
+ "resultType":"IOI"
+}
diff --git a/config/spbkoshp/2022/events.properties b/config/spbkoshp/2022/events.properties
deleted file mode 100644
index c04a1f618..000000000
--- a/config/spbkoshp/2022/events.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-url=https://nerc.itmo.ru/school/archive/2022-2023/ru-olymp-team-spb-2022-standings.xml
-standings.type=PCMS
diff --git a/config/spbkoshp/2022/settings.json b/config/spbkoshp/2022/settings.json
new file mode 100644
index 000000000..71ddf3ef8
--- /dev/null
+++ b/config/spbkoshp/2022/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"pcms",
+ "url":"https://nerc.itmo.ru/school/archive/2022-2023/ru-olymp-team-spb-2022-standings.xml"
+}
\ No newline at end of file
diff --git a/config/spbsu/2023-may/main/settings.json b/config/spbsu/2023-may/main/settings.json
new file mode 100644
index 000000000..c77d28369
--- /dev/null
+++ b/config/spbsu/2023-may/main/settings.json
@@ -0,0 +1,5 @@
+{
+ "type":"testsys",
+ "#url":"https://nerc.itmo.ru/jm230514.dat for resolver",
+ "url":"http://acm.math.spbu.ru/cgi-bin/view.pl/m230514.dat"
+}
\ No newline at end of file
diff --git a/config/spbsu/2023-may/trial/events.properties b/config/spbsu/2023-may/trial/events.properties
deleted file mode 100644
index a20464e48..000000000
--- a/config/spbsu/2023-may/trial/events.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-standings.type=TESTSYS
-url=http://acm.math.spbu.ru/cgi-bin/view.pl/m230514p.dat
\ No newline at end of file
diff --git a/config/spbsu/2023-may/trial/settings.json b/config/spbsu/2023-may/trial/settings.json
new file mode 100644
index 000000000..f8dbcde06
--- /dev/null
+++ b/config/spbsu/2023-may/trial/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"testsys",
+ "url":"http://acm.math.spbu.ru/cgi-bin/view.pl/m230514p.dat"
+}
\ No newline at end of file
diff --git a/config/technocup/2018/events.properties b/config/technocup/2018/events.properties
deleted file mode 100644
index a4d9befa3..000000000
--- a/config/technocup/2018/events.properties
+++ /dev/null
@@ -1,8 +0,0 @@
-cf.api.key=$creds.codeforces_key
-cf.api.secret=$creds.codeforces_secret
-contest_id=944
-standings.type=CF
-
-
-emulation.startTime=2022-12-29 16:35
-emulation.speed=1
\ No newline at end of file
diff --git a/config/technocup/2018/settings.json b/config/technocup/2018/settings.json
new file mode 100644
index 000000000..5c7c29458
--- /dev/null
+++ b/config/technocup/2018/settings.json
@@ -0,0 +1,6 @@
+{
+ "type": "cf",
+ "apiKey": "$creds.codeforces_key",
+ "apiSecret": "$creds.codeforces_secret",
+ "contestId": 944
+}
diff --git a/config/test/.gitkeep b/config/test/.gitkeep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/config/vkcup/2021/events.properties b/config/vkcup/2021/events.properties
deleted file mode 100644
index 8de29e334..000000000
--- a/config/vkcup/2021/events.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-cf.api.key=$creds.codeforces_key
-cf.api.secret=$creds.codeforces_secret
-contest_id=1563
-standings.type=CF
diff --git a/config/vkcup/2021/settings.json b/config/vkcup/2021/settings.json
new file mode 100644
index 000000000..a63b1b26b
--- /dev/null
+++ b/config/vkcup/2021/settings.json
@@ -0,0 +1,6 @@
+{
+ "type": "cf",
+ "apiKey": "$creds.codeforces_key",
+ "apiSecret": "$creds.codeforces_secret",
+ "contestId": 1563
+}
\ No newline at end of file
diff --git a/config/vkcup/2022/elim/events.properties b/config/vkcup/2022/elim/events.properties
deleted file mode 100644
index 5c304f424..000000000
--- a/config/vkcup/2022/elim/events.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-cf.api.key=$creds.codeforces_key
-cf.api.secret=$creds.codeforces_secret
-contest_id=1781
-standings.type=CF
-
-emulation.startTime=now
-emulation.speed=3
diff --git a/config/vkcup/2022/elim/settings.json b/config/vkcup/2022/elim/settings.json
new file mode 100644
index 000000000..3a48d5984
--- /dev/null
+++ b/config/vkcup/2022/elim/settings.json
@@ -0,0 +1,6 @@
+{
+ "type": "cf",
+ "apiKey": "$creds.codeforces_key",
+ "apiSecret": "$creds.codeforces_secret",
+ "contestId": 1781
+}
diff --git a/config/vkcup/2022/final/settings.json b/config/vkcup/2022/final/settings.json
new file mode 100644
index 000000000..8b3d0640f
--- /dev/null
+++ b/config/vkcup/2022/final/settings.json
@@ -0,0 +1,7 @@
+{
+ "type": "cf",
+ "apiKey": "$creds.codeforces_key",
+ "apiSecret": "$creds.codeforces_secret",
+ "contestId": 1784
+}
+
diff --git a/config/vkoshp/2016/events.properties b/config/vkoshp/2016/events.properties
deleted file mode 100644
index d67b47e73..000000000
--- a/config/vkoshp/2016/events.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-login=test
-password=test
-url=http://neerc.ifmo.ru/school/russia-team/standings.xml
-participants=parties.xml
-problems.url=problems.xml
-problemsNumber=11
-standings.type=PCMS
-
-contest.length=18000000
-#5400000
-freeze.time=14400000
\ No newline at end of file
diff --git a/config/vkoshp/2016/mainscreen.properties b/config/vkoshp/2016/mainscreen.properties
deleted file mode 100644
index c96ba96b5..000000000
--- a/config/vkoshp/2016/mainscreen.properties
+++ /dev/null
@@ -1,40 +0,0 @@
-update.wait=1000
-backup.persons=persons.txt
-backup.advertisements=advertisements.txt
-breakingnews.time=20000
-breakingnews.runs.number=10
-breakingnews.patterns.filename=patterns.txt
-standings.blinking.time=10000
-advertisement.time=20000
-person.time=20000
-latency.time=2000
-data.update=1000
-data.host=192.168.1.122
-data.port=25675
-info.types=screen
-main.type=photo
-info.photo=pics/team.jpg
-info.screen=http://192.168.0.8:8008/%d/%d
-sleep.time=15000
-automated.show.time=20000
-automated.info=screen
-team.double.video=false
-
-queue.show.verdict=true
-
-ticker.rotate.time=20000
-ticker.logo=NEERC 2016;#NEERC
-ticker.logo.time=10000
-ticker.logo.change.time=10000
-
-overlayed.delay=3000
-
-width=1280
-height=720
-
-rate=25
-
-top.teams.file=vkoshp-2016/topteams.txt
-onsite.teams=S.*
-
-stylesheet=stylesheets/wf.jss
diff --git a/config/vkoshp/2016/problems.xml b/config/vkoshp/2016/problems.xml
deleted file mode 100644
index 54d92c3cf..000000000
--- a/config/vkoshp/2016/problems.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/vkoshp/2016/settings.json b/config/vkoshp/2016/settings.json
new file mode 100644
index 000000000..e44185569
--- /dev/null
+++ b/config/vkoshp/2016/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"pcms",
+ "url":"http://nerc.itmo.ru/school/archive/2016-2017/ru-olymp-team-russia-2016-standings.xml"
+}
diff --git a/config/vkoshp/2016/topteams.txt b/config/vkoshp/2016/topteams.txt
deleted file mode 100644
index f9e1cc9c1..000000000
--- a/config/vkoshp/2016/topteams.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-S520
-S502
\ No newline at end of file
diff --git a/config/vkoshp/2017/events.properties b/config/vkoshp/2017/events.properties
deleted file mode 100644
index 19d1f64dc..000000000
--- a/config/vkoshp/2017/events.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-login=test
-password=test
-url=http://neerc.ifmo.ru/school/russia-team/standings.xml
-teams.url=parties.xml
-problems.url=problems.xml
-problems.number=13
-standings.type=PCMS
-
-contest.length=18000000
-#18000000
-freeze.time=14400000
\ No newline at end of file
diff --git a/config/vkoshp/2017/mainscreen.properties b/config/vkoshp/2017/mainscreen.properties
deleted file mode 100644
index 8145ce07f..000000000
--- a/config/vkoshp/2017/mainscreen.properties
+++ /dev/null
@@ -1,57 +0,0 @@
-update.wait=1000
-backup.persons=persons.txt
-backup.advertisements=advertisements.txt
-breakingnews.time=20000
-breakingnews.runs.number=10
-breakingnews.patterns.filename=patterns.txt
-standings.blinking.time=10000
-advertisement.time=5000
-person.time=5000
-latency.time=2000
-data.update=1000
-data.host=192.168.1.144
-data.port=25675
-info.types=screen
-main.type=screen
-info.screen=http://192.168.0.8:8008/%d/%d
-sleep.time=10000
-automated.show.time=20000
-automated.info=screen
-team.double.video=false
-
-queue.show.verdict=true
-
-ticker.rotate.time=10000
-ticker.logo=#Clock#,ВКОШП 2017;#VKOSHP
-ticker.logo.time=5000
-ticker.clock.time=20000
-ticker.logo.change.time=1000
-
-overlayed.delay=3000
-
-width=1280
-height=720
-
-rate=25
-
-top.teams.file=vkoshp-2017/topteams.txt
-onsite.teams=S.*
-
-stylesheet=stylesheets/wf.jss
-
-polls.backup.file=polls.txt
-poll.show.time=20000
-poll.top.teams=5
-
-twitch.chat.server=irc.chat.twitch.tv
-twitch.chat.username=aksenov239
-twitch.chat.password=oauth:8yb7ygy3ey2wdwmlkvd7bs2o8guwf3
-twitch.chat.channel=#aksenov239;#icpclive1;#icpclive_ru
-
-twitter.hashtag=#NEERC2017
-
-word.statistics.backup.file=words-statistics.txt
-word.statistics.words=tweets
-word.statistics.tweets.text=$tweets$
-
-outputFile=d:/work/image.bin
diff --git a/config/vkoshp/2017/problems.xml b/config/vkoshp/2017/problems.xml
deleted file mode 100644
index d751138b2..000000000
--- a/config/vkoshp/2017/problems.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/vkoshp/2017/settings.json b/config/vkoshp/2017/settings.json
new file mode 100644
index 000000000..e5fb90229
--- /dev/null
+++ b/config/vkoshp/2017/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"pcms",
+ "url":"http://nerc.itmo.ru/school/archive/2017-2018/ru-olymp-team-russia-2017-standings.xml"
+}
diff --git a/config/vkoshp/2017/topteams.txt b/config/vkoshp/2017/topteams.txt
deleted file mode 100644
index 37c3d14e2..000000000
--- a/config/vkoshp/2017/topteams.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-S102
-S308
-S504
-S303
-S110
-S211
diff --git a/config/vkoshp/2019/events.properties b/config/vkoshp/2019/events.properties
deleted file mode 100644
index 1a8d9e7e4..000000000
--- a/config/vkoshp/2019/events.properties
+++ /dev/null
@@ -1,10 +0,0 @@
-login=admin
-password=adm1n
-url=http://nerc.itmo.ru/school/archive/2019-2020/ru-olymp-team-russia-2019-standings.xml
-teams.url=participants.xml
-problems.url=problems-practice.xml
-problems.number=8
-standings.type=PCMS
-
-running.time=18000000
-freeze.time=14400000
diff --git a/config/vkoshp/2019/mainscreen.properties b/config/vkoshp/2019/mainscreen.properties
deleted file mode 100644
index 6e6399ed7..000000000
--- a/config/vkoshp/2019/mainscreen.properties
+++ /dev/null
@@ -1,78 +0,0 @@
-#width=1280
-#height=720
-width=1920
-height=1080
-rate=25
-output.file=c:/work/image.bin
-output.mode=file
-#output.mode=window
-
-update.wait=500
-backup.persons=persons.txt
-backup.advertisements=advertisements.txt
-breakingnews.time=20000
-breakingnews.runs.number=10
-breakingnews.patterns.filename=patterns.txt
-standings.blinking.time=10000
-advertisement.time=50000
-person.time=50000
-latency.time=2000
-data.update=1000
-data.host=localhost
-data.port=25675
-
-info.types=screen;
-#info.screen=http://192.168.1.207:9080/video/screen/%d
-#info.camera=http://192.168.1.207:9080/video/camera/%d
-#info.record=http://192.168.1.207:9080/video/reaction/%d
-info.screen=http://10.240.%d.2:8088
-#info.camera=https://live:evMUzdqM@192.168.1.207/video/webcam/%s
-#info.video=teamVideos/%s.mp4
-#info.record=pics/team.jpg
-#info.types=photo;screen
-#info.video=teamVideos/%03d.mp4
-#pics/BigBuckBunny_320x180.mp4
-#pics/team.jpg
-#info.screen=pics/BigBuckBunny_320x180.mp4
-#pics/screen.png
-
-sleep.time=20000
-automated.show.time=40000
-automated.info=screen
-team.double.video=false
-
-ticker.rotate.time=10000
-ticker.logo=#Clock#;ВКОШП 2019
-ticker.logo.time=5000
-ticker.clock.time=20000
-ticker.logo.change.time=1000
-
-queue.show.verdict=true
-
-overlayed.delay=3000
-
-top.teams=S101,S111,S306,S105
-onsite.teams=S.*
-
-stylesheet=stylesheets/wf.jss
-
-polls.backup.file=polls.txt
-poll.show.time=20000
-poll.top.teams=5
-
-twitch.chat.server=irc.chat.twitch.tv
-twitch.chat.username=aksenov239
-twitch.chat.password=oauth:8yb7ygy3ey2wdwmlkvd7bs2o8guwf3
-twitch.chat.channel=#aksenov239;#icpclive1;#icpclive_ru
-
-twitter.hashtag=#ВКОШП2019
-
-word.statistics.backup.file=words-statistics.txt
-word.statistics.words=tweets;goose;energy
-word.statistics.tweets.text=$tweets$
-word.statistics.tweets.picture=
-word.statistics.goose.text=(*)>
-word.statistics.goose.picture=pics/goose.jpg
-word.statistics.energy.text=ί-- ??φ Π?_Π? ί-ι??φ
-word.statistics.energy.picture=pics/energy.jpg
-word.statistics.word.show.time=10000
diff --git a/config/vkoshp/2019/problems-practice.xml b/config/vkoshp/2019/problems-practice.xml
deleted file mode 100644
index 75334f65d..000000000
--- a/config/vkoshp/2019/problems-practice.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/config/vkoshp/2019/problems.xml b/config/vkoshp/2019/problems.xml
deleted file mode 100644
index 2ecffb2ef..000000000
--- a/config/vkoshp/2019/problems.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/vkoshp/2019/settings.json b/config/vkoshp/2019/settings.json
new file mode 100644
index 000000000..ff1843163
--- /dev/null
+++ b/config/vkoshp/2019/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"pcms",
+ "url":"http://nerc.itmo.ru/school/archive/2019-2020/ru-olymp-team-russia-2019-standings.xml"
+}
diff --git a/config/vkoshp/2022-junior/events.properties b/config/vkoshp/2022-junior/events.properties
deleted file mode 100644
index ef400816c..000000000
--- a/config/vkoshp/2022-junior/events.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-# this is config file for codeforces contests. Don't remove this line, or BOM will eat you. Insert api key and secret from https://codeforces.com/settings/api below
-cf.api.key=$creds.codeforces_key
-cf.api.secret=$creds.codeforces_secret
-contest_id=373376
-standings.type=CF
diff --git a/config/vkoshp/2022-junior/settings.json b/config/vkoshp/2022-junior/settings.json
new file mode 100644
index 000000000..8c7b2aeae
--- /dev/null
+++ b/config/vkoshp/2022-junior/settings.json
@@ -0,0 +1,7 @@
+{
+ "type": "cf",
+ "apiKey": "$creds.codeforces_key",
+ "apiSecret": "$creds.codeforces_secret",
+ "contestId": 373376
+}
+
diff --git a/config/vkoshp/2022/events.properties b/config/vkoshp/2022/events.properties
deleted file mode 100644
index c100142b5..000000000
--- a/config/vkoshp/2022/events.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-url=https://nerc.itmo.ru/school/archive/2022-2023/ru-olymp-team-russia-2022-standings.xml
-standings.type=PCMS
diff --git a/config/vkoshp/2022/settings.json b/config/vkoshp/2022/settings.json
new file mode 100644
index 000000000..5e81f59ca
--- /dev/null
+++ b/config/vkoshp/2022/settings.json
@@ -0,0 +1,4 @@
+{
+ "type":"pcms",
+ "url":"https://nerc.itmo.ru/school/archive/2022-2023/ru-olymp-team-russia-2022-standings.xml"
+}
diff --git a/config/vkoshp/2023-junior/events.properties b/config/vkoshp/2023-junior/events.properties
deleted file mode 100644
index 6b288eec6..000000000
--- a/config/vkoshp/2023-junior/events.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-# this is config file for codeforces contests. Don't remove this line, or BOM will eat you. Insert api key and secret from https://codeforces.com/settings/api below
-cf.api.key=$creds.codeforces_key
-cf.api.secret=$creds.codeforces_secret
-contest_id=432594
-standings.type=CF
\ No newline at end of file
diff --git a/config/vkoshp/2023-junior/settings.json b/config/vkoshp/2023-junior/settings.json
new file mode 100644
index 000000000..2c2f73285
--- /dev/null
+++ b/config/vkoshp/2023-junior/settings.json
@@ -0,0 +1,6 @@
+{
+ "type": "cf",
+ "apiKey": "$creds.codeforces_key",
+ "apiSecret": "$creds.codeforces_secret",
+ "contestId": 432594
+}
diff --git a/advanced.json.md b/docs/advanced.json.md
similarity index 91%
rename from advanced.json.md
rename to docs/advanced.json.md
index 55ccaeb25..b11b8e67b 100644
--- a/advanced.json.md
+++ b/docs/advanced.json.md
@@ -1,3 +1,6 @@
+This doc is a bit outdated, although it is still a good source of examples.
+Full description of all properties supported can be found [here](https://icpc.io/live-v3/cds/-i-c-p-c-live%20contest%20data%20parser/org.icpclive.api.tunning/-advanced-properties/index.html)
+
# How to setup advanced.json
Apart from ```events.properties``` file, each contest can adjust imported from contest management system using ```advanced.json``` file.
@@ -14,7 +17,7 @@ You can adjust received participant information for each separate participant us
"hashTag": "#ItMo",
"groups": ["SPb ITMO", "SPb"],
"isHidden": false,
- "isOutOfCompetition": false,
+ "isOutOfContest": false,
"medias": {
"screen": {
"type": "Video",
@@ -30,7 +33,7 @@ You can adjust received participant information for each separate participant us
}
```
-`isHidden` and `isOutOfCompetition` can be be applied to groups:
+`isHidden` and `isOutOfContest` can be be applied to groups:
```
"groupOverrides": {
"test": {"isOutOfContest":true}
@@ -38,7 +41,7 @@ You can adjust received participant information for each separate participant us
```
`isHidden`: allows to hide a team or a group of teams from everywhere
-`isOutOfCompetition`: replaces team place with * sign, but still shows the team in testing queue, leaderboard and others.
+`isOutOfContest`: replaces team place with * sign, but still shows the team in testing queue, leaderboard and others.
Also, you can create a template rule for medias, and it would be applied to all teams.
diff --git a/docs/development.md b/docs/development.md
new file mode 100644
index 000000000..1ceed57e5
--- /dev/null
+++ b/docs/development.md
@@ -0,0 +1,126 @@
+# Run in development mode
+
+Requirements:
+
+* gradle
+* jdk
+* node:16
+* browser
+
+Before cloning on Windows configure correct crlf handling
+
+* `git config --global core.autocrlf false`
+* `git config --global core.symlinks true`
+
+## Developing backend
+
+### To test your changes:
+
+1. `live-v3\gradlew :backend:run -Plive.dev.contest=nerc-onsite-2020`
+ * Or run one of configurations from IDEA stored in .run
+2. open http://localhost:8080/admin to control overlay
+3. open http://localhost:8080/overlay to view result
+
+### General backend architecture
+
+Backend is implemented in kotlin as [ktor](https://ktor.io/docs/) server.
+
+Admin api endpoints are `/api/admin`. They are using REST-like conventions for naming,
+and mostly implemented in `org.icpclive.admin` package. All data is stored in json-files in
+contest config directory for now.
+
+Overlay api endpoints are `/api/overlay`. They are websockets with updates, read by
+overlay frontend part. Internally, they are implemented
+as [flows](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/)
+from kotlinx.coroutines.
+
+Admin and overlay can be hosted over `/admin` and `/overlay` paths as SPA using ktor builtin
+SPA hosting.
+
+Contest systems integrations are implemented in `org.icpclive.cds` package. Currently,
+CLICS, PCMS, Codeforces and Yandex.Contest, Ejudge and KRSU are supported. Only ICPC mode
+is supported at the moment.
+
+Basically, to add new contest data provider, you need to implement contest information updates
+(start time, list of problems, list of teams, etc.) and runs updates (events like new run, run status changes, partial
+and final testing). In simple cases, if you reload all data every time, it can be useful to inherit from FullReloadContestDataSource.
+
+Everything else should work automatically in the same manner for all CDS sources.
+
+### Emulation mode
+
+If `elmulation.startTime` property is defined, instead of regular updating, cds provider need to download all runs once,
+and
+they would be timely pushed further automatically. This is useful to check everything on already happened contest.
+
+```
+emulation.speed=10
+emulation.startTime=2022-04-03 22:50
+```
+
+Emulation only works if contest is finished.
+
+## Developing frontend
+
+We have two front end packages:
+
+* overlay - webapp that is rendered in OBS (located in `overlay`)
+* admin - admin app for controlling the overlay (located in `admin`)
+
+Install dependencies with `npm ci` in the root path of the project
+(see package.json for more details)
+
+### Running frontend separate from backend
+
+If you are running locally replace `` with `localhost`
+
+#### overlay
+
+Overlay takes base url from environment variable `REACT_APP_WEBSOCKET_URL`
+A path to backend's path for websocket connection.
+Exposed on /api/overlay path
+
+Run this in `overlay` directory to start the development server:
+Linux:
+
+```
+REACT_APP_WEBSOCKET_URL=ws://:8080/api/overlay npm run start
+```
+
+Windows:
+
+```
+set REACT_APP_WEBSOCKET_URL=ws://:8080/api/overlay
+npm run start
+```
+
+#### admin
+
+Admin panel takes two urls:
+
+* `REACT_APP_BACKEND_URL` - for updating data and talking to the backend (exposed in /api/admin)
+* `REACT_APP_WEBSOCKET_URL` - for real time updates of presets and settings (exposed in /api/admin)
+
+Run this in `admin` directory to start the development server:
+Linux:
+
+```
+REACT_APP_BACKEND_URL=http://:8080/api/admin;REACT_APP_WEBSOCKET_URL=ws://:8080/api/admin npm run start
+```
+
+Windows:
+
+```
+set REACT_APP_BACKEND_URL=http://:8080/api/admin
+set REACT_APP_WEBSOCKET_URL=ws://:8080/api/admin
+npm run start
+```
+
+# Run tests
+
+Create release in artifacts, then run:
+```bash
+npm ci
+npx playwright install --with-deps
+npx playwright test
+```
diff --git a/docs/emulation.md b/docs/emulation.md
new file mode 100644
index 000000000..77f32265c
--- /dev/null
+++ b/docs/emulation.md
@@ -0,0 +1,33 @@
+### Emulation mode
+
+Emulation mode is useful to check everything on already happened contest.
+
+If emulation is defined, instead of regular updating data,
+cds provider would download everything once, and events would be timely pushed further automatically.
+
+Also, emulation can be speeded up several times for faster testing.
+
+To enable the emulation mode, add following in your `settings.json` file
+```
+{
+ "emulation": {
+ "speed": 10,
+ "startTime": "2022-04-03 22:50"
+ }
+}
+```
+
+Or, if you are using legacy `events.properties` format:
+
+```
+emulation.speed=10
+emulation.startTime=2022-04-03 22:50
+```
+
+This means that overlay would pretend that the contest was started at 22:50
+local time at the 4-th of March 2022. This is recommended format of time, although
+some others would be parsed. Also, you can write `now` and it would be converted to time when
+overlay was started.
+
+
+Emulation only works if the contest is finished.
diff --git a/docs/settings.md b/docs/settings.md
new file mode 100644
index 000000000..57602e994
--- /dev/null
+++ b/docs/settings.md
@@ -0,0 +1,43 @@
+## TL;DR
+
+* Examples [contests](https://github.com/icpc/live-v3/tree/main/config/_examples) for all supported contest systems
+ * [CLICS](https://github.com/icpc/live-v3/tree/main/config/icpc-rmc/2021)
+ * [PCMS](https://github.com/icpc/live-v3/tree/main/config/icpc-nef/2021-2022/main)
+ * [Codeforces](https://github.com/icpc/live-v3/tree/main/config/vkoshp/2022-junior)
+* See the [full archive](https://github.com/icpc/live-v3/tree/main/config) for more examples
+
+## Config file
+
+Main config should be stored within config directory in `settings.json` or `settings.json5` file.
+In some outdated examples legacy `events.properties` format is used instead.
+
+Settings should specify the contest system used and parameters of the contest.
+Also, it sometimes contains some abilities to modify received data.
+
+You can use [json schema file](https://github.com/icpc/live-v3/tree/main/schemas/settings.schema.json) in your text editor to get help with writing config.
+
+[Here](https://icpc.io/live-v3/cds/-i-c-p-c-live%20contest%20data%20parser/org.icpclive.cds.settings/-c-d-s-settings/index.html)
+is the full list of supported properties for all systems.
+
+Typical config should look like that
+
+```
+// settings.json file in your config directory
+{
+ "type": "cf",
+ "apiKey": "$creds.cf_api_key",
+ "apiSecret": "$creds.cf_api_secret",
+ "contestId": 1600,
+ "emulation": { "speed": 10, "startTime": "2023-08-24 22:43"}, // remove this if you don't need emulation
+}
+// creds.json file somewhere else passed with --creds option
+{
+ "cf_api_key": "YOUR CODEFORCES API KEY",
+ "cf_api_secret": "YOUR CODEFORCES API SECRET",
+}
+```
+
+Other contest systems have different arguments than apiKey/apiSecret/contestId but the main idea is the same.
+
+Separate creds file is needed to avoid accidential publishing of your keys.
+If you don't plan to publish config file you can just put key into it instead of a separate file.
\ No newline at end of file
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
new file mode 100644
index 000000000..42f1dccbb
--- /dev/null
+++ b/docs/troubleshooting.md
@@ -0,0 +1,20 @@
+# Typical problems
+
+## Overlay backend is not starting or sends no data
+
+* Check `icpclive.log` file, there are probably some useful exceptions
+ * If it has some SSL exceptions
+ * Add `"network": { "allowUnsecureConnections": true }` into your settings file,
+ if you are fine with ignoring certificate check
+ * If there are some FileNotFound exceptions
+ * Check your command line arguments, maybe some pathes are relative to unexpected source
+ * If there are some other crashes
+ * Sorry, report a bug to us
+* Check frontend log by opening `http://localhost:8080/overlay` in browser and
+ scrolling down.
+
+## Overlay works, but no updates after some time
+
+* If you are using clics check your clics server has keep-alive enabled
+* If you are using codeforces, check if you are not banned by their anti-ddos.
+ * Write to Mike if you are :(
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 4b705a7a9..1cab3ddc2 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -2,5 +2,7 @@ kotlin.code.style=official
build_version=dev
#change this to `false` to use system installed npm
-npm.download=false
+npm.download=true
org.gradle.parallel=true
+org.gradle.caching=true
+live.dev.embedFrontend=true
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 8eea63745..0ccfa89d0 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,30 +1,35 @@
[versions]
-ktor = "2.3.0" # https://ktor.io/
+ktor = "2.3.3" # https://ktor.io/
datetime = "0.4.0" # https://github.com/Kotlin/kotlinx-datetime
-serialization = "1.5.1" # https://github.com/Kotlin/kotlinx.serialization
-kotlin = "1.8.21"
-logback = "1.4.7" # https://logback.qos.ch/download.html
-node-plugin = "4.0.0" # https://github.com/node-gradle/gradle-node-plugin
-coroutines = "1.7.0" # https://github.com/Kotlin/kotlinx.coroutines/
-exposed = "0.41.1" # https://github.com/JetBrains/Exposed
-telegram-bot = "6.0.7" # https://github.com/kotlin-telegram-bot/kotlin-telegram-bot
+serialization = "1.6.0" # https://github.com/Kotlin/kotlinx.serialization
+kotlin = "1.9.10"
+slf4j = "1.7.36" # https://www.slf4j.org/download.html
+logback = "1.4.11" # https://logback.qos.ch/download.html
+node-plugin = "7.0.0" # https://github.com/node-gradle/gradle-node-plugin
+coroutines = "1.7.3" # https://github.com/Kotlin/kotlinx.coroutines/
+exposed = "0.42.1" # https://github.com/JetBrains/Exposed
+telegram-bot = "6.1.0" # https://github.com/kotlin-telegram-bot/kotlin-telegram-bot
shadow-plugin = "8.1.1" # https://github.com/johnrengelman/shadow
-sqlite = "3.41.2.1" # https://github.com/xerial/sqlite-jdbc
-clikt = "3.5.2" # https://ajalt.github.io/clikt/
+sqlite = "3.42.0.0" # https://github.com/xerial/sqlite-jdbc
+clikt = "4.2.0" # https://ajalt.github.io/clikt/
immutable = "0.3.5" # https://github.com/Kotlin/kotlinx.collections.immutable
+protobuf-plugin = "0.9.4" # https://github.com/google/protobuf-gradle-plugin
+protobuf = "3.24.1" # https://mvnrepository.com/artifact/com.google.protobuf/protobuf-kotlin
+grpc = "1.57.0" # https://github.com/grpc/grpc
+grpc-kotlin = "1.3.1" # https://github.com/grpc/grpc-kotlin
+dokka = "1.8.20" # https://github.com/Kotlin/dokka
+retrofit = "2.9.0" # https://mvnrepository.com/artifact/com.squareup.retrofit2/retrofit/2.9.0
+json5 = "0.3.0" # https://github.com/xn32/json5k
[libraries]
ktor-client-cio = { version.ref = "ktor", group = "io.ktor", name = "ktor-client-cio" }
ktor-client-auth = { version.ref = "ktor", group = "io.ktor", name = "ktor-client-auth" }
-ktor-client-websockets = { version.ref = "ktor", group = "io.ktor", name = "ktor-client-websockets" }
-ktor-client-logging = { version.ref = "ktor", group = "io.ktor", name = "ktor-client-logging" }
ktor-serialization-kotlinx-json = { version.ref = "ktor", group = "io.ktor", name = "ktor-serialization-kotlinx-json" }
-ktor-server-tests = { version.ref = "ktor", group = "io.ktor", name = "ktor-server-tests" }
-ktor-server-autoHeadResponse = { version.ref = "ktor", group = "io.ktor", name = "ktor-server-auto-head-response" }
ktor-server-auth = { version.ref = "ktor", group = "io.ktor", name = "ktor-server-auth" }
+ktor-server-autoHeadResponse = { version.ref = "ktor", group = "io.ktor", name = "ktor-server-auto-head-response" }
ktor-server-callLogging = { version.ref = "ktor", group = "io.ktor", name = "ktor-server-call-logging" }
ktor-server-contentNegotiation = { version.ref = "ktor", group = "io.ktor", name = "ktor-server-content-negotiation" }
ktor-server-core = { version.ref = "ktor", group = "io.ktor", name = "ktor-server-core" }
@@ -32,36 +37,49 @@ ktor-server-cors = { version.ref = "ktor", group = "io.ktor", nam
ktor-server-defaultHeaders = { version.ref = "ktor", group = "io.ktor", name = "ktor-server-default-headers" }
ktor-server-netty = { version.ref = "ktor", group = "io.ktor", name = "ktor-server-netty" }
ktor-server-statusPages = { version.ref = "ktor", group = "io.ktor", name = "ktor-server-status-pages" }
+ktor-server-tests = { version.ref = "ktor", group = "io.ktor", name = "ktor-server-tests" }
ktor-server-websockets = { version.ref = "ktor", group = "io.ktor", name = "ktor-server-websockets" }
-
-kotlinx-datetime = { version.ref = "datetime", group = "org.jetbrains.kotlinx", name = "kotlinx-datetime" }
+kotlinx-datetime = { version.ref = "datetime", group = "org.jetbrains.kotlinx", name = "kotlinx-datetime" }
kotlinx-serialization-json = { version.ref = "serialization", group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json" }
-kotlinx-coroutines-core = { version.ref = "coroutines", group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core" }
+kotlinx-serialization-properties = { version.ref = "serialization", group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-properties" }
+kotlinx-coroutines-core = { version.ref = "coroutines", group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core" }
kotlinx-collections-immutable = { version.ref = "immutable", group = "org.jetbrains.kotlinx", name = "kotlinx-collections-immutable"}
+kotlinx-serialization-json5 = { version.ref = "json5", group = "io.github.xn32", name = "json5k" }
+
-kotlin-serialization-plugin = { version.ref = "kotlin", group = "org.jetbrains.kotlin", name = "kotlin-serialization" }
-kotlin-gradle-plugin = { version.ref = "kotlin", group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin" }
-kotlin-junit = { version.ref = "kotlin", group = "org.jetbrains.kotlin", name = "kotlin-test-junit" }
+kotlin-junit = { version.ref = "kotlin", group = "org.jetbrains.kotlin", name = "kotlin-test-junit5" }
+kotlin-reflect = { version.ref = "kotlin", group = "org.jetbrains.kotlin", name = "kotlin-reflect" }
exposed-core = { version.ref = "exposed", group = "org.jetbrains.exposed", name = "exposed-core"}
-exposed-dao = { version.ref = "exposed", group = "org.jetbrains.exposed", name = "exposed-dao"}
+exposed-dao = { version.ref = "exposed", group = "org.jetbrains.exposed", name = "exposed-dao"}
exposed-jdbc = { version.ref = "exposed", group = "org.jetbrains.exposed", name = "exposed-jdbc"}
+slf4j = { version.ref = "slf4j", group = "org.slf4j", name = "slf4j-api" }
logback = { version.ref = "logback", group = "ch.qos.logback", name = "logback-classic" }
telegram-bot = { version.ref = "telegram-bot", group = "io.github.kotlin-telegram-bot.kotlin-telegram-bot", name = "telegram" }
-
+retrofit = { version.ref = "retrofit", group = "com.squareup.retrofit2", name = "retrofit" }
db-sqlite = { version.ref = "sqlite", group = "org.xerial", name = "sqlite-jdbc" }
cli = { version.ref = "clikt", group = "com.github.ajalt.clikt", name = "clikt" }
+grpc-netty = { version.ref = "grpc", group = "io.grpc", name = "grpc-netty" }
+grpc-protobuf = { version.ref = "grpc", group = "io.grpc", name = "grpc-protobuf" }
+grpc-stub = { version.ref = "grpc-kotlin", group = "io.grpc", name = "grpc-kotlin-stub" }
+grpc-gen-java = { version.ref = "grpc", group = "io.grpc", name = "protoc-gen-grpc-java" }
+grpc-gen-kotlin = { version.ref = "grpc-kotlin", group = "io.grpc", name = "protoc-gen-grpc-kotlin" }
+
+protobuf = { version.ref = "protobuf", group = "com.google.protobuf", name = "protobuf-kotlin" }
+protoc = { version.ref = "protobuf", group = "com.google.protobuf", name = "protoc" }
+
[plugins]
-ktor = { id = "io.ktor.plugin", version.ref = "ktor" }
node = { id = "com.github.node-gradle.node", version.ref = "node-plugin" }
shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow-plugin" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
-kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
\ No newline at end of file
+kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
+protobuf = { id = "com.google.protobuf", version.ref = "protobuf-plugin" }
+dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" }
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index c1962a79e..033e24c4c 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 37aef8d3f..9f4197d5f 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index aeb74cbb4..fcb6fca14 100755
--- a/gradlew
+++ b/gradlew
@@ -130,10 +130,13 @@ location of your Java installation."
fi
else
JAVACMD=java
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 000000000..4cefbcf4b
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,96 @@
+{
+ "name": "live-v3",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "live-v3",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "fsevents": "^2.3.2",
+ "playwright-core": "^1.32.3",
+ "ws": "^8.13.0"
+ },
+ "devDependencies": {
+ "@playwright/test": "^1.32.3",
+ "@types/ws": "^8.5.5"
+ }
+ },
+ "node_modules/@playwright/test": {
+ "version": "1.32.3",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.32.3.tgz",
+ "integrity": "sha512-BvWNvK0RfBriindxhLVabi8BRe3X0J9EVjKlcmhxjg4giWBD/xleLcg2dz7Tx0agu28rczjNIPQWznwzDwVsZQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*",
+ "playwright-core": "1.32.3"
+ },
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "optionalDependencies": {
+ "fsevents": "2.3.2"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "18.16.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.0.tgz",
+ "integrity": "sha512-BsAaKhB+7X+H4GnSjGhJG9Qi8Tw+inU9nJDwmD5CgOmBLEI6ArdhikpLX7DjbjDRDTbqZzU2LSQNZg8WGPiSZQ==",
+ "dev": true
+ },
+ "node_modules/@types/ws": {
+ "version": "8.5.5",
+ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz",
+ "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "hasInstallScript": true,
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/playwright-core": {
+ "version": "1.32.3",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.32.3.tgz",
+ "integrity": "sha512-SB+cdrnu74ZIn5Ogh/8278ngEh9NEEV0vR4sJFmK04h2iZpybfbqBY0bX6+BLYWVdV12JLLI+JEFtSnYgR+mWg==",
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/ws": {
+ "version": "8.13.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
+ "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 000000000..b27a682db
--- /dev/null
+++ b/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "live-v3",
+ "version": "1.0.0",
+ "description": "Welcome to the ICPC Live Source Code Repository.",
+ "main": "index.js",
+ "dependencies": {
+ "fsevents": "^2.3.2",
+ "playwright-core": "^1.32.3",
+ "ws": "^8.13.0"
+ },
+ "devDependencies": {
+ "@playwright/test": "^1.32.3",
+ "@types/ws": "^8.5.5"
+ },
+ "scripts": {},
+ "keywords": [],
+ "author": "",
+ "license": "ISC"
+}
diff --git a/playwright.config.js b/playwright.config.js
new file mode 100644
index 000000000..e2c58bf0c
--- /dev/null
+++ b/playwright.config.js
@@ -0,0 +1,44 @@
+// @ts-check
+import { defineConfig, devices } from "@playwright/test";
+
+/**
+ * Read environment variables from file.
+ * https://github.com/motdotla/dotenv
+ */
+// require('dotenv').config();
+
+/**
+ * @see https://playwright.dev/docs/test-configuration
+ */
+module.exports = defineConfig({
+ testDir: "./tests",
+ /* Run tests in files in parallel */
+ fullyParallel: true,
+ /* Fail the build on CI if you accidentally left test.only in the source code. */
+ forbidOnly: !!process.env.CI,
+ /* No retries */
+ retries: 0,
+ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
+ reporter: "html",
+ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
+ use: {
+ /* Base URL to use in actions like `await page.goto('/')`. */
+ baseURL: "http://127.0.0.1:8080",
+
+ /* Collect trace for failing tests. See https://playwright.dev/docs/trace-viewer */
+ trace: "retain-on-failure",
+ },
+ /* Set timeout for each test to 2 minute */
+ timeout: 2 * 60 * 1000,
+ /* Configure projects for major browsers */
+ projects: [
+ {
+ name: "chromium",
+ use: {
+ ...devices["Desktop Chrome"],
+ viewport: { width: 1920, height: 1080 },
+ },
+ },
+ ],
+});
+
diff --git a/run.bat b/run.bat
index cf3a3a36f..8912155b6 100644
--- a/run.bat
+++ b/run.bat
@@ -1 +1 @@
-java -jar artifacts/live-v3-dev.jar -port=8080 -P:live.configDirectory=config/sgu/ -P:live.credsFile=artifacts/creds.json
+java -jar artifacts/live-v3-dev.jar --port=8080 --config-directory=config/atcoder/wtf22-day2/ --creds=artifacts/creds.json
diff --git a/runtests.bat b/runtests.bat
new file mode 100644
index 000000000..b5dc00443
--- /dev/null
+++ b/runtests.bat
@@ -0,0 +1,3 @@
+call npm ci
+call npx playwright install --with-deps
+call npx playwright test
\ No newline at end of file
diff --git a/schemas/advanced.schema.json b/schemas/advanced.schema.json
new file mode 100644
index 000000000..183265bb6
--- /dev/null
+++ b/schemas/advanced.schema.json
@@ -0,0 +1,2644 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://github.com/icpc/live-v3/blob/main/schemas/advanced.schema.json",
+ "title": "ICPC live advanced settings",
+ "type": "object",
+ "properties": {
+ "startTime": {
+ "type": "string"
+ },
+ "freezeTimeSeconds": {
+ "type": "integer"
+ },
+ "holdTimeSeconds": {
+ "type": "integer"
+ },
+ "teamMediaTemplate": {
+ "type": "object",
+ "properties": {
+ "camera": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Object"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Photo"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "TaskStatus"
+ },
+ "teamId": {
+ "type": "integer"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "teamId"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Video"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCGrabberConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "peerName": {
+ "type": "string"
+ },
+ "streamType": {
+ "type": "string"
+ },
+ "credential": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url",
+ "peerName",
+ "streamType",
+ "credential"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCProxyConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "audioUrl": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ }
+ ]
+ },
+ "screen": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Object"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Photo"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "TaskStatus"
+ },
+ "teamId": {
+ "type": "integer"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "teamId"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Video"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCGrabberConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "peerName": {
+ "type": "string"
+ },
+ "streamType": {
+ "type": "string"
+ },
+ "credential": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url",
+ "peerName",
+ "streamType",
+ "credential"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCProxyConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "audioUrl": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ }
+ ]
+ },
+ "record": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Object"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Photo"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "TaskStatus"
+ },
+ "teamId": {
+ "type": "integer"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "teamId"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Video"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCGrabberConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "peerName": {
+ "type": "string"
+ },
+ "streamType": {
+ "type": "string"
+ },
+ "credential": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url",
+ "peerName",
+ "streamType",
+ "credential"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCProxyConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "audioUrl": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ }
+ ]
+ },
+ "photo": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Object"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Photo"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "TaskStatus"
+ },
+ "teamId": {
+ "type": "integer"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "teamId"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Video"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCGrabberConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "peerName": {
+ "type": "string"
+ },
+ "streamType": {
+ "type": "string"
+ },
+ "credential": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url",
+ "peerName",
+ "streamType",
+ "credential"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCProxyConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "audioUrl": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ }
+ ]
+ },
+ "reactionVideo": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Object"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Photo"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "TaskStatus"
+ },
+ "teamId": {
+ "type": "integer"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "teamId"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Video"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCGrabberConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "peerName": {
+ "type": "string"
+ },
+ "streamType": {
+ "type": "string"
+ },
+ "credential": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url",
+ "peerName",
+ "streamType",
+ "credential"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCProxyConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "audioUrl": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ }
+ ]
+ },
+ "achievement": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Object"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Photo"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "TaskStatus"
+ },
+ "teamId": {
+ "type": "integer"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "teamId"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Video"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCGrabberConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "peerName": {
+ "type": "string"
+ },
+ "streamType": {
+ "type": "string"
+ },
+ "credential": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url",
+ "peerName",
+ "streamType",
+ "credential"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCProxyConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "audioUrl": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ }
+ ]
+ }
+ }
+ },
+ "teamOverrideTemplate": {
+ "type": "object",
+ "properties": {
+ "displayName": {
+ "type": "string"
+ },
+ "fullName": {
+ "type": "string"
+ },
+ "medias": {
+ "type": "object",
+ "properties": {
+ "camera": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Object"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Photo"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "TaskStatus"
+ },
+ "teamId": {
+ "type": "integer"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "teamId"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Video"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCGrabberConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "peerName": {
+ "type": "string"
+ },
+ "streamType": {
+ "type": "string"
+ },
+ "credential": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url",
+ "peerName",
+ "streamType",
+ "credential"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCProxyConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "audioUrl": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ }
+ ]
+ },
+ "screen": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Object"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Photo"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "TaskStatus"
+ },
+ "teamId": {
+ "type": "integer"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "teamId"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Video"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCGrabberConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "peerName": {
+ "type": "string"
+ },
+ "streamType": {
+ "type": "string"
+ },
+ "credential": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url",
+ "peerName",
+ "streamType",
+ "credential"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCProxyConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "audioUrl": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ }
+ ]
+ },
+ "record": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Object"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Photo"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "TaskStatus"
+ },
+ "teamId": {
+ "type": "integer"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "teamId"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Video"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCGrabberConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "peerName": {
+ "type": "string"
+ },
+ "streamType": {
+ "type": "string"
+ },
+ "credential": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url",
+ "peerName",
+ "streamType",
+ "credential"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCProxyConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "audioUrl": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ }
+ ]
+ },
+ "photo": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Object"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Photo"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "TaskStatus"
+ },
+ "teamId": {
+ "type": "integer"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "teamId"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Video"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCGrabberConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "peerName": {
+ "type": "string"
+ },
+ "streamType": {
+ "type": "string"
+ },
+ "credential": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url",
+ "peerName",
+ "streamType",
+ "credential"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCProxyConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "audioUrl": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ }
+ ]
+ },
+ "reactionVideo": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Object"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Photo"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "TaskStatus"
+ },
+ "teamId": {
+ "type": "integer"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "teamId"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Video"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCGrabberConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "peerName": {
+ "type": "string"
+ },
+ "streamType": {
+ "type": "string"
+ },
+ "credential": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url",
+ "peerName",
+ "streamType",
+ "credential"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCProxyConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "audioUrl": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ }
+ ]
+ },
+ "achievement": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Object"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Photo"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "TaskStatus"
+ },
+ "teamId": {
+ "type": "integer"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "teamId"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Video"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCGrabberConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "peerName": {
+ "type": "string"
+ },
+ "streamType": {
+ "type": "string"
+ },
+ "credential": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url",
+ "peerName",
+ "streamType",
+ "credential"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCProxyConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "audioUrl": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ }
+ ]
+ }
+ }
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ ]
+ },
+ "teamRegexes": {
+ "type": "object",
+ "properties": {
+ "organizationRegex": {
+ "type": "string"
+ },
+ "customFields": {
+ "type": "object",
+ "patternProperties": {
+ ".*": {
+ "type": "string"
+ }
+ }
+ },
+ "groupRegex": {
+ "type": "object",
+ "patternProperties": {
+ ".*": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ ]
+ },
+ "teamOverrides": {
+ "type": "object",
+ "patternProperties": {
+ ".*": {
+ "type": "object",
+ "properties": {
+ "fullName": {
+ "type": "string"
+ },
+ "displayName": {
+ "type": "string"
+ },
+ "groups": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "organizationId": {
+ "type": "string"
+ },
+ "hashTag": {
+ "type": "string"
+ },
+ "medias": {
+ "type": "object",
+ "properties": {
+ "camera": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Object"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Photo"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "TaskStatus"
+ },
+ "teamId": {
+ "type": "integer"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "teamId"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Video"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCGrabberConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "peerName": {
+ "type": "string"
+ },
+ "streamType": {
+ "type": "string"
+ },
+ "credential": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url",
+ "peerName",
+ "streamType",
+ "credential"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCProxyConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "audioUrl": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ }
+ ]
+ },
+ "screen": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Object"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Photo"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "TaskStatus"
+ },
+ "teamId": {
+ "type": "integer"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "teamId"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Video"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCGrabberConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "peerName": {
+ "type": "string"
+ },
+ "streamType": {
+ "type": "string"
+ },
+ "credential": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url",
+ "peerName",
+ "streamType",
+ "credential"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCProxyConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "audioUrl": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ }
+ ]
+ },
+ "record": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Object"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Photo"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "TaskStatus"
+ },
+ "teamId": {
+ "type": "integer"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "teamId"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Video"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCGrabberConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "peerName": {
+ "type": "string"
+ },
+ "streamType": {
+ "type": "string"
+ },
+ "credential": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url",
+ "peerName",
+ "streamType",
+ "credential"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCProxyConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "audioUrl": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ }
+ ]
+ },
+ "photo": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Object"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Photo"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "TaskStatus"
+ },
+ "teamId": {
+ "type": "integer"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "teamId"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Video"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCGrabberConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "peerName": {
+ "type": "string"
+ },
+ "streamType": {
+ "type": "string"
+ },
+ "credential": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url",
+ "peerName",
+ "streamType",
+ "credential"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCProxyConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "audioUrl": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ }
+ ]
+ },
+ "reactionVideo": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Object"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Photo"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "TaskStatus"
+ },
+ "teamId": {
+ "type": "integer"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "teamId"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Video"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCGrabberConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "peerName": {
+ "type": "string"
+ },
+ "streamType": {
+ "type": "string"
+ },
+ "credential": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url",
+ "peerName",
+ "streamType",
+ "credential"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCProxyConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "audioUrl": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ }
+ ]
+ },
+ "achievement": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Object"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Photo"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "TaskStatus"
+ },
+ "teamId": {
+ "type": "integer"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "teamId"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "Video"
+ },
+ "url": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCGrabberConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "peerName": {
+ "type": "string"
+ },
+ "streamType": {
+ "type": "string"
+ },
+ "credential": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url",
+ "peerName",
+ "streamType",
+ "credential"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "WebRTCProxyConnection"
+ },
+ "url": {
+ "type": "string"
+ },
+ "audioUrl": {
+ "type": "string"
+ },
+ "isMedia": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ }
+ ]
+ }
+ }
+ },
+ "customFields": {
+ "type": "object",
+ "patternProperties": {
+ ".*": {
+ "type": "string"
+ }
+ }
+ },
+ "isHidden": {
+ "type": "boolean"
+ },
+ "isOutOfContest": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ ]
+ }
+ }
+ },
+ "groupOverrides": {
+ "type": "object",
+ "patternProperties": {
+ ".*": {
+ "type": "object",
+ "properties": {
+ "isHidden": {
+ "type": "boolean"
+ },
+ "isOutOfContest": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ ]
+ }
+ }
+ },
+ "organizationOverrides": {
+ "type": "object",
+ "patternProperties": {
+ ".*": {
+ "type": "object",
+ "properties": {
+ "displayName": {
+ "type": "string"
+ },
+ "fullName": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ ]
+ }
+ }
+ },
+ "problemOverrides": {
+ "type": "object",
+ "patternProperties": {
+ ".*": {
+ "type": "object",
+ "properties": {
+ "displayName": {
+ "type": "string"
+ },
+ "fullName": {
+ "type": "string"
+ },
+ "color": {
+ "type": "string"
+ },
+ "ordinal": {
+ "type": "integer"
+ },
+ "minScore": {
+ "type": "number"
+ },
+ "maxScore": {
+ "type": "number"
+ },
+ "scoreMergeMode": {
+ "enum": [
+ "MAX_PER_GROUP",
+ "MAX_TOTAL",
+ "LAST",
+ "LAST_OK",
+ "SUM"
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ ]
+ }
+ }
+ },
+ "scoreboardOverrides": {
+ "type": "object",
+ "properties": {
+ "medals": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "count": {
+ "type": "integer"
+ },
+ "minScore": {
+ "type": "number"
+ },
+ "tiebreakMode": {
+ "enum": [
+ "NONE",
+ "ALL"
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "name",
+ "count"
+ ]
+ }
+ },
+ "penaltyPerWrongAttempt": {
+ "type": "integer"
+ },
+ "showTeamsWithoutSubmissions": {
+ "type": "boolean"
+ },
+ "penaltyRoundingMode": {
+ "enum": [
+ "each_submission_down_to_minute",
+ "sum_down_to_minute",
+ "sum_in_seconds",
+ "last",
+ "zero"
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ ]
+}
diff --git a/schemas/settings.schema.json b/schemas/settings.schema.json
new file mode 100644
index 000000000..2568492d7
--- /dev/null
+++ b/schemas/settings.schema.json
@@ -0,0 +1,682 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://github.com/icpc/live-v3/blob/main/schemas/settings.schema.json",
+ "title": "ICPC live settings",
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "atcoder"
+ },
+ "contestId": {
+ "type": "string"
+ },
+ "sessionCookie": {
+ "type": "string"
+ },
+ "startTime": {
+ "type": "string"
+ },
+ "contestLengthSeconds": {
+ "type": "integer"
+ },
+ "emulation": {
+ "type": "object",
+ "properties": {
+ "speed": {
+ "type": "number"
+ },
+ "startTime": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "speed",
+ "startTime"
+ ]
+ },
+ "network": {
+ "type": "object",
+ "properties": {
+ "allowUnsecureConnections": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "contestId",
+ "sessionCookie",
+ "startTime",
+ "contestLengthSeconds"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "cf"
+ },
+ "contestId": {
+ "type": "integer"
+ },
+ "apiKey": {
+ "type": "string"
+ },
+ "apiSecret": {
+ "type": "string"
+ },
+ "asManager": {
+ "type": "boolean"
+ },
+ "emulation": {
+ "type": "object",
+ "properties": {
+ "speed": {
+ "type": "number"
+ },
+ "startTime": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "speed",
+ "startTime"
+ ]
+ },
+ "network": {
+ "type": "object",
+ "properties": {
+ "allowUnsecureConnections": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "contestId",
+ "apiKey",
+ "apiSecret"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "cats"
+ },
+ "login": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string"
+ },
+ "timeZone": {
+ "type": "string"
+ },
+ "resultType": {
+ "enum": [
+ "ICPC",
+ "IOI"
+ ]
+ },
+ "cid": {
+ "type": "string"
+ },
+ "emulation": {
+ "type": "object",
+ "properties": {
+ "speed": {
+ "type": "number"
+ },
+ "startTime": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "speed",
+ "startTime"
+ ]
+ },
+ "network": {
+ "type": "object",
+ "properties": {
+ "allowUnsecureConnections": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "login",
+ "password",
+ "url",
+ "cid"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "clics"
+ },
+ "url": {
+ "type": "string"
+ },
+ "login": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ },
+ "eventFeedName": {
+ "type": "string"
+ },
+ "feedVersion": {
+ "enum": [
+ "2020_03",
+ "2022_07"
+ ]
+ },
+ "additionalFeed": {
+ "type": "object",
+ "properties": {
+ "url": {
+ "type": "string"
+ },
+ "login": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ },
+ "eventFeedName": {
+ "type": "string"
+ },
+ "feedVersion": {
+ "enum": [
+ "2020_03",
+ "2022_07"
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "url"
+ ]
+ },
+ "useTeamNames": {
+ "type": "boolean"
+ },
+ "mediaBaseUrl": {
+ "type": "string"
+ },
+ "emulation": {
+ "type": "object",
+ "properties": {
+ "speed": {
+ "type": "number"
+ },
+ "startTime": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "speed",
+ "startTime"
+ ]
+ },
+ "network": {
+ "type": "object",
+ "properties": {
+ "allowUnsecureConnections": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "cms"
+ },
+ "url": {
+ "type": "string"
+ },
+ "activeContest": {
+ "type": "string"
+ },
+ "otherContests": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "network": {
+ "type": "object",
+ "properties": {
+ "allowUnsecureConnections": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ ]
+ },
+ "emulation": {
+ "type": "object",
+ "properties": {
+ "speed": {
+ "type": "number"
+ },
+ "startTime": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "speed",
+ "startTime"
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url",
+ "activeContest",
+ "otherContests"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "codedrills"
+ },
+ "url": {
+ "type": "string"
+ },
+ "port": {
+ "type": "integer"
+ },
+ "contestId": {
+ "type": "string"
+ },
+ "authKey": {
+ "type": "string"
+ },
+ "emulation": {
+ "type": "object",
+ "properties": {
+ "speed": {
+ "type": "number"
+ },
+ "startTime": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "speed",
+ "startTime"
+ ]
+ },
+ "network": {
+ "type": "object",
+ "properties": {
+ "allowUnsecureConnections": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url",
+ "port",
+ "contestId",
+ "authKey"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "ejudge"
+ },
+ "url": {
+ "type": "string"
+ },
+ "resultType": {
+ "enum": [
+ "ICPC",
+ "IOI"
+ ]
+ },
+ "timeZone": {
+ "type": "string"
+ },
+ "emulation": {
+ "type": "object",
+ "properties": {
+ "speed": {
+ "type": "number"
+ },
+ "startTime": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "speed",
+ "startTime"
+ ]
+ },
+ "network": {
+ "type": "object",
+ "properties": {
+ "allowUnsecureConnections": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "krsu"
+ },
+ "submissionsUrl": {
+ "type": "string"
+ },
+ "contestUrl": {
+ "type": "string"
+ },
+ "timeZone": {
+ "type": "string"
+ },
+ "emulation": {
+ "type": "object",
+ "properties": {
+ "speed": {
+ "type": "number"
+ },
+ "startTime": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "speed",
+ "startTime"
+ ]
+ },
+ "network": {
+ "type": "object",
+ "properties": {
+ "allowUnsecureConnections": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "submissionsUrl",
+ "contestUrl"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "noop"
+ },
+ "emulation": {
+ "type": "object",
+ "properties": {
+ "speed": {
+ "type": "number"
+ },
+ "startTime": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "speed",
+ "startTime"
+ ]
+ },
+ "network": {
+ "type": "object",
+ "properties": {
+ "allowUnsecureConnections": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "pcms"
+ },
+ "url": {
+ "type": "string"
+ },
+ "login": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ },
+ "problemsUrl": {
+ "type": "string"
+ },
+ "resultType": {
+ "enum": [
+ "ICPC",
+ "IOI"
+ ]
+ },
+ "emulation": {
+ "type": "object",
+ "properties": {
+ "speed": {
+ "type": "number"
+ },
+ "startTime": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "speed",
+ "startTime"
+ ]
+ },
+ "network": {
+ "type": "object",
+ "properties": {
+ "allowUnsecureConnections": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "testsys"
+ },
+ "url": {
+ "type": "string"
+ },
+ "timeZone": {
+ "type": "string"
+ },
+ "emulation": {
+ "type": "object",
+ "properties": {
+ "speed": {
+ "type": "number"
+ },
+ "startTime": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "speed",
+ "startTime"
+ ]
+ },
+ "network": {
+ "type": "object",
+ "properties": {
+ "allowUnsecureConnections": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "yandex"
+ },
+ "apiKey": {
+ "type": "string"
+ },
+ "loginRegex": {
+ "type": "string"
+ },
+ "contestId": {
+ "type": "integer"
+ },
+ "resultType": {
+ "enum": [
+ "ICPC",
+ "IOI"
+ ]
+ },
+ "emulation": {
+ "type": "object",
+ "properties": {
+ "speed": {
+ "type": "number"
+ },
+ "startTime": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "speed",
+ "startTime"
+ ]
+ },
+ "network": {
+ "type": "object",
+ "properties": {
+ "allowUnsecureConnections": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "apiKey",
+ "loginRegex",
+ "contestId"
+ ]
+ }
+ ]
+}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 43d85c628..79f6c4458 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,3 +1,8 @@
+plugins {
+ `gradle-enterprise`
+ id("org.gradle.toolchains.foojay-resolver-convention") version("0.4.0")
+}
+
rootProject.name = "live-v3"
dependencyResolutionManagement {
@@ -11,12 +16,30 @@ dependencyResolutionManagement {
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
-include(":sniper-tools", ":reactions-bot", ":common", ":cds", ":frontend", ":backend", ":cds-converter", ":faker")
-project(":sniper-tools").projectDir = file("src/sniper-tools")
-project(":common").projectDir = file("src/common")
-project(":reactions-bot").projectDir = file("src/reactions-bot")
-project(":cds").projectDir = file("src/cds")
-project(":frontend").projectDir = file("src/frontend")
+include(
+ ":backend",
+ ":cds",
+ ":cds-converter",
+ ":clics-api",
+ ":common",
+ ":frontend",
+ ":reactions-bot",
+ ":schema-generator",
+ ":sniper-tools",
+ ":faker"
+)
project(":backend").projectDir = file("src/backend")
+project(":cds").projectDir = file("src/cds")
project(":cds-converter").projectDir = file("src/cds-converter")
+project(":clics-api").projectDir = file("src/clics-api")
+project(":common").projectDir = file("src/common")
+project(":frontend").projectDir = file("src/frontend")
+project(":reactions-bot").projectDir = file("src/reactions-bot")
+project(":schema-generator").projectDir = file("src/schema-generator")
+project(":sniper-tools").projectDir = file("src/sniper-tools")
project(":faker").projectDir = file("src/faker")
+
+gradleEnterprise.buildScan {
+ termsOfServiceUrl = "https://gradle.com/terms-of-service"
+ termsOfServiceAgree = "yes"
+}
\ No newline at end of file
diff --git a/src/backend/build.gradle.kts b/src/backend/build.gradle.kts
index 0f1e6051f..c69e96dc7 100644
--- a/src/backend/build.gradle.kts
+++ b/src/backend/build.gradle.kts
@@ -1,19 +1,18 @@
+import org.gradle.kotlin.dsl.run as runTask
+
plugins {
+ application
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.kotlin.serialization)
- alias(libs.plugins.ktor)
+ alias(libs.plugins.shadow)
}
-group = "org.icpclive"
-version = rootProject.findProperty("build_version")!!
-application {
- mainClass.set("org.icpclive.ApplicationKt")
+base {
+ archivesName = rootProject.name
}
-ktor {
- fatJar {
- archiveFileName.set("${rootProject.name}-${project.version}.jar")
- }
+application {
+ mainClass = "org.icpclive.ApplicationKt"
}
kotlin {
@@ -25,55 +24,40 @@ kotlin {
}
tasks {
- named("run") {
+ runTask {
this.args = listOfNotNull(
- "-P:auth.disabled=true",
- project.properties["live.dev.credsFile"]?.let { "-P:live.credsFile=$it"},
- project.properties["live.dev.widgetPositionsFile"]?.let { "-P:live.widgetPositionsFile=$it"},
- project.properties["live.dev.contest"]?.let { "-P:live.configDirectory=$it" },
- project.properties["live.dev.allowUnsecureConnections"]?.let { "-P:live.allowUnsecureConnections=$it" },
- project.properties["live.dev.analyticsTemplatesFile"]?.let { "-P:live.analyticsTemplatesFile=$it" },
+ "--no-auth",
+ project.properties["live.dev.credsFile"]?.let { "--creds=$it" },
+ project.properties["live.dev.widgetPositionsFile"]?.let { "--widget-positions=$it" },
+ project.properties["live.dev.contest"]?.let { "--config-directory=$it" },
+ project.properties["live.dev.analyticsTemplatesFile"]?.let { "--analytics-template=$it" },
)
- this.workingDir(rootDir.resolve("config"))
- }
- task("release") {
- from(shadowJar)
- destinationDir = rootProject.rootDir.resolve("artifacts")
- }
- val jsBuildPath = project.buildDir.resolve("js")
- val copyJsAdmin = register("copyJsAdmin") {
- from(project(":frontend").tasks["npm_run_buildAdmin"])
- destinationDir = jsBuildPath.resolve("admin")
+ this.workingDir = rootDir.resolve("config")
}
- val copyJsOverlay = register("copyJsOverlay") {
- from(project(":frontend").tasks["npm_run_buildOverlay"])
- destinationDir = jsBuildPath.resolve("overlay")
- }
- register("buildJs") {
- dependsOn(copyJsAdmin, copyJsOverlay)
- outputs.dir(jsBuildPath)
- }
-}
-
-
-sourceSets {
- main {
- resources {
- srcDirs(tasks["buildJs"].outputs)
+ // Not the best way of doing this, but should work out.
+ processResources {
+ into("schemas") {
+ from(project(":schema-generator").tasks.named("generateAllSchemas"))
+ }
+ if (project.properties["live.dev.embedFrontend"] == "true") {
+ into("admin") {
+ from(project(":frontend").tasks.named("npm_run_buildAdmin"))
+ }
+ into("overlay") {
+ from(project(":frontend").tasks.named("npm_run_buildOverlay"))
+ }
}
}
}
-repositories {
- mavenCentral()
-}
-
dependencies {
- implementation(libs.logback)
+ implementation(projects.cds)
+ implementation(projects.common)
+ implementation(libs.cli)
implementation(libs.ktor.serialization.kotlinx.json)
- implementation(libs.ktor.server.autoHeadResponse)
implementation(libs.ktor.server.auth)
+ implementation(libs.ktor.server.autoHeadResponse)
implementation(libs.ktor.server.callLogging)
implementation(libs.ktor.server.contentNegotiation)
implementation(libs.ktor.server.core)
@@ -82,10 +66,8 @@ dependencies {
implementation(libs.ktor.server.netty)
implementation(libs.ktor.server.statusPages)
implementation(libs.ktor.server.websockets)
- implementation(libs.kotlinx.datetime)
- implementation(libs.kotlinx.serialization.json)
- implementation(projects.cds)
- implementation(projects.common)
+ implementation(libs.logback)
+
testImplementation(libs.kotlin.junit)
testImplementation(libs.ktor.server.tests)
-}
+}
\ No newline at end of file
diff --git a/src/backend/src/main/kotlin/org/icpclive/Application.kt b/src/backend/src/main/kotlin/org/icpclive/Application.kt
index e2c9b4184..01f9be8b2 100644
--- a/src/backend/src/main/kotlin/org/icpclive/Application.kt
+++ b/src/backend/src/main/kotlin/org/icpclive/Application.kt
@@ -15,31 +15,25 @@ import io.ktor.server.request.*
import io.ktor.server.routing.*
import io.ktor.server.util.*
import io.ktor.server.websocket.*
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
import org.icpclive.admin.configureAdminApiRouting
-import org.icpclive.api.AdvancedProperties
-import org.icpclive.cds.InfoUpdate
+import org.icpclive.api.tunning.AdvancedProperties
import org.icpclive.cds.adapters.*
+import org.icpclive.cds.settings.parseFileToCdsSettings
import org.icpclive.data.Controllers
-import org.icpclive.overlay.configureOverlayRouting
-import org.icpclive.util.*
-import org.icpclive.cds.getContestDataSourceAsFlow
import org.icpclive.data.DataBus
-import org.icpclive.service.AdvancedPropertiesService
+import org.icpclive.overlay.configureOverlayRouting
import org.icpclive.service.launchServices
+import org.icpclive.util.*
import org.slf4j.event.Level
-import java.io.FileInputStream
-import java.io.FileNotFoundException
-import java.nio.file.Files
+import java.nio.file.Paths
import java.time.Duration
-import java.util.*
+import kotlin.io.path.exists
import kotlin.system.exitProcess
-fun main(args: Array): Unit =
- io.ktor.server.netty.EngineMain.main(args)
+fun main(args: Array): Unit = Config.main(args)
private fun Application.setupKtorPlugins() {
install(DefaultHeaders)
@@ -63,7 +57,7 @@ private fun Application.setupKtorPlugins() {
masking = false
}
install(Authentication) {
- if (config.authDisabled) {
+ if (Config.authDisabled) {
val config = object : AuthenticationProvider.Config("admin-api-auth") {}
register(object : AuthenticationProvider(config) {
override suspend fun onAuthenticate(context: AuthenticationContext) {
@@ -94,11 +88,13 @@ private fun Application.setupKtorPlugins() {
@Suppress("unused") // application.yaml references the main function. This annotation prevents the IDE from marking it as unused.
fun Application.module() {
- config = Config(environment)
+ environment.log.info("Using config directory ${Config.configDirectory.toAbsolutePath()}")
+ environment.log.info("Current working directory is ${Paths.get("").toAbsolutePath()}")
setupKtorPlugins()
routing {
- staticFiles("/media", config.mediaDirectory.toFile())
+ staticFiles("/media", Config.mediaDirectory.toFile())
+ staticResources("/schemas", "schemas")
singlePageApplication {
useResources = true
applicationRoute = "admin"
@@ -124,22 +120,23 @@ fun Application.module() {
// TODO: understand why normal exception propagation doesn't work
exitProcess(1)
}
- val path = config.configDirectory.resolve("events.properties")
- if (!Files.exists(path)) throw FileNotFoundException("events.properties not found in ${config.configDirectory}")
- val properties = Properties()
- FileInputStream(path.toString()).use { properties.load(it) }
+ val path =
+ Config.configDirectory.resolve("events.properties")
+ .takeIf { it.exists() }
+ ?.also { environment.log.warn("Using events.properties is deprecated, use settings.json instead.") }
+ ?: Config.configDirectory.resolve("settings.json5").takeIf { it.exists() }
+ ?: Config.configDirectory.resolve("settings.json")
launch(handler) {
- val advancedJsonPath = config.configDirectory.resolve("advanced.json")
- val advancedPropertiesFlow = fileJsonContentFlow(advancedJsonPath, AdvancedPropertiesService.logger)
- .stateIn(this, SharingStarted.Eagerly, AdvancedProperties())
+ val advancedPropertiesFlow =
+ fileJsonContentFlow(Config.advancedJsonPath, environment.log, AdvancedProperties())
+ .stateIn(this)
DataBus.advancedPropertiesFlow.completeOrThrow(advancedPropertiesFlow)
- val loader = getContestDataSourceAsFlow(
- properties,
- config.creds,
- ).applyAdvancedProperties(advancedPropertiesFlow)
- .withRunsBefore()
+ val loader = parseFileToCdsSettings(path)
+ .toFlow(config.creds)
+ .applyAdvancedProperties(advancedPropertiesFlow)
+ .contestState()
.filterUseless()
.removeFrozenSubmissions()
.processHiddenTeamsAndGroups()
diff --git a/src/backend/src/main/kotlin/org/icpclive/Config.kt b/src/backend/src/main/kotlin/org/icpclive/Config.kt
index 8e3b35743..ca97ba76c 100644
--- a/src/backend/src/main/kotlin/org/icpclive/Config.kt
+++ b/src/backend/src/main/kotlin/org/icpclive/Config.kt
@@ -1,50 +1,72 @@
package org.icpclive
-import io.ktor.server.application.*
-import io.ktor.server.config.*
+import com.github.ajalt.clikt.core.CliktCommand
+import com.github.ajalt.clikt.core.context
+import com.github.ajalt.clikt.output.MordantHelpFormatter
+import com.github.ajalt.clikt.parameters.options.*
+import com.github.ajalt.clikt.parameters.types.*
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import org.icpclive.api.LocationRectangle
-import org.icpclive.cds.common.setAllowUnsecureConnections
-import org.icpclive.util.getCredentials
-import java.io.File
-import java.nio.file.Path
-import java.nio.file.Paths
-import java.util.*
-import kotlin.io.path.exists
-
-class Config(environment: ApplicationEnvironment) {
- private fun ApplicationConfig.stringOrNull(name: String) = propertyOrNull(name)?.getString()
- private fun ApplicationConfig.string(name: String) = property(name).getString()
- private fun ApplicationConfig.bool(name: String) = stringOrNull(name) == "true"
-
- val configDirectory: Path = environment.config.stringOrNull("live.configDirectory")
- ?.let { Paths.get(it).toAbsolutePath() }
- ?.also {
- if (!it.exists()) throw IllegalStateException("Config directory $it does not exist")
- environment.log.info("Using config directory $it")
- environment.log.info("Current working directory is ${Paths.get("").toAbsolutePath()}")
- } ?: throw IllegalStateException("Config directory should be set")
-
- private fun ApplicationConfig.directory(name: String) =
- configDirectory.resolve(string(name)).also { it.toFile().mkdirs() }
-
- val presetsDirectory: Path = environment.config.directory("live.presetsDirectory")
- val mediaDirectory: Path = environment.config.directory("live.mediaDirectory")
- val creds: Map = environment.config.stringOrNull("live.credsFile")?.let {
- Json.decodeFromStream(File(it).inputStream())
- } ?: emptyMap()
- val widgetPositions: Map =
- environment.config.stringOrNull("live.widgetPositionsFile")?.let {
- Json.decodeFromStream(File(it).inputStream())
- } ?: emptyMap()
- val allowUnsecureConnections = environment.config.bool("live.allowUnsecureConnections").also {
- setAllowUnsecureConnections(it)
+
+object Config : CliktCommand(name = "java -jar live-v3.jar", printHelpOnEmptyArgs = true) {
+ val configDirectory by option(
+ "-c", "--config-directory",
+ help = "Path to config directory"
+ ).path(mustExist = true, canBeFile = false, canBeDir = true).required()
+
+ val port: Int by option("-p", "--port", help = "Port to listen").int().default(8080)
+ val authDisabled by option(
+ "--no-auth",
+ help = "Disable http basic auth in admin"
+ ).flag()
+
+
+ val creds by option(
+ "--creds",
+ help = "Path to file with credentials"
+ ).path(mustExist = true, canBeFile = true, canBeDir = false)
+ .convert { path ->
+ path.toFile().inputStream().use { Json.decodeFromStream