From d4df57bd05cd315ff54c73412bfdaff0d8784fd9 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 5 Oct 2025 20:55:43 -0400 Subject: [PATCH 001/187] fix(scrapers): cses interactive problems --- lua/cp/commands/init.lua | 4 +--- lua/cp/setup.lua | 15 +++------------ scrapers/cses.py | 15 ++++++++++----- 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/lua/cp/commands/init.lua b/lua/cp/commands/init.lua index ae07889..9583204 100644 --- a/lua/cp/commands/init.lua +++ b/lua/cp/commands/init.lua @@ -153,9 +153,7 @@ function M.handle_command(opts) cache_commands.handle_cache_command(cmd) elseif cmd.type == 'contest_setup' then local setup = require('cp.setup') - if setup.set_platform(cmd.platform) then - setup.setup_contest(cmd.platform, cmd.contest, nil) - end + setup.setup_contest(cmd.platform, cmd.contest, nil) return end end diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index 3406c27..486aad9 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -7,16 +7,6 @@ local scraper = require('cp.scraper') local state = require('cp.state') local constants = require('cp.constants') -local platforms = constants.PLATFORMS - -function M.set_platform(platform) - if not vim.tbl_contains(platforms, platform) then - logger.log(("Unknown platform '%s'"):format(platform), vim.log.levels.ERROR) - return false - end - state.set_platform(platform) - return true -end ---@class TestCaseLite ---@field input string @@ -35,9 +25,10 @@ end ---@param platform string ---@param contest_id string ----@param problem_id string|nil ----@param language? string|nil +---@param problem_id? string +---@param language? string function M.setup_contest(platform, contest_id, problem_id, language) + state.set_platform(platform) state.set_contest_id(contest_id) cache.load() diff --git a/scrapers/cses.py b/scrapers/cses.py index 0ef9778..ea8f57a 100644 --- a/scrapers/cses.py +++ b/scrapers/cses.py @@ -132,12 +132,17 @@ def parse_category_problems(category_id: str, html: str) -> list[ProblemSummary] return [] -def parse_limits(html: str) -> tuple[int, int]: +def _extract_problem_info(html: str) -> tuple[int, int, bool]: tm = TIME_RE.search(html) mm = MEM_RE.search(html) t = int(round(float(tm.group(1)) * 1000)) if tm else 0 m = int(mm.group(1)) if mm else 0 - return t, m + md = MD_BLOCK_RE.search(html) + interactive = False + if md: + body = md.group(1) + interactive = "This is an interactive problem." in body + return t, m, interactive def parse_title(html: str) -> str: @@ -220,10 +225,10 @@ class CSESScraper(BaseScraper): try: html = await fetch_text(client, task_path(pid)) tests = parse_tests(html) - timeout_ms, memory_mb = parse_limits(html) + timeout_ms, memory_mb, interactive = _extract_problem_info(html) except Exception: tests = [] - timeout_ms, memory_mb = 0, 0 + timeout_ms, memory_mb, interactive = 0, 0, False return { "problem_id": pid, "tests": [ @@ -231,7 +236,7 @@ class CSESScraper(BaseScraper): ], "timeout_ms": timeout_ms, "memory_mb": memory_mb, - "interactive": False, + "interactive": interactive, } tasks = [run_one(p.id) for p in problems] From a7eb731730d564481007bdb265feab1e1ae5f8c4 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 5 Oct 2025 21:06:57 -0400 Subject: [PATCH 002/187] fea(ci): improve prettier config --- .github/workflows/quality.yml | 8 +++---- .prettierrc | 17 ++++++++++++++ tests/conftest.py | 43 +++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 .prettierrc create mode 100644 tests/conftest.py diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 8b6432f..7261d29 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -90,7 +90,7 @@ jobs: - name: Install ruff run: uv tool install ruff - name: Check Python formatting with ruff - run: ruff format --check scrapers/ tests/scrapers/ + run: ruff format --check . python-lint: name: Python Lint Check @@ -104,7 +104,7 @@ jobs: - name: Install ruff run: uv tool install ruff - name: Lint Python files with ruff - run: ruff check scripts/ scrapers/ tests/scrapers/ + run: ruff check . python-typecheck: name: Python Type Check @@ -118,7 +118,7 @@ jobs: - name: Install dependencies with mypy run: uv sync --dev - name: Type check Python files with mypy - run: uv run mypy scripts/ scrapers/ tests/scrapers/ + run: uv run mypy . markdown-format: name: Markdown Format Check @@ -138,4 +138,4 @@ jobs: - name: Install prettier run: pnpm add -g prettier@3.1.0 - name: Check markdown formatting with prettier - run: prettier --check "*.md" "docs/**/*.md" || true + run: prettier --check . diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..ed9f7c5 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,17 @@ +{ + "proseWrap": "always", + "printWidth": 80, + "tabWidth": 2, + "useTabs": false, + "trailingComma": "none", + "semi": false, + "singleQuote": true, + "overrides": [ + { + "files": ["*.md", "docs/**/*.md"], + "options": { + "parser": "markdown" + } + } + ] +} diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..2cba275 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,43 @@ +import sys +from pathlib import Path + +import pytest + +ROOT = Path(__file__).resolve().parent.parent +FIXTURES = Path(__file__).resolve().parent / "fixtures" + + +@pytest.fixture +def fixture_text(): + """Load HTML fixture by filename.""" + + def _load(name: str) -> str: + p = FIXTURES / name + return p.read_text(encoding="utf-8") + + return _load + + +@pytest.fixture +def run_scraper(monkeypatch): + def _run(name: str, mode: str, *args, replace_fetch=None) -> dict: + scraper_path = ROOT / "scrapers" / f"{name}.py" + ns = {} + code = scraper_path.read_text(encoding="utf-8") + if replace_fetch: + code = code.replace("def _fetch", "def _fixture_fetch") + code += f"\n_fetch = _fixture_fetch\nfetch_text = _fixture_fetch\n" + ns.update(replace_fetch) + exec(compile(code, str(scraper_path), "exec"), ns) + main_async = ns.get("main_async") + if not main_async: + raise RuntimeError(f"Could not load main_async from {name}.py") + import asyncio + + async def wrapper(): + sys.argv = [str(scraper_path), mode, *args] + return await main_async() + + return asyncio.run(wrapper()) + + return _run From c509102b3784824f6673912cbbac62329b7c0a45 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 5 Oct 2025 21:58:43 -0400 Subject: [PATCH 003/187] feat(tests): basic tests --- .github/workflows/test.yml | 4 +- .pre-commit-config.yaml | 7 +- pyproject.toml | 1 + scrapers/atcoder.py | 19 +- scrapers/base.py | 19 +- scrapers/codeforces.py | 21 +- scrapers/cses.py | 15 +- scrapers/models.py | 56 +- tests/conftest.py | 170 +- tests/fixtures/atcoder_abc100_tasks.html | 519 ++ tests/fixtures/atcoder_contests.html | 1902 +++++ tests/fixtures/atcoder_task_abc100_a.html | 885 +++ tests/fixtures/atcoder_task_abc100_b.html | 887 +++ tests/fixtures/codeforces_1550_A.html | 8210 +++++++++++++++++++++ tests/fixtures/codeforces_1550_B.html | 4724 ++++++++++++ tests/fixtures/codeforces_contests.html | 10 + tests/fixtures/cses_contests.html | 43 + tests/fixtures/cses_task_1068.html | 156 + tests/fixtures/cses_task_1621.html | 150 + tests/scrapers/test_filler.py | 2 - tests/test_scrapers.py | 69 + uv.lock | 103 + 22 files changed, 17879 insertions(+), 93 deletions(-) create mode 100644 tests/fixtures/atcoder_abc100_tasks.html create mode 100644 tests/fixtures/atcoder_contests.html create mode 100644 tests/fixtures/atcoder_task_abc100_a.html create mode 100644 tests/fixtures/atcoder_task_abc100_b.html create mode 100644 tests/fixtures/codeforces_1550_A.html create mode 100644 tests/fixtures/codeforces_1550_B.html create mode 100644 tests/fixtures/codeforces_contests.html create mode 100644 tests/fixtures/cses_contests.html create mode 100644 tests/fixtures/cses_task_1068.html create mode 100644 tests/fixtures/cses_task_1621.html delete mode 100644 tests/scrapers/test_filler.py create mode 100644 tests/test_scrapers.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ddabc71..731ad4f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,7 +31,7 @@ jobs: python: - 'scripts/**' - 'scrapers/**' - - 'tests/scrapers/**' + - 'tests/**' - 'pyproject.toml' - 'uv.lock' @@ -64,4 +64,4 @@ jobs: - name: Fetch camoufox data run: uv run camoufox fetch - name: Run Python tests - run: uv run pytest tests/scrapers/ -v + run: uv run pytest tests/ -v diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 51a81f3..60acfc6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,6 @@ repos: - id: stylua-github name: stylua (Lua formatter) args: ["."] - files: ^(lua/|spec/|plugin/|after/|ftdetect/|.*\.lua$) additional_dependencies: [] - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.6.9 @@ -16,16 +15,14 @@ repos: files: ^(scrapers/|tests/scrapers/|.*\.py$) - id: ruff name: ruff (lint) - args: ["--fix", "--select=I"] - files: ^(scrapers/|tests/scrapers/|.*\.py$) + args: ["--fix", "--select=I", "."] - repo: local hooks: - id: mypy name: mypy (type check) entry: uv run mypy language: system - args: ["scrapers/", "tests/scrapers/"] - files: ^(scrapers/|tests/scrapers/|.*\.py$) + args: ["."] pass_filenames: false - repo: https://github.com/pre-commit/mirrors-prettier rev: v3.1.0 diff --git a/pyproject.toml b/pyproject.toml index 8ecd950..b114d87 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,6 +10,7 @@ dependencies = [ "curl-cffi>=0.13.0", "httpx>=0.28.1", "ndjson>=0.3.1", + "pydantic>=2.11.10", "requests>=2.32.5", "scrapling[fetchers]>=0.3.5", ] diff --git a/scrapers/atcoder.py b/scrapers/atcoder.py index c5d116f..7571a26 100644 --- a/scrapers/atcoder.py +++ b/scrapers/atcoder.py @@ -5,7 +5,6 @@ import json import re import sys import time -from dataclasses import asdict from typing import Any import backoff @@ -231,16 +230,12 @@ def _scrape_problem_page_sync(contest_id: str, slug: str) -> dict[str, Any]: def _to_problem_summaries(rows: list[dict[str, str]]) -> list[ProblemSummary]: out: list[ProblemSummary] = [] - seen: set[str] = set() for r in rows: letter = (r.get("letter") or "").strip().upper() title = r.get("title") or "" if not letter: continue pid = letter.lower() - if pid in seen: - continue - seen.add(pid) out.append(ProblemSummary(id=pid, name=title)) return out @@ -341,7 +336,7 @@ async def main_async() -> int: success=False, error="Usage: atcoder.py metadata OR atcoder.py tests OR atcoder.py contests", ) - print(json.dumps(asdict(result))) + print(result.model_dump_json()) return 1 mode: str = sys.argv[1] @@ -352,11 +347,11 @@ async def main_async() -> int: result = MetadataResult( success=False, error="Usage: atcoder.py metadata " ) - print(json.dumps(asdict(result))) + print(result.model_dump_json()) return 1 contest_id = sys.argv[2] result = await scraper.scrape_contest_metadata(contest_id) - print(json.dumps(asdict(result))) + print(result.model_dump_json()) return 0 if result.success else 1 if mode == "tests": @@ -370,7 +365,7 @@ async def main_async() -> int: timeout_ms=0, memory_mb=0, ) - print(json.dumps(asdict(tests_result))) + print(tests_result.model_dump_json()) return 1 contest_id = sys.argv[2] await scraper.stream_tests_for_category_async(contest_id) @@ -381,17 +376,17 @@ async def main_async() -> int: contest_result = ContestListResult( success=False, error="Usage: atcoder.py contests" ) - print(json.dumps(asdict(contest_result))) + print(contest_result.model_dump_json()) return 1 contest_result = await scraper.scrape_contest_list() - print(json.dumps(asdict(contest_result))) + print(contest_result.model_dump_json()) return 0 if contest_result.success else 1 result = MetadataResult( success=False, error="Unknown mode. Use 'metadata ', 'tests ', or 'contests'", ) - print(json.dumps(asdict(result))) + print(result.model_dump_json()) return 1 diff --git a/scrapers/base.py b/scrapers/base.py index 7cd3714..dbf76e6 100644 --- a/scrapers/base.py +++ b/scrapers/base.py @@ -1,20 +1,9 @@ -from __future__ import annotations - from abc import ABC, abstractmethod -from dataclasses import dataclass from typing import Any, Awaitable, Callable, ParamSpec, cast -from .models import ContestListResult, MetadataResult, TestsResult - P = ParamSpec("P") - -@dataclass -class ScraperConfig: - timeout_seconds: int = 30 - max_retries: int = 3 - backoff_base: float = 2.0 - rate_limit_delay: float = 1.0 +from .models import ContestListResult, MetadataResult, TestsResult class BaseScraper(ABC): @@ -38,6 +27,7 @@ class BaseScraper(ABC): success=False, error=f"{self.platform_name}: {error_msg}", contest_id=contest_id, + problems=[], ) def _create_tests_error( @@ -51,11 +41,14 @@ class BaseScraper(ABC): tests=[], timeout_ms=0, memory_mb=0, + interactive=False, ) def _create_contests_error(self, error_msg: str) -> ContestListResult: return ContestListResult( - success=False, error=f"{self.platform_name}: {error_msg}" + success=False, + error=f"{self.platform_name}: {error_msg}", + contests=[], ) async def _safe_execute( diff --git a/scrapers/codeforces.py b/scrapers/codeforces.py index 5d5421d..b0eecc3 100644 --- a/scrapers/codeforces.py +++ b/scrapers/codeforces.py @@ -5,7 +5,6 @@ import json import logging import re import sys -from dataclasses import asdict from typing import Any import requests @@ -63,8 +62,6 @@ def _extract_limits(block: Tag) -> tuple[int, float]: def _group_lines_by_id(pre: Tag) -> dict[int, list[str]]: groups: dict[int, list[str]] = {} - if not isinstance(pre, Tag): - return groups for div in pre.find_all("div", class_="test-example-line"): cls = " ".join(div.get("class", [])) m = re.search(r"\btest-example-line-(\d+)\b", cls) @@ -182,12 +179,8 @@ def _scrape_contest_problems_sync(contest_id: str) -> list[ProblemSummary]: html = _fetch_problems_html(contest_id) blocks = _parse_all_blocks(html) problems: list[ProblemSummary] = [] - seen: set[str] = set() for b in blocks: pid = b["letter"].upper() - if pid in seen: - continue - seen.add(pid) problems.append(ProblemSummary(id=pid.lower(), name=b["name"])) return problems @@ -267,7 +260,7 @@ async def main_async() -> int: success=False, error="Usage: codeforces.py metadata OR codeforces.py tests OR codeforces.py contests", ) - print(json.dumps(asdict(result))) + print(result.model_dump_json()) return 1 mode: str = sys.argv[1] @@ -278,11 +271,11 @@ async def main_async() -> int: result = MetadataResult( success=False, error="Usage: codeforces.py metadata " ) - print(json.dumps(asdict(result))) + print(result.model_dump_json()) return 1 contest_id = sys.argv[2] result = await scraper.scrape_contest_metadata(contest_id) - print(json.dumps(asdict(result))) + print(result.model_dump_json()) return 0 if result.success else 1 if mode == "tests": @@ -296,7 +289,7 @@ async def main_async() -> int: timeout_ms=0, memory_mb=0, ) - print(json.dumps(asdict(tests_result))) + print(tests_result.model_dump_json()) return 1 contest_id = sys.argv[2] await scraper.stream_tests_for_category_async(contest_id) @@ -307,17 +300,17 @@ async def main_async() -> int: contest_result = ContestListResult( success=False, error="Usage: codeforces.py contests" ) - print(json.dumps(asdict(contest_result))) + print(contest_result.model_dump_json()) return 1 contest_result = await scraper.scrape_contest_list() - print(json.dumps(asdict(contest_result))) + print(contest_result.model_dump_json()) return 0 if contest_result.success else 1 result = MetadataResult( success=False, error="Unknown mode. Use 'metadata ', 'tests ', or 'contests'", ) - print(json.dumps(asdict(result))) + print(result.model_dump_json()) return 1 diff --git a/scrapers/cses.py b/scrapers/cses.py index ea8f57a..5302caa 100644 --- a/scrapers/cses.py +++ b/scrapers/cses.py @@ -4,7 +4,6 @@ import asyncio import json import re import sys -from dataclasses import asdict from typing import Any import httpx @@ -251,7 +250,7 @@ async def main_async() -> int: success=False, error="Usage: cses.py metadata OR cses.py tests OR cses.py contests", ) - print(json.dumps(asdict(result))) + print(result.model_dump_json()) return 1 mode: str = sys.argv[1] @@ -262,11 +261,11 @@ async def main_async() -> int: result = MetadataResult( success=False, error="Usage: cses.py metadata " ) - print(json.dumps(asdict(result))) + print(result.model_dump_json()) return 1 category_id = sys.argv[2] result = await scraper.scrape_contest_metadata(category_id) - print(json.dumps(asdict(result))) + print(result.model_dump_json()) return 0 if result.success else 1 if mode == "tests": @@ -280,7 +279,7 @@ async def main_async() -> int: timeout_ms=0, memory_mb=0, ) - print(json.dumps(asdict(tests_result))) + print(tests_result.model_dump_json()) return 1 category = sys.argv[2] await scraper.stream_tests_for_category_async(category) @@ -291,17 +290,17 @@ async def main_async() -> int: contest_result = ContestListResult( success=False, error="Usage: cses.py contests" ) - print(json.dumps(asdict(contest_result))) + print(contest_result.model_dump_json()) return 1 contest_result = await scraper.scrape_contest_list() - print(json.dumps(asdict(contest_result))) + print(contest_result.model_dump_json()) return 0 if contest_result.success else 1 result = MetadataResult( success=False, error=f"Unknown mode: {mode}. Use 'metadata ', 'tests ', or 'contests'", ) - print(json.dumps(asdict(result))) + print(result.model_dump_json()) return 1 diff --git a/scrapers/models.py b/scrapers/models.py index 9a0f3a5..69ba52b 100644 --- a/scrapers/models.py +++ b/scrapers/models.py @@ -1,47 +1,71 @@ -from dataclasses import dataclass, field +from pydantic import BaseModel, Field -@dataclass -class TestCase: +class TestCase(BaseModel): input: str expected: str + class Config: + extra = "forbid" -@dataclass -class ProblemSummary: + +class ProblemSummary(BaseModel): id: str name: str + class Config: + extra = "forbid" -@dataclass -class ContestSummary: + +class ContestSummary(BaseModel): id: str name: str - display_name: str + display_name: str | None = None + + class Config: + extra = "forbid" -@dataclass -class ScrapingResult: +class ScrapingResult(BaseModel): success: bool error: str + class Config: + extra = "forbid" + -@dataclass class MetadataResult(ScrapingResult): contest_id: str = "" - problems: list[ProblemSummary] = field(default_factory=list) + problems: list[ProblemSummary] = Field(default_factory=list) + + class Config: + extra = "forbid" -@dataclass class ContestListResult(ScrapingResult): - contests: list[ContestSummary] = field(default_factory=list) + contests: list[ContestSummary] = Field(default_factory=list) + + class Config: + extra = "forbid" -@dataclass class TestsResult(ScrapingResult): problem_id: str url: str - tests: list[TestCase] + tests: list[TestCase] = Field(default_factory=list) timeout_ms: int memory_mb: float interactive: bool = False + + class Config: + extra = "forbid" + + +class ScraperConfig(BaseModel): + timeout_seconds: int = 30 + max_retries: int = 3 + backoff_base: float = 2.0 + rate_limit_delay: float = 1.0 + + class Config: + extra = "forbid" diff --git a/tests/conftest.py b/tests/conftest.py index 2cba275..1053031 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,43 +1,171 @@ +import io +import json import sys from pathlib import Path +from typing import Callable import pytest ROOT = Path(__file__).resolve().parent.parent -FIXTURES = Path(__file__).resolve().parent / "fixtures" +FIX = Path(__file__).resolve().parent / "fixtures" @pytest.fixture def fixture_text(): - """Load HTML fixture by filename.""" - def _load(name: str) -> str: - p = FIXTURES / name + p = FIX / name return p.read_text(encoding="utf-8") return _load +def _compile_and_exec_module( + module_path: Path, offline_fetch_impls: dict[str, Callable] +): + src = module_path.read_text(encoding="utf-8") + + replacements: list[tuple[str, str]] = [ + ("def _fetch(", "def _orig_fetch("), + ("def fetch_text(", "def _orig_fetch_text("), + ("async def _get_async(", "async def _orig_get_async("), + ] + for old, new in replacements: + src = src.replace(old, new) + + stub_lines = [] + if " _orig_fetch(" in src or "def _orig_fetch(" in src: + stub_lines.append("_fetch = __offline_fetch_sync") + if " _orig_fetch_text(" in src or "def _orig_fetch_text(" in src: + stub_lines.append("fetch_text = __offline_fetch_text") + if " _orig_get_async(" in src or "async def _orig_get_async(" in src: + stub_lines.append("_get_async = __offline_fetch_async") + src += "\n" + "\n".join(stub_lines) + "\n" + + ns = {} + ns.update(offline_fetch_impls) + exec(compile(src, str(module_path), "exec"), ns) + return ns + + +def _capture_stdout(coro): + import asyncio + + buf = io.StringIO() + old = sys.stdout + sys.stdout = buf + try: + rc = asyncio.run(coro) + out = buf.getvalue() + finally: + sys.stdout = old + return rc, out + + @pytest.fixture -def run_scraper(monkeypatch): - def _run(name: str, mode: str, *args, replace_fetch=None) -> dict: - scraper_path = ROOT / "scrapers" / f"{name}.py" - ns = {} - code = scraper_path.read_text(encoding="utf-8") - if replace_fetch: - code = code.replace("def _fetch", "def _fixture_fetch") - code += f"\n_fetch = _fixture_fetch\nfetch_text = _fixture_fetch\n" - ns.update(replace_fetch) - exec(compile(code, str(scraper_path), "exec"), ns) +def run_scraper_offline(fixture_text): + def _router_cses(*, path: str | None = None, url: str | None = None) -> str: + if path == "/problemset/list": + return fixture_text("cses_contests.html") + if path and path.startswith("/problemset/task/"): + pid = path.rsplit("/", 1)[-1] + return fixture_text(f"cses_task_{pid}.html") + raise AssertionError(f"No fixture for CSES path={path!r}") + + def _router_atcoder(*, path: str | None = None, url: str | None = None) -> str: + if not url: + raise AssertionError("AtCoder expects url routing") + if "/contests/archive" in url: + return fixture_text("atcoder_contests.html") + if url.endswith("/tasks"): + return fixture_text("atcoder_abc100_tasks.html") + if "/tasks/" in url: + slug = url.rsplit("/", 1)[-1] + return fixture_text(f"atcoder_task_{slug}.html") + raise AssertionError(f"No fixture for AtCoder url={url!r}") + + def _router_codeforces(*, path: str | None = None, url: str | None = None) -> str: + if not url: + raise AssertionError("Codeforces expects url routing") + if "/contests" in url and "/problem/" not in url: + return fixture_text("codeforces_contests.html") + if "/problem/" in url: + parts = url.rstrip("/").split("/") + contest_id, index = parts[-3], parts[-1] + return fixture_text(f"codeforces_{contest_id}_{index}.html") + if "/problemset/problem/" in url: + parts = url.rstrip("/").split("/") + contest_id, index = parts[-2], parts[-1] + return fixture_text(f"codeforces_{contest_id}_{index}.html") + raise AssertionError(f"No fixture for Codeforces url={url!r}") + + def _make_offline_fetches(scraper_name: str): + if scraper_name == "cses": + + def __offline_fetch_text(client, path: str) -> str: + return _router_cses(path=path) + + return { + "__offline_fetch_text": __offline_fetch_text, + "__offline_fetch_sync": lambda url: (_ for _ in ()).throw( + AssertionError("CSES doesn't use _fetch") + ), + "__offline_fetch_async": lambda client, url: (_ for _ in ()).throw( + AssertionError("CSES doesn't use _get_async") + ), + } + if scraper_name == "atcoder": + + async def __offline_fetch_async(client, url: str) -> str: + return _router_atcoder(url=url) + + def __offline_fetch_sync(url: str) -> str: + return _router_atcoder(url=url) + + return { + "__offline_fetch_text": lambda client, path: (_ for _ in ()).throw( + AssertionError("AtCoder doesn't use fetch_text") + ), + "__offline_fetch_sync": __offline_fetch_sync, + "__offline_fetch_async": __offline_fetch_async, + } + if scraper_name == "codeforces": + + def __offline_fetch_sync(url: str) -> str: + return _router_codeforces(url=url) + + return { + "__offline_fetch_text": lambda client, path: (_ for _ in ()).throw( + AssertionError("Codeforces doesn't use fetch_text") + ), + "__offline_fetch_sync": __offline_fetch_sync, + "__offline_fetch_async": lambda client, url: (_ for _ in ()).throw( + AssertionError("Codeforces doesn't use _get_async") + ), + } + raise AssertionError(f"Unknown scraper: {scraper_name}") + + def _run(scraper_name: str, mode: str, *args: str): + mod_path = ROOT / "scrapers" / f"{scraper_name}.py" + ns = _compile_and_exec_module(mod_path, _make_offline_fetches(scraper_name)) main_async = ns.get("main_async") - if not main_async: - raise RuntimeError(f"Could not load main_async from {name}.py") - import asyncio + assert callable(main_async), f"main_async not found in {scraper_name}" - async def wrapper(): - sys.argv = [str(scraper_path), mode, *args] - return await main_async() + argv = [str(mod_path), mode, *args] + old_argv = sys.argv + sys.argv = argv + try: + rc, out = _capture_stdout(main_async()) + finally: + sys.argv = old_argv - return asyncio.run(wrapper()) + json_lines = [] + for line in (l for l in out.splitlines() if l.strip()): + try: + json_lines.append(json.loads(line)) + except json.JSONDecodeError as e: + raise AssertionError( + f"Invalid JSON from {scraper_name} {mode}: {line}" + ) from e + return rc, json_lines return _run diff --git a/tests/fixtures/atcoder_abc100_tasks.html b/tests/fixtures/atcoder_abc100_tasks.html new file mode 100644 index 0000000..d19d7b9 --- /dev/null +++ b/tests/fixtures/atcoder_abc100_tasks.html @@ -0,0 +1,519 @@ + + + + Tasks - AtCoder Beginner Contest 100 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
+
+ + Contest Duration: + + - + + (local time) (100 minutes) + + Back to Home +
+ +
+
+

Tasks

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Task NameTime Limit + Memory Limit +
+ A + + Happy Birthday! + 2 sec976 MiB
+ B + + Ringo's Favorite Numbers + 2 sec976 MiB
+ C + + *3 or /2 + 2 sec976 MiB
+ D + + Patisserie ABC + 2 sec976 MiB
+
+ +

+ Tasks for printing +

+
+
+ +
+ +
+ + + + + + +
+ + +
+
+
+ +
+ +
+

+ + + diff --git a/tests/fixtures/atcoder_contests.html b/tests/fixtures/atcoder_contests.html new file mode 100644 index 0000000..9107b98 --- /dev/null +++ b/tests/fixtures/atcoder_contests.html @@ -0,0 +1,1902 @@ + + + + Contest Archive - AtCoder + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+

+ Search in Archive + +

+
+ +
+ +
+
+

Contest Archive

+
+ +
+
    +
  • 1
  • + +
  • 2
  • + +
  • 3
  • + +
  • 4
  • + +
  • 8
  • + +
  • 16
  • +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Start Time (local time) + Contest NameDurationRated Range
+ + + + + + AtCoder Regular Contest 207 (Div.1) + 02:301600 - 2999
+ + + + + + AtCoder Beginner Contest 426 + 01:40- 1999
+ + + + + + AtCoder Grand Contest 073 + 03:002000 -
+ + + + + + UNIQUE VISION Programming Contest 2025 Autumn + (AtCoder Beginner Contest 425) + 01:40- 1999
+ + + + + + AtCoder Regular Contest 206 (Div. 2) + 02:001200 - 2399
+ + + + + + AtCoder Beginner Contest 424 + 01:40- 1999
+ + + + + + ALGO ARTIS Programming Contest 2025 Summer(AtCoder + Heuristic Contest 054) + 240:00All
+ + + + + + AtCoder Beginner Contest 423 + 01:40- 1999
+ + + + + + 12th Asprova Programming Contest(AtCoder Heuristic + Contest 053) + 04:00All
+ + + + + + 日本最強プログラマー学生選手権~Advance~ + 01:40- 1999
+ + + + + + AtCoder Beginner Contest 422 + 01:40- 1999
+ + + + + + AtCoder Regular Contest 205 (Div. 2) + 02:001200 - 2399
+ + + + + + AtCoder Beginner Contest 421 + 01:40- 1999
+ + + + + + AtCoder Beginner Contest 420 + 01:40- 1999
+ + + + + + AtCoder Heuristic Contest 052 + 04:00All
+ + + + + + AtCoder Regular Contest 204 (Div. 1) + 02:301600 - 2999
+ + + + + + AtCoder Beginner Contest 419 + 01:40- 1999
+ + + + + + AtCoder Beginner Contest 418 + 01:40- 1999
+ + + + + + AtCoder Regular Contest 203 (Div. 2) + 02:001200 - 2399
+ + + + + + AtCoder Beginner Contest 417 + 01:40- 1999
+ + + + + + THIRD Programming Contest 2025 Summer(AtCoder + Heuristic Contest 051) + 240:00All
+ + + + + + AtCoder Beginner Contest 416 + 01:40- 1999
+ + + + + + AtCoder Regular Contest 202 (Div. 1) + 02:301600 - 2999
+ + + + + + Japan Registry Services (JPRS) Programming Contest + 2025#2 (AtCoder Beginner Contest 415) + 01:40- 1999
+ + + + + + World Tour Finals 2025 Algorithm(Open Contest) + 05:00-
+ + + + + + World Tour Finals 2025 Algorithm + 05:00-
+ + + + + + World Tour Finals 2025 Heuristic + 10:00-
+ + + + + + + Mirrativ Programming Contest 2025 (AtCoder Beginner + Contest 414) + 01:40- 1999
+ + + + + + AtCoder Heuristic Contest 050 + 04:00All
+ + + + + + Denso Create Programming Contest 2025(AtCoder + Beginner Contest 413) + 01:40- 1999
+ + + + + + AtCoder Beginner Contest 412 + 01:40- 1999
+ + + + + + AtCoder Regular Contest 201 + 02:001200 - 2799
+ + + + + + UNIQUE VISION Programming Contest 2025 Summer + (AtCoder Beginner Contest 411) + 01:40- 1999
+ + + + + + Toyota Programming Contest 2025#3(AtCoder Heuristic + Contest 049) + 04:00All
+ + + + + + AtCoder Regular Contest 200 (Div. 2) + 02:001200 - 2399
+ + + + + + AtCoder Beginner Contest 410 + 01:40- 1999
+ + + + + + AtCoder Beginner Contest 409 + 01:40- 1999
+ + + + + + AtCoder Regular Contest 199 (Div. 1) + 02:301600 - 2999
+ + + + + + AtCoder Beginner Contest 408 + 01:40- 1999
+ + + + + + MC Digital Programming Contest 2025 (AtCoder + Heuristic Contest 048) + 240:00All
+ + + + + + AtCoder Regular Contest 198 (Div. 2) + 02:001200 - 2399
+ + + + + + AtCoder Beginner Contest 407 + 01:40- 1999
+ + + + + + Toyota Programming Contest 2025#2(AtCoder Heuristic + Contest 047) + 04:00All
+ + + + + + Panasonic Programming Contest 2025(AtCoder Beginner + Contest 406) + 01:40- 1999
+ + + + + + AtCoder Beginner Contest 405 + 01:40- 1999
+ + + + + + AtCoder Regular Contest 197 (Div. 2) + 02:001200 - 2399
+ + + + + + AtCoder Beginner Contest 404 + 01:40- 1999
+ + + + + + AtCoder Beginner Contest 403 + 01:40- 1999
+ + + + + + BrainPad Programming Contest 2025 (AtCoder Heuristic + Contest 046) + 04:00All
+ + + + + + AtCoder Grand Contest 072 + 03:002000 -
+
+
+
+
    +
  • 1
  • + +
  • 2
  • + +
  • 3
  • + +
  • 4
  • + +
  • 8
  • + +
  • 16
  • +
+
+
+
+ +
+ +
+ + + + + + +
+ + +
+
+
+ +
+ +
+

+ + + diff --git a/tests/fixtures/atcoder_task_abc100_a.html b/tests/fixtures/atcoder_task_abc100_a.html new file mode 100644 index 0000000..c96cd9a --- /dev/null +++ b/tests/fixtures/atcoder_task_abc100_a.html @@ -0,0 +1,885 @@ + + + + A - Happy Birthday! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
+
+ + Contest Duration: + + - + + (local time) (100 minutes) + + Back to Home +
+ +
+
+ + A - Happy Birthday! + Editorial + + + / + + +
+

Time Limit: 2 sec / Memory Limit: 976 MiB

+ +
+ + +

配点: 100

+ +
+
+

問題文

+

+ もうすぐ E869120 君と square1001 君の + 16 才の誕生日が来る.
+ そこで, AtCoder 王国の高橋君は, 円形のケーキ + 1 個に放射状に切れ目を入れ + 16 等分したものを, 彼らにプレゼントした. +

+

+ E869120 君はそのうち A 切れ、square1001 君は + B 切れを食べようとした.
+ しかし, ケーキと一緒についていた紙を見ると, + 「同じ人が隣り合う + 2 + 切れのケーキを両方取ってはならない」と書かれていた. +

+

+ さて、彼らは紙に書かれたことを守って、2 + 人とも食べたい数のケーキを取ることができるだろうか? +

+
+
+ +
+
+

制約

+
    +
  • + A, B1 以上 + 16 以下の整数 +
  • +
  • A+B16 以下である.
  • +
+
+
+ +
+ +
+
+
+

入力

+

入力は以下の形式で標準入力から与えられる.

+
A B
+
+
+
+ +
+
+

出力

+

+ 紙に書かれたことを守って, E869120 君と square1001 + 君両方が, 食べたい数のケーキを取ることができるならば + Yay!, そうでなければ + :( と出力しなさい. +

+
+
+
+ +
+ +
+
+

入力例 1

+
+5 4
+
+
+
+ +
+
+

出力例 1

+
+Yay!
+
+ +

+ 下の図のようにケーキを取れば、2 + 人とも目標を達成することができる.
+  +

+
+
+ +
+ +
+
+

入力例 2

+
+8 8
+
+
+
+ +
+
+

出力例 2

+
+Yay!
+
+ +

+ 下の図のようにケーキを取れば、2 + 人とも目標を達成することができる.
+  +

+
+
+ +
+ +
+
+

入力例 3

+
+11 4
+
+
+
+ +
+
+

出力例 3

+
+:(
+
+ +

+ この場合, 残念ながら目標を達成する方法は + 1 つもない. +

+
+
+
+ +

Score: 100 points

+ +
+
+

Problem Statement

+

+ E869120's and square1001's 16-th birthday is + coming soon.
+ Takahashi from AtCoder Kingdom gave them a round cake + cut into 16 equal fan-shaped pieces. +

+

+ E869120 and square1001 were just about to eat + A and B of those pieces, + respectively,
+ when they found a note attached to the cake saying that + "the same person should not take two adjacent pieces of + cake". +

+

+ Can both of them obey the instruction in the note and + take desired numbers of pieces of cake? +

+
+
+ +
+
+

Constraints

+
    +
  • + A and B are integers between + 1 and 16 (inclusive). +
  • +
  • A+B is at most 16.
  • +
+
+
+ +
+ +
+
+
+

Input

+

+ Input is given from Standard Input in the following + format: +

+
A B
+
+
+
+ +
+
+

Output

+

+ If both E869120 and square1001 can obey the + instruction in the note and take desired numbers of + pieces of cake, print Yay!; otherwise, + print :(. +

+
+
+
+ +
+ +
+
+

Sample Input 1

+
+5 4
+
+
+
+ +
+
+

Sample Output 1

+
+Yay!
+
+ +

+ Both of them can take desired number of pieces as + follows: +  +

+
+
+ +
+ +
+
+

Sample Input 2

+
+8 8
+
+
+
+ +
+
+

Sample Output 2

+
+Yay!
+
+ +

+ Both of them can take desired number of pieces as + follows: +  +

+
+
+ +
+ +
+
+

Sample Input 3

+
+11 4
+
+
+
+ +
+
+

Sample Output 3

+
+:(
+
+ +

+ In this case, there is no way for them to take desired + number of pieces, unfortunately. +

+
+
+
+
+
+
+
+ +
+ +
+ + + + + + +
+ + +
+
+
+ +
+ +
+

+ + + diff --git a/tests/fixtures/atcoder_task_abc100_b.html b/tests/fixtures/atcoder_task_abc100_b.html new file mode 100644 index 0000000..c2ab95e --- /dev/null +++ b/tests/fixtures/atcoder_task_abc100_b.html @@ -0,0 +1,887 @@ + + + + B - Ringo's Favorite Numbers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
+
+ + Contest Duration: + + - + + (local time) (100 minutes) + + Back to Home +
+ +
+
+ + B - Ringo's Favorite Numbers + Editorial + + + / + + +
+

Time Limit: 2 sec / Memory Limit: 976 MiB

+ +
+ + +

配点: 200

+ +
+
+

問題文

+

+ 今日は, 記念すべき AtCoder Beginner Contest 100 + が開催される. そのため, 高橋君はりんごさんに, + ある整数をプレゼントしようと思った.
+ 今日のコンテストは「AtCoder Beginner Contest + 100」なので, りんごさんは 100 で + ちょうど + D + 回割りきれる正の整数をプレゼントされると喜ぶ. +

+

+ さて, りんごさんがプレゼントされると喜ぶような整数のうち + N 番目に小さいものを求めなさい. +

+
+
+ +
+
+

制約

+
    +
  • + D0, 1, 2 のいずれかである +
  • +
  • + N1 以上 + 100 以下の整数 +
  • +
+
+
+ +
+ +
+
+
+

入力

+

入力は以下の形式で標準入力から与えられる.

+
D N
+
+
+
+ +
+
+

出力

+

+ 100 でちょうど + D 回割りきれる正の整数の中で + N 番目に小さいものを出力しなさい. +

+
+
+
+ +
+ +
+
+

入力例 1

+
+0 5
+
+
+
+ +
+
+

出力例 1

+
+5
+
+ +

+ 100 でちょうど + 0 回割り切れる(すなわち, + 100 で割り切れない)整数は, 1, + 2, 3, 4, 5, + 6, 7, ... と続く.
+ よって, 5 番目に小さいりんごさんが喜ぶ整数は + 5 である. +

+
+
+ +
+ +
+
+

入力例 2

+
+1 11
+
+
+
+ +
+
+

出力例 2

+
+1100
+
+ +

+ 100 でちょうど + 1 回割り切れる整数は, 100, + 200, 300, 400, + 500, 600, 700, + 800, 900, 1 \ 000, + 1 \ 100, ... と続く.
+ よって, 求めたい整数は 1 \ 100 である. +

+
+
+ +
+ +
+
+

入力例 3

+
+2 85
+
+
+
+ +
+
+

出力例 3

+
+850000
+
+ +

+ 100 でちょうど + 2 回割り切れる整数は, 10 \ 000, + 20 \ 000, 30 \ 000, ... と続く.
+ よって, 求めたい整数は 850 \ 000 である. +

+
+
+
+ +

Score: 200 points

+ +
+
+

Problem Statement

+

+ Today, the memorable AtCoder Beginner Contest 100 takes + place. On this occasion, Takahashi would like to give an + integer to Ringo.
+ As the name of the contest is AtCoder Beginner Contest + 100, Ringo would be happy if he is given a positive + integer that can be divided by 100 + exactly D times. +

+

+ Find the N-th smallest integer that would + make Ringo happy. +

+
+
+ +
+
+

Constraints

+
    +
  • + D is 0, 1 or + 2. +
  • +
  • + N is an integer between 1 and + 100 (inclusive). +
  • +
+
+
+ +
+ +
+
+
+

Input

+

+ Input is given from Standard Input in the following + format: +

+
D N
+
+
+
+ +
+
+

Output

+

+ Print the N-th smallest integer that can be + divided by 100 exactly D times. +

+
+
+
+ +
+ +
+
+

Sample Input 1

+
+0 5
+
+
+
+ +
+
+

Sample Output 1

+
+5
+
+ +

+ The integers that can be divided by + 100 exactly 0 times (that is, not + divisible by 100) are as follows: + 1, 2, 3, 4, + 5, 6, 7, ...
+ Thus, the 5-th smallest integer that would + make Ringo happy is 5. +

+
+
+ +
+ +
+
+

Sample Input 2

+
+1 11
+
+
+
+ +
+
+

Sample Output 2

+
+1100
+
+ +

+ The integers that can be divided by + 100 exactly once are as follows: + 100, 200, 300, + 400, 500, 600, + 700, 800, 900, + 1 \ 000, 1 \ 100, ...
+ Thus, the integer we are seeking is 1 \ 100. +

+
+
+ +
+ +
+
+

Sample Input 3

+
+2 85
+
+
+
+ +
+
+

Sample Output 3

+
+850000
+
+ +

+ The integers that can be divided by + 100 exactly twice are as follows: + 10 \ 000, 20 \ 000, + 30 \ 000, ...
+ Thus, the integer we are seeking is + 850 \ 000. +

+
+
+
+
+
+
+
+ +
+ +
+ + + + + + +
+ + +
+
+
+ +
+ +
+

+ + + diff --git a/tests/fixtures/codeforces_1550_A.html b/tests/fixtures/codeforces_1550_A.html new file mode 100644 index 0000000..18a519c --- /dev/null +++ b/tests/fixtures/codeforces_1550_A.html @@ -0,0 +1,8210 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Problem - A - Codeforces + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ +
+ + + + +
+
+ + + + +
+
+ + + + + + + + +
+
+ +
+ + + + +
+ +
+
+
+ The problem statement has recently been changed. + View the changes. +
+ × +
+
+
+
+
A. Find The Array
+
+
time limit per test
+ 1 second +
+
+
memory limit per test
+ 256 megabytes +
+
+
input
+ standard input +
+
+
output
+ standard output +
+
+
+

+ Let's call an array + aa + + consisting of + nn + + positive (greater than + 00 + + ) integers + beautiful if the + following condition is held for every + ii + + from + 11 + + to + nn + + : either + ai=1ai=1 + + , or at least one of the numbers + ai1ai1 + + and + ai2ai2 + + exists in the array as well. +

+

For example:

+
    +
  • + the array + [5,3,1][5,3,1] + + is beautiful: for + a1a1 + + , the number + a12=3a12=3 + + exists in the array; for + a2a2 + + , the number + a22=1a22=1 + + exists in the array; for + a3a3 + + , the condition + a3=1a3=1 + + holds; +
  • +
  • + the array + [1,2,2,2,2][1,2,2,2,2] + + is beautiful: for + a1a1 + + , the condition + a1=1a1=1 + + holds; for every other number + aiai + + , the number + ai1=1ai1=1 + + exists in the array; +
  • +
  • + the array + [1,4][1,4] + + is not beautiful: for + a2a2 + + , neither + a22=2a22=2 + + nor + a21=3a21=3 + + exists in the array, and + a21a21 + + ; +
  • +
  • + the array + [2][2] + + is not beautiful: for + a1a1 + + , neither + a11=1a11=1 + + nor + a12=0a12=0 + + exists in the array, and + a11a11 + + ; +
  • +
  • + the array + [2,1,3][2,1,3] + + is beautiful: for + a1a1 + + , the number + a11=1a11=1 + + exists in the array; for + a2a2 + + , the condition + a2=1a2=1 + + holds; for + a3a3 + + , the number + a32=1a32=1 + + exists in the array. +
  • +
+

+ You are given a positive integer + ss + + . Find the minimum possible size of a beautiful array with + the sum of elements equal to + ss + + . +

+
+
+
Input
+

+ The first line contains one integer + tt + + (1t50001t5000 + + ) — the number of test cases. +

+

+ Then + tt + + lines follow, the + ii + + -th line contains one integer + ss + + (1s50001s5000 + + ) for the + ii + + -th test case. +

+
+
+
Output
+

+ Print + tt + + integers, the + ii + + -th integer should be the answer for the + ii + + -th testcase: the minimum possible size of a beautiful array + with the sum of elements equal to + ss + + . +

+
+
+
Example
+
+
+
+ Input +
+ Copy +
+
+
+4
+1
+8
+7
+42
+
+
+
+
+ Output +
+ Copy +
+
+
+1
+3
+3
+7
+
+
+
+
+
+
Note
+

Consider the example test:

+
    +
  1. + in the first test case, the array + [1][1] + + meets all conditions; +
  2. +
  3. + in the second test case, the array + [3,4,1][3,4,1] + + meets all conditions; +
  4. +
  5. + in the third test case, the array + [1,2,4][1,2,4] + + meets all conditions; +
  6. +
  7. + in the fourth test case, the array + [1,4,6,8,10,2,11][1,4,6,8,10,2,11] + + meets all conditions. +
  8. +
+
+
+

+
+
+ + + +
+
+
+ + + + + +
+ + + + + + + +
+
+
+ + diff --git a/tests/fixtures/codeforces_1550_B.html b/tests/fixtures/codeforces_1550_B.html new file mode 100644 index 0000000..d3444da --- /dev/null +++ b/tests/fixtures/codeforces_1550_B.html @@ -0,0 +1,4724 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Problem - B - Codeforces + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ +
+ + + + +
+
+ + + + +
+
+ + + + + + + + +
+
+ +
+ + + + +
+ +
+
+
+ The problem statement has recently been changed. + View the changes. +
+ × +
+
+
+
+
B. Maximum Cost Deletion
+
+
time limit per test
+ 2 seconds +
+
+
memory limit per test
+ 256 megabytes +
+
+
input
+ standard input +
+
+
output
+ standard output +
+
+
+

+ You are given a string + ss + + of length + nn + + consisting only of the characters + 0 and + 1. +

+

+ You perform the following operation until the string becomes + empty: choose some + consecutive substring + of equal characters, + erase it from the string and glue the remaining two parts + together (any of them can be empty) in the same order. For + example, if you erase the substring + 111 from the string + 111110, you will get the string + 110. When you delete + a substring of length + ll + + , you get + al+bal+b + + points. +

+

+ Your task is to calculate the maximum number of points that + you can score in total, if you have to make the given string + empty. +

+
+
+
Input
+

+ The first line contains a single integer + tt + + (1t20001t2000 + + ) — the number of testcases. +

+

+ The first line of each testcase contains three integers + nn + + , + aa + + and + bb + + (1n100;100a,b1001n100;100a,b100 + + ) — the length of the string + ss + + and the parameters + aa + + and + bb + + . +

+

+ The second line contains the string + ss + + . The string + ss + + consists only of the characters + 0 and + 1. +

+
+
+
Output
+

+ For each testcase, print a single integer — the maximum + number of points that you can score. +

+
+
+
Example
+
+
+
+ Input +
+ Copy +
+
+
+3
+3 2 0
+000
+5 -2 5
+11001
+6 1 -4
+100111
+
+
+
+
+ Output +
+ Copy +
+
+
+6
+15
+-2
+
+
+
+
+
+
Note
+

+ In the first example, it is enough to delete the entire + string, then we will get + 23+0=623+0=6 + + points. +

+

+ In the second example, if we delete characters one by one, + then for each deleted character we will get + (2)1+5=3(2)1+5=3 + + points, i. e. + 1515 + + points in total. +

+

+ In the third example, we can delete the substring + 00 from the string + 100111, we get + 12+(4)=212+(4)=2 + + points, and the string will be equal to + 1111, removing it + entirely we get + 14+(4)=014+(4)=0 + + points. In total, we got + 22 + + points for + 22 + + operations. +

+
+
+

+
+
+ + + +
+
+
+ + + + + +
+ + + + + + + +
+
+
+ + diff --git a/tests/fixtures/codeforces_contests.html b/tests/fixtures/codeforces_contests.html new file mode 100644 index 0000000..5e5b367 --- /dev/null +++ b/tests/fixtures/codeforces_contests.html @@ -0,0 +1,10 @@ + + + + + +
+{"status":"OK","result":[{"id":2156,"name":"Codeforces Round (Div. 2)","type":"CF","phase":"BEFORE","frozen":false,"durationSeconds":7200,"startTimeSeconds":1761489300,"relativeTimeSeconds":-1774097},{"id":2154,"name":"Codeforces Round (Div. 2)","type":"CF","phase":"BEFORE","frozen":false,"durationSeconds":7200,"startTimeSeconds":1760884500,"relativeTimeSeconds":-1169297},{"id":2159,"name":"Codeforces Round (Div. 1)","type":"CF","phase":"BEFORE","frozen":false,"durationSeconds":9000,"startTimeSeconds":1760279700,"relativeTimeSeconds":-564497},{"id":2160,"name":"Codeforces Round (Div. 2)","type":"CF","phase":"BEFORE","frozen":false,"durationSeconds":9000,"startTimeSeconds":1760279700,"relativeTimeSeconds":-564497},{"id":2153,"name":"Codeforces Round 1057 (Div. 2)","type":"CF","phase":"BEFORE","frozen":false,"durationSeconds":7200,"startTimeSeconds":1760106900,"relativeTimeSeconds":-391697},{"id":2145,"name":"Educational Codeforces Round 183 (Rated for Div. 2)","type":"ICPC","phase":"BEFORE","frozen":false,"durationSeconds":7200,"startTimeSeconds":1759761300,"relativeTimeSeconds":-46099},{"id":2155,"name":"Codeforces Round 1056 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1759682100,"relativeTimeSeconds":33103},{"id":2152,"name":"Squarepoint Challenge (Codeforces Round 1055, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1759502100,"relativeTimeSeconds":213103},{"id":2149,"name":"Codeforces Round 1054 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1758810900,"relativeTimeSeconds":904303},{"id":2150,"name":"Codeforces Round 1053 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":11700,"startTimeSeconds":1758713700,"relativeTimeSeconds":1001503},{"id":2151,"name":"Codeforces Round 1053 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":11700,"startTimeSeconds":1758713700,"relativeTimeSeconds":1001503},{"id":2146,"name":"Codeforces Round 1052 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1758465300,"relativeTimeSeconds":1249903},{"id":2147,"name":"Codeforces Global Round 29 (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1758378900,"relativeTimeSeconds":1336303},{"id":2143,"name":"Codeforces Round 1051 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1758119700,"relativeTimeSeconds":1595503},{"id":2144,"name":"Educational Codeforces Round 182 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1757946900,"relativeTimeSeconds":1768303},{"id":2148,"name":"Codeforces Round 1050 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1757774100,"relativeTimeSeconds":1941103},{"id":2141,"name":"Kotlin Heroes: Episode 13","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1757687700,"relativeTimeSeconds":2027503},{"id":2140,"name":"Codeforces Round 1049 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1757428500,"relativeTimeSeconds":2286703},{"id":2138,"name":"Codeforces Round 1048 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1757342100,"relativeTimeSeconds":2373103},{"id":2139,"name":"Codeforces Round 1048 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1757342100,"relativeTimeSeconds":2373103},{"id":2137,"name":"Codeforces Round 1047 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1757255700,"relativeTimeSeconds":2459503},{"id":2142,"name":"Kotlin Heroes: Practice 13","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":864000,"startTimeSeconds":1756823400,"relativeTimeSeconds":2891803},{"id":2135,"name":"Codeforces Round 1046 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1756391700,"relativeTimeSeconds":3323503},{"id":2136,"name":"Codeforces Round 1046 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1756391700,"relativeTimeSeconds":3323503},{"id":2134,"name":"Codeforces Round 1045 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1756218900,"relativeTimeSeconds":3496303},{"id":2133,"name":"Codeforces Round 1044 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1756046100,"relativeTimeSeconds":3669103},{"id":2132,"name":"Codeforces Round 1043 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1755786900,"relativeTimeSeconds":3928303},{"id":2131,"name":"Codeforces Round 1042 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1754836500,"relativeTimeSeconds":4878703},{"id":2127,"name":"Atto Round 1 (Codeforces Round 1041, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1754577300,"relativeTimeSeconds":5137903},{"id":2129,"name":"Codeforces Round 1040 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1753972500,"relativeTimeSeconds":5742703},{"id":2130,"name":"Codeforces Round 1040 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1753972500,"relativeTimeSeconds":5742703},{"id":2128,"name":"Codeforces Round 1039 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1753626900,"relativeTimeSeconds":6088303},{"id":2125,"name":"Educational Codeforces Round 181 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1753194900,"relativeTimeSeconds":6520303},{"id":2122,"name":"Order Capital Round 1 (Codeforces Round 1038, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1752935700,"relativeTimeSeconds":6779503},{"id":2126,"name":"Codeforces Round 1037 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1752762900,"relativeTimeSeconds":6952303},{"id":2124,"name":"EPIC Institute of Technology Round Summer 2025 (Codeforces Round 1036, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1751812500,"relativeTimeSeconds":7902703},{"id":2119,"name":"Codeforces Round 1035 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1751726100,"relativeTimeSeconds":7989103},{"id":2123,"name":"Codeforces Round 1034 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1751380500,"relativeTimeSeconds":8334701},{"id":2112,"name":"Educational Codeforces Round 180 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1750689300,"relativeTimeSeconds":9025903},{"id":2120,"name":"Codeforces Round 1033 (Div. 2) and CodeNite 2025","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1750516500,"relativeTimeSeconds":9198703},{"id":2121,"name":"Codeforces Round 1032 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1750170900,"relativeTimeSeconds":9544303},{"id":2113,"name":"Codeforces Round 1031 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1749978300,"relativeTimeSeconds":9736901},{"id":2118,"name":"Codeforces Round 1030 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1749738900,"relativeTimeSeconds":9976303},{"id":2117,"name":"Codeforces Round 1029 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1749393300,"relativeTimeSeconds":10321903},{"id":2111,"name":"Educational Codeforces Round 179 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1748961300,"relativeTimeSeconds":10753903},{"id":2115,"name":"Codeforces Round 1028 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1748702100,"relativeTimeSeconds":11013103},{"id":2116,"name":"Codeforces Round 1028 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1748702100,"relativeTimeSeconds":11013103},{"id":2114,"name":"Codeforces Round 1027 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1748270100,"relativeTimeSeconds":11445103},{"id":2110,"name":"Codeforces Round 1026 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1748097300,"relativeTimeSeconds":11617903},{"id":2109,"name":"Codeforces Round 1025 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1747492500,"relativeTimeSeconds":12222703},{"id":2101,"name":"Codeforces Round 1024 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1746974100,"relativeTimeSeconds":12741103},{"id":2102,"name":"Codeforces Round 1024 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1746974100,"relativeTimeSeconds":12741103},{"id":2107,"name":"Codeforces Round 1023 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1746455700,"relativeTimeSeconds":13259503},{"id":2108,"name":"Codeforces Round 1022 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1746110100,"relativeTimeSeconds":13605103},{"id":2104,"name":"Educational Codeforces Round 178 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1745850900,"relativeTimeSeconds":13864303},{"id":2097,"name":"Codeforces Round 1021 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1745656500,"relativeTimeSeconds":14058703},{"id":2098,"name":"Codeforces Round 1021 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1745656500,"relativeTimeSeconds":14058703},{"id":2106,"name":"Codeforces Round 1020 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1745505300,"relativeTimeSeconds":14209903},{"id":2103,"name":"Codeforces Round 1019 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1745246100,"relativeTimeSeconds":14469103},{"id":2105,"name":"Tact Smart Battle 1","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":604800,"startTimeSeconds":1745226000,"relativeTimeSeconds":14489203},{"id":2096,"name":"Neowise Labs Contest 1 (Codeforces Round 1018, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1745073300,"relativeTimeSeconds":14641903},{"id":2094,"name":"Codeforces Round 1017 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1744558500,"relativeTimeSeconds":15156703},{"id":2093,"name":"Codeforces Round 1016 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1744122900,"relativeTimeSeconds":15592303},{"id":2087,"name":"Kotlin Heroes: Episode 12","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1744036500,"relativeTimeSeconds":15678703},{"id":2084,"name":"Teza Round 1 (Codeforces Round 1015, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1743863700,"relativeTimeSeconds":15851503},{"id":2086,"name":"Educational Codeforces Round 177 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1743690900,"relativeTimeSeconds":16024303},{"id":2095,"name":"April Fools Day Contest 2025","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1743518100,"relativeTimeSeconds":16197103},{"id":2088,"name":"Kotlin Heroes: Practice 12","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":604800,"startTimeSeconds":1743428100,"relativeTimeSeconds":16287103},{"id":2092,"name":"Codeforces Round 1014 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1743258900,"relativeTimeSeconds":16456303},{"id":2091,"name":"Codeforces Round 1013 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1742913300,"relativeTimeSeconds":16801903},{"id":2089,"name":"Codeforces Round 1012 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1742708100,"relativeTimeSeconds":17007103},{"id":2090,"name":"Codeforces Round 1012 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1742708100,"relativeTimeSeconds":17007103},{"id":2085,"name":"Codeforces Round 1011 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1742654100,"relativeTimeSeconds":17061103},{"id":2075,"name":"Educational Codeforces Round 176 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1742222100,"relativeTimeSeconds":17493103},{"id":2081,"name":"Codeforces Round 1010 (Div. 1, Unrated)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1742049300,"relativeTimeSeconds":17665903},{"id":2082,"name":"Codeforces Round 1010 (Div. 2, Unrated)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1742049300,"relativeTimeSeconds":17665903},{"id":2074,"name":"Codeforces Round 1009 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1741703700,"relativeTimeSeconds":18011503},{"id":2077,"name":"Codeforces Round 1008 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1741617900,"relativeTimeSeconds":18097303},{"id":2078,"name":"Codeforces Round 1008 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1741617900,"relativeTimeSeconds":18097303},{"id":2080,"name":"XIX Open Olympiad in Informatics - Final Stage, Day 2 (Unrated, Online Mirror, IOI rules)","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1741593900,"relativeTimeSeconds":18121303},{"id":2079,"name":"XIX Open Olympiad in Informatics - Final Stage, Day 1 (Unrated, Online Mirror, IOI rules)","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1741334700,"relativeTimeSeconds":18380503},{"id":2068,"name":"European Championship 2025 - Online Mirror (Unrated, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1740911700,"relativeTimeSeconds":18803503},{"id":2073,"name":"2025 ICPC Asia Pacific Championship - Online Mirror (Unrated, Online Mirror, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1740794700,"relativeTimeSeconds":18920503},{"id":2071,"name":"Codeforces Round 1007 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1740753300,"relativeTimeSeconds":18961903},{"id":2070,"name":"Educational Codeforces Round 175 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1740666900,"relativeTimeSeconds":19048303},{"id":2072,"name":"Codeforces Round 1006 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1740494100,"relativeTimeSeconds":19221103},{"id":2069,"name":"Educational Codeforces Round 174 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1739889300,"relativeTimeSeconds":19825903},{"id":2064,"name":"Codeforces Round 1005 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1739716500,"relativeTimeSeconds":19998703},{"id":2066,"name":"Codeforces Round 1004 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1739284500,"relativeTimeSeconds":20430701},{"id":2067,"name":"Codeforces Round 1004 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1739284500,"relativeTimeSeconds":20430701},{"id":2065,"name":"Codeforces Round 1003 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1739111700,"relativeTimeSeconds":20603503},{"id":2059,"name":"Codeforces Round 1002 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1738506900,"relativeTimeSeconds":21208303},{"id":2062,"name":"Ethflow Round 1 (Codeforces Round 1001, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1737902100,"relativeTimeSeconds":21813103},{"id":2063,"name":"Codeforces Round 1000 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1737547500,"relativeTimeSeconds":22167701},{"id":2061,"name":"IAEPC Preliminary Contest (Codeforces Round 999, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1737383700,"relativeTimeSeconds":22331501},{"id":2060,"name":"Codeforces Round 998 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1737297300,"relativeTimeSeconds":22417903},{"id":2056,"name":"Codeforces Round 997 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1737124500,"relativeTimeSeconds":22590701},{"id":2055,"name":"Codeforces Round 996 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1736692500,"relativeTimeSeconds":23022703},{"id":2057,"name":"Hello 2025","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1736001300,"relativeTimeSeconds":23713903},{"id":2053,"name":"Good Bye 2024: 2025 is NEAR","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1735396500,"relativeTimeSeconds":24318703},{"id":2043,"name":"Educational Codeforces Round 173 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1735050900,"relativeTimeSeconds":24664303},{"id":2054,"name":"MaraTON Challenge 1","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":1814400,"startTimeSeconds":1734960900,"relativeTimeSeconds":24754303},{"id":2051,"name":"Codeforces Round 995 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1734878100,"relativeTimeSeconds":24837103},{"id":2049,"name":"Codeforces Round 994 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1734705300,"relativeTimeSeconds":25009903},{"id":2048,"name":"Codeforces Global Round 28","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1734618900,"relativeTimeSeconds":25096303},{"id":2044,"name":"Codeforces Round 993 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1734273300,"relativeTimeSeconds":25441903},{"id":2052,"name":"2024-2025 ICPC, NERC, Northern Eurasia Finals (Unrated, Online Mirror, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1734248100,"relativeTimeSeconds":25467103},{"id":2040,"name":"Codeforces Round 992 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1733668500,"relativeTimeSeconds":26046703},{"id":2050,"name":"Codeforces Round 991 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1733409300,"relativeTimeSeconds":26305903},{"id":2046,"name":"Codeforces Round 990 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1733207100,"relativeTimeSeconds":26508103},{"id":2047,"name":"Codeforces Round 990 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1733207100,"relativeTimeSeconds":26508103},{"id":2042,"name":"Educational Codeforces Round 172 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1733150100,"relativeTimeSeconds":26565103},{"id":2045,"name":"2024-2025 ICPC Asia Jakarta Regional Contest (Unrated, Online Mirror, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"freezeDurationSeconds":3600,"startTimeSeconds":1733029500,"relativeTimeSeconds":26685703},{"id":2034,"name":"Rayan Programming Contest 2024 - Selection (Codeforces Round 989, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1732977300,"relativeTimeSeconds":26737903},{"id":2041,"name":"2024 ICPC Asia Taichung Regional Contest (Unrated, Online Mirror, ICPC Rules, Preferably Teams)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"freezeDurationSeconds":3600,"startTimeSeconds":1732431900,"relativeTimeSeconds":27283301},{"id":2039,"name":"CodeTON Round 9 (Div. 1 + Div. 2, Rated, Prizes!)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1732372500,"relativeTimeSeconds":27342703},{"id":2038,"name":"2024-2025 ICPC, NERC, Southern and Volga Russian Regional Contest (Unrated, Online Mirror, ICPC Rules, Preferably Teams)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1731926100,"relativeTimeSeconds":27789103},{"id":2037,"name":"Codeforces Round 988 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1731854100,"relativeTimeSeconds":27861103},{"id":2031,"name":"Codeforces Round 987 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1731674100,"relativeTimeSeconds":28041103},{"id":2028,"name":"Codeforces Round 986 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1731252900,"relativeTimeSeconds":28462303},{"id":2029,"name":"Refact.ai Match 1 (Codeforces Round 985)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1731162900,"relativeTimeSeconds":28552303},{"id":2036,"name":"Codeforces Round 984 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1730558100,"relativeTimeSeconds":29157103},{"id":2032,"name":"Codeforces Round 983 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1730471700,"relativeTimeSeconds":29243503},{"id":2026,"name":"Educational Codeforces Round 171 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1730126100,"relativeTimeSeconds":29589103},{"id":2035,"name":"Codeforces Global Round 27","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1730039700,"relativeTimeSeconds":29675503},{"id":2027,"name":"Codeforces Round 982 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1729953300,"relativeTimeSeconds":29761901},{"id":2033,"name":"Codeforces Round 981 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1729780500,"relativeTimeSeconds":29934703},{"id":2023,"name":"Codeforces Round 980 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1729415100,"relativeTimeSeconds":30300103},{"id":2024,"name":"Codeforces Round 980 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1729415100,"relativeTimeSeconds":30300103},{"id":2030,"name":"Codeforces Round 979 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1729346700,"relativeTimeSeconds":30368503},{"id":2025,"name":"Educational Codeforces Round 170 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1728916500,"relativeTimeSeconds":30798703},{"id":2022,"name":"Codeforces Round 978 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1728848100,"relativeTimeSeconds":30867103},{"id":2021,"name":"Codeforces Round 977 (Div. 2, based on COMPFEST 16 - Final Round)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1728194700,"relativeTimeSeconds":31520503},{"id":2011,"name":"Kotlin Heroes: Episode 11","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1727706900,"relativeTimeSeconds":32008303},{"id":2020,"name":"Codeforces Round 976 (Div. 2) and Divide By Zero 9.0","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1727624100,"relativeTimeSeconds":32091103},{"id":2018,"name":"Codeforces Round 975 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1727444100,"relativeTimeSeconds":32271103},{"id":2019,"name":"Codeforces Round 975 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1727444100,"relativeTimeSeconds":32271103},{"id":2014,"name":"Codeforces Round 974 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1726929900,"relativeTimeSeconds":32785303},{"id":2013,"name":"Codeforces Round 973 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1726842900,"relativeTimeSeconds":32872303},{"id":2012,"name":"Kotlin Heroes: Practice 11","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":1123200,"startTimeSeconds":1726583700,"relativeTimeSeconds":33131503},{"id":2015,"name":"2024 ICPC World Finals Challenge powered by Huawei","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1726554840,"relativeTimeSeconds":33160363},{"id":2017,"name":"2024 ICPC World Finals: JetBrains Tech Trek","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":2580,"startTimeSeconds":1726548420,"relativeTimeSeconds":33166783},{"id":2005,"name":"Codeforces Round 972 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1726324500,"relativeTimeSeconds":33390703},{"id":2009,"name":"Codeforces Round 971 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1725374100,"relativeTimeSeconds":34341103},{"id":2008,"name":"Codeforces Round 970 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1725201300,"relativeTimeSeconds":34513903},{"id":2006,"name":"Codeforces Round 969 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1725028500,"relativeTimeSeconds":34686703},{"id":2007,"name":"Codeforces Round 969 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1725028500,"relativeTimeSeconds":34686703},{"id":2010,"name":"Testing Round 19 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":2700,"startTimeSeconds":1724877300,"relativeTimeSeconds":34837903},{"id":2003,"name":"Codeforces Round 968 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1724596500,"relativeTimeSeconds":35118703},{"id":2001,"name":"Codeforces Round 967 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1724164500,"relativeTimeSeconds":35550703},{"id":2004,"name":"Educational Codeforces Round 169 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1723732500,"relativeTimeSeconds":35982703},{"id":2000,"name":"Codeforces Round 966 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1723560000,"relativeTimeSeconds":36155203},{"id":2002,"name":"EPIC Institute of Technology Round August 2024 (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1723386900,"relativeTimeSeconds":36328303},{"id":1998,"name":"Codeforces Round 965 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1723300500,"relativeTimeSeconds":36414703},{"id":1999,"name":"Codeforces Round 964 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8700,"startTimeSeconds":1722954900,"relativeTimeSeconds":36760301},{"id":1993,"name":"Codeforces Round 963 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1722782100,"relativeTimeSeconds":36933103},{"id":1997,"name":"Educational Codeforces Round 168 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1722350100,"relativeTimeSeconds":37365103},{"id":1991,"name":"Pinely Round 4 (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1722177300,"relativeTimeSeconds":37537903},{"id":1996,"name":"Codeforces Round 962 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1722004500,"relativeTimeSeconds":37710703},{"id":1995,"name":"Codeforces Round 961 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1721745300,"relativeTimeSeconds":37969903},{"id":1990,"name":"Codeforces Round 960 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1721486100,"relativeTimeSeconds":38229103},{"id":1994,"name":"Codeforces Round 959 sponsored by NEAR (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1721313300,"relativeTimeSeconds":38401903},{"id":1988,"name":"Codeforces Round 958 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1721054100,"relativeTimeSeconds":38661103},{"id":1992,"name":"Codeforces Round 957 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1720708500,"relativeTimeSeconds":39006703},{"id":1983,"name":"Codeforces Round 956 (Div. 2) and ByteRace 2024","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1720362900,"relativeTimeSeconds":39352301},{"id":1987,"name":"EPIC Institute of Technology Round Summer 2024 (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1719758100,"relativeTimeSeconds":39957103},{"id":1989,"name":"Educational Codeforces Round 167 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1719498900,"relativeTimeSeconds":40216303},{"id":1982,"name":"Codeforces Round 955 (Div. 2, with prizes from NEAR!)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1719326100,"relativeTimeSeconds":40389103},{"id":1986,"name":"Codeforces Round 954 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1719154200,"relativeTimeSeconds":40561003},{"id":1978,"name":"Codeforces Round 953 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1718528700,"relativeTimeSeconds":41186503},{"id":1985,"name":"Codeforces Round 952 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1718116500,"relativeTimeSeconds":41598703},{"id":1984,"name":"Codeforces Global Round 26","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1717943700,"relativeTimeSeconds":41771503},{"id":1979,"name":"Codeforces Round 951 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1717684500,"relativeTimeSeconds":42030703},{"id":1980,"name":"Codeforces Round 950 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1717425300,"relativeTimeSeconds":42289903},{"id":1981,"name":"Codeforces Round 949 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1717149900,"relativeTimeSeconds":42565301},{"id":1976,"name":"Educational Codeforces Round 166 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1717079700,"relativeTimeSeconds":42635503},{"id":1977,"name":"Codeforces Round 948 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1716734100,"relativeTimeSeconds":42981103},{"id":1975,"name":"Codeforces Round 947 (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1716647700,"relativeTimeSeconds":43067503},{"id":1974,"name":"Codeforces Round 946 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1716215700,"relativeTimeSeconds":43499501},{"id":1973,"name":"Codeforces Round 945 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1715956500,"relativeTimeSeconds":43758703},{"id":1958,"name":"Kotlin Heroes: Episode 10","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1715610900,"relativeTimeSeconds":44104303},{"id":1971,"name":"Codeforces Round 944 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1715351700,"relativeTimeSeconds":44363503},{"id":1959,"name":"Kotlin Heroes: Practice 10","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":511200,"startTimeSeconds":1715096100,"relativeTimeSeconds":44619103},{"id":1953,"name":"2023 Post World Finals Online ICPC Challenge powered by Huawei","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":1472400,"startTimeSeconds":1715007600,"relativeTimeSeconds":44707603},{"id":1970,"name":"Helvetic Coding Contest 2024 online mirror (teams allowed, unrated)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":16200,"startTimeSeconds":1714806300,"relativeTimeSeconds":44908903},{"id":1968,"name":"Codeforces Round 943 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1714661100,"relativeTimeSeconds":45054103},{"id":1967,"name":"Codeforces Round 942 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1714487700,"relativeTimeSeconds":45227501},{"id":1972,"name":"Codeforces Round 942 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1714487700,"relativeTimeSeconds":45227503},{"id":1969,"name":"Educational Codeforces Round 165 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1714401300,"relativeTimeSeconds":45313903},{"id":1965,"name":"Codeforces Round 941 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1714228500,"relativeTimeSeconds":45486701},{"id":1966,"name":"Codeforces Round 941 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1714228500,"relativeTimeSeconds":45486703},{"id":1957,"name":"Codeforces Round 940 (Div. 2) and CodeCraft-23","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1713710100,"relativeTimeSeconds":46005103},{"id":1956,"name":"Codeforces Round 939 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1713018900,"relativeTimeSeconds":46696301},{"id":1954,"name":"Educational Codeforces Round 164 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1712932500,"relativeTimeSeconds":46782701},{"id":1955,"name":"Codeforces Round 938 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1712586900,"relativeTimeSeconds":47128301},{"id":1951,"name":"Codeforces Global Round 25","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1712414100,"relativeTimeSeconds":47301101},{"id":1952,"name":"April Fools Day Contest 2024","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1711982100,"relativeTimeSeconds":47733103},{"id":1942,"name":"CodeTON Round 8 (Div. 1 + Div. 2, Rated, Prizes!)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1711809300,"relativeTimeSeconds":47905903},{"id":1950,"name":"Codeforces Round 937 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1711637100,"relativeTimeSeconds":48078103},{"id":1949,"name":"European Championship 2024 - Online Mirror (Unrated, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1711274400,"relativeTimeSeconds":48440803},{"id":1946,"name":"Codeforces Round 936 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1711118100,"relativeTimeSeconds":48597103},{"id":1945,"name":"Codeforces Round 935 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1710835500,"relativeTimeSeconds":48879703},{"id":1943,"name":"Codeforces Round 934 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8700,"startTimeSeconds":1710599700,"relativeTimeSeconds":49115503},{"id":1944,"name":"Codeforces Round 934 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8700,"startTimeSeconds":1710599700,"relativeTimeSeconds":49115503},{"id":1948,"name":"Educational Codeforces Round 163 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1710513300,"relativeTimeSeconds":49201903},{"id":1941,"name":"Codeforces Round 933 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1710167700,"relativeTimeSeconds":49547503},{"id":1940,"name":"XVIII Open Olympiad in Informatics - Final Stage, Day 2 (Unrated, Online Mirror, IOI rules)","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1709975100,"relativeTimeSeconds":49740103},{"id":1939,"name":"XVIII Open Olympiad in Informatics - Final Stage, Day 1 (Unrated, Online Mirror, IOI rules)","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1709888700,"relativeTimeSeconds":49826503},{"id":1935,"name":"Codeforces Round 932 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1709649300,"relativeTimeSeconds":50065903},{"id":1938,"name":"2024 ICPC Asia Pacific Championship - Online Mirror (Unrated, Online Mirror, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1709346900,"relativeTimeSeconds":50368303},{"id":1934,"name":"Codeforces Round 931 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1709303700,"relativeTimeSeconds":50411503},{"id":1936,"name":"Codeforces Round 930 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1709217300,"relativeTimeSeconds":50497901},{"id":1937,"name":"Codeforces Round 930 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1709217300,"relativeTimeSeconds":50497903},{"id":1933,"name":"Codeforces Round 929 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1709044500,"relativeTimeSeconds":50670703},{"id":1923,"name":"Educational Codeforces Round 162 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1708698900,"relativeTimeSeconds":51016303},{"id":1926,"name":"Codeforces Round 928 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1708353300,"relativeTimeSeconds":51361903},{"id":1932,"name":"Codeforces Round 927 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1708257900,"relativeTimeSeconds":51457303},{"id":1930,"name":"think-cell Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1708180500,"relativeTimeSeconds":51534703},{"id":1929,"name":"Codeforces Round 926 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1708007700,"relativeTimeSeconds":51707503},{"id":1931,"name":"Codeforces Round 925 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1707834900,"relativeTimeSeconds":51880303},{"id":1928,"name":"Codeforces Round 924 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1707644100,"relativeTimeSeconds":52071103},{"id":1927,"name":"Codeforces Round 923 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1707230700,"relativeTimeSeconds":52484503},{"id":1918,"name":"Codeforces Round 922 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1706625300,"relativeTimeSeconds":53089903},{"id":1924,"name":"Codeforces Round 921 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1706366700,"relativeTimeSeconds":53348503},{"id":1925,"name":"Codeforces Round 921 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1706366700,"relativeTimeSeconds":53348501},{"id":1922,"name":"Educational Codeforces Round 161 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1705588500,"relativeTimeSeconds":54126703},{"id":1921,"name":"Codeforces Round 920 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1705329300,"relativeTimeSeconds":54385903},{"id":1920,"name":"Codeforces Round 919 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1705156500,"relativeTimeSeconds":54558703},{"id":1919,"name":"Hello 2024","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1704551700,"relativeTimeSeconds":55163503},{"id":1916,"name":"Good Bye 2023","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1703947800,"relativeTimeSeconds":55767401},{"id":1915,"name":"Codeforces Round 918 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1703774100,"relativeTimeSeconds":55941103},{"id":1917,"name":"Codeforces Round 917 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1703428500,"relativeTimeSeconds":56286703},{"id":1909,"name":"Pinely Round 3 (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1703342100,"relativeTimeSeconds":56373103},{"id":1914,"name":"Codeforces Round 916 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1702996500,"relativeTimeSeconds":56718701},{"id":1913,"name":"Educational Codeforces Round 160 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1702910100,"relativeTimeSeconds":56805103},{"id":1905,"name":"Codeforces Round 915 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1702737300,"relativeTimeSeconds":56977903},{"id":1912,"name":"2023-2024 ICPC, NERC, Northern Eurasia Onsite (Unrated, Online Mirror, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1702452900,"relativeTimeSeconds":57262303},{"id":1910,"name":"Kotlin Heroes: Episode 9 (Unrated, T-Shirts + Prizes!)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1702305300,"relativeTimeSeconds":57409903},{"id":1904,"name":"Codeforces Round 914 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1702137900,"relativeTimeSeconds":57577303},{"id":1907,"name":"Codeforces Round 913 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1701787500,"relativeTimeSeconds":57927703},{"id":1902,"name":"Educational Codeforces Round 159 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1701614100,"relativeTimeSeconds":58101103},{"id":1906,"name":"2023-2024 ICPC, Asia Jakarta Regional Contest (Online Mirror, Unrated, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"freezeDurationSeconds":3600,"startTimeSeconds":1701578100,"relativeTimeSeconds":58137103},{"id":1911,"name":"Kotlin Heroes: Practice 9 (release 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":864000,"startTimeSeconds":1701440700,"relativeTimeSeconds":58274503},{"id":1903,"name":"Codeforces Round 912 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1701362100,"relativeTimeSeconds":58353103},{"id":1900,"name":"Codeforces Round 911 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1701009300,"relativeTimeSeconds":58705903},{"id":1896,"name":"CodeTON Round 7 (Div. 1 + Div. 2, Rated, Prizes!)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1700923800,"relativeTimeSeconds":58791401},{"id":1901,"name":"Educational Codeforces Round 158 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1700836500,"relativeTimeSeconds":58878701},{"id":1885,"name":"ICPC 2023 Online Challenge powered by Huawei","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":1209600,"startTimeSeconds":1700463600,"relativeTimeSeconds":59251603},{"id":1898,"name":"Codeforces Round 910 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1700404500,"relativeTimeSeconds":59310703},{"id":1899,"name":"Codeforces Round 909 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1700231700,"relativeTimeSeconds":59483503},{"id":1893,"name":"Codeforces Round 908 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1699367700,"relativeTimeSeconds":60347503},{"id":1894,"name":"Codeforces Round 908 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1699367700,"relativeTimeSeconds":60347503},{"id":1895,"name":"Educational Codeforces Round 157 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1699022100,"relativeTimeSeconds":60693103},{"id":1891,"name":"Codeforces Round 907 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1698676500,"relativeTimeSeconds":61038703},{"id":1889,"name":"Codeforces Round 906 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1698503700,"relativeTimeSeconds":61211503},{"id":1890,"name":"Codeforces Round 906 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1698503700,"relativeTimeSeconds":61211503},{"id":1887,"name":"Codeforces Round 905 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1697972700,"relativeTimeSeconds":61742503},{"id":1888,"name":"Codeforces Round 905 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1697972700,"relativeTimeSeconds":61742503},{"id":1883,"name":"Codeforces Round 905 (Div. 3)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1697972700,"relativeTimeSeconds":61742503},{"id":1884,"name":"Codeforces Round 904 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1697958300,"relativeTimeSeconds":61756901},{"id":1881,"name":"Codeforces Round 903 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1697121300,"relativeTimeSeconds":62593903},{"id":1886,"name":"Educational Codeforces Round 156 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1696862100,"relativeTimeSeconds":62853103},{"id":1876,"name":"Codeforces Round 902 (Div. 1, based on COMPFEST 15 - Final Round)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1696755900,"relativeTimeSeconds":62959303},{"id":1877,"name":"Codeforces Round 902 (Div. 2, based on COMPFEST 15 - Final Round)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1696755900,"relativeTimeSeconds":62959303},{"id":1874,"name":"Codeforces Round 901 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1696084500,"relativeTimeSeconds":63630701},{"id":1875,"name":"Codeforces Round 901 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1696084500,"relativeTimeSeconds":63630703},{"id":1878,"name":"Codeforces Round 900 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1695738900,"relativeTimeSeconds":63976303},{"id":1882,"name":"Codeforces Round 899 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1695652500,"relativeTimeSeconds":64062701},{"id":1879,"name":"Educational Codeforces Round 155 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1695566100,"relativeTimeSeconds":64149101},{"id":1873,"name":"Codeforces Round 898 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1695306900,"relativeTimeSeconds":64408303},{"id":1870,"name":"CodeTON Round 6 (Div. 1 + Div. 2, Rated, Prizes!)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1695047700,"relativeTimeSeconds":64667503},{"id":1867,"name":"Codeforces Round 897 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1694442900,"relativeTimeSeconds":65272303},{"id":1868,"name":"Codeforces Round 896 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1694354700,"relativeTimeSeconds":65360503},{"id":1869,"name":"Codeforces Round 896 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1694354700,"relativeTimeSeconds":65360503},{"id":1872,"name":"Codeforces Round 895 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1694097300,"relativeTimeSeconds":65617903},{"id":1866,"name":"COMPFEST 15 - Preliminary Online Mirror (Unrated, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"freezeDurationSeconds":3600,"startTimeSeconds":1693742700,"relativeTimeSeconds":65972503},{"id":1861,"name":"Educational Codeforces Round 154 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1693492500,"relativeTimeSeconds":66222703},{"id":1863,"name":"Pinely Round 2 (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1693406100,"relativeTimeSeconds":66309103},{"id":1864,"name":"Harbour.Space Scholarship Contest 2023-2024 (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1693060500,"relativeTimeSeconds":66654703},{"id":1862,"name":"Codeforces Round 894 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1692887700,"relativeTimeSeconds":66827503},{"id":1860,"name":"Educational Codeforces Round 153 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1692282900,"relativeTimeSeconds":67432303},{"id":1858,"name":"Codeforces Round 893 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1692110100,"relativeTimeSeconds":67605103},{"id":1859,"name":"Codeforces Round 892 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1691850900,"relativeTimeSeconds":67864303},{"id":1857,"name":"Codeforces Round 891 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1691418900,"relativeTimeSeconds":68296303},{"id":1856,"name":"Codeforces Round 890 (Div. 2) supported by Constructor Institute","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1691246100,"relativeTimeSeconds":68469103},{"id":1854,"name":"Codeforces Round 889 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1690641300,"relativeTimeSeconds":69073903},{"id":1855,"name":"Codeforces Round 889 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1690641300,"relativeTimeSeconds":69073903},{"id":1849,"name":"Educational Codeforces Round 152 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1690468500,"relativeTimeSeconds":69246703},{"id":1851,"name":"Codeforces Round 888 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1690295700,"relativeTimeSeconds":69419503},{"id":1852,"name":"Codeforces Round 887 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1690122900,"relativeTimeSeconds":69592303},{"id":1853,"name":"Codeforces Round 887 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1690122900,"relativeTimeSeconds":69592303},{"id":1850,"name":"Codeforces Round 886 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1689950100,"relativeTimeSeconds":69765103},{"id":1848,"name":"Codeforces Round 885 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1689518100,"relativeTimeSeconds":70197103},{"id":1844,"name":"Codeforces Round 884 (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1689086100,"relativeTimeSeconds":70629103},{"id":1846,"name":"Codeforces Round 883 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1688740500,"relativeTimeSeconds":70974703},{"id":1847,"name":"Codeforces Round 882 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1688654100,"relativeTimeSeconds":71061103},{"id":1845,"name":"Educational Codeforces Round 151 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1688049300,"relativeTimeSeconds":71665903},{"id":1842,"name":"CodeTON Round 5 (Div. 1 + Div. 2, Rated, Prizes!)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1687615500,"relativeTimeSeconds":72099703},{"id":1843,"name":"Codeforces Round 881 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1687271700,"relativeTimeSeconds":72443503},{"id":1835,"name":"Codeforces Round 880 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1687098900,"relativeTimeSeconds":72616303},{"id":1836,"name":"Codeforces Round 880 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1687098900,"relativeTimeSeconds":72616303},{"id":1834,"name":"Codeforces Round 879 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1687075500,"relativeTimeSeconds":72639703},{"id":1841,"name":"Educational Codeforces Round 150 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1686580500,"relativeTimeSeconds":73134703},{"id":1840,"name":"Codeforces Round 878 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1686062100,"relativeTimeSeconds":73653103},{"id":1838,"name":"Codeforces Round 877 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1685889900,"relativeTimeSeconds":73825303},{"id":1839,"name":"Codeforces Round 876 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1685802900,"relativeTimeSeconds":73912303},{"id":1830,"name":"Codeforces Round 875 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1685284500,"relativeTimeSeconds":74430703},{"id":1831,"name":"Codeforces Round 875 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1685284500,"relativeTimeSeconds":74430703},{"id":1837,"name":"Educational Codeforces Round 149 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1685025300,"relativeTimeSeconds":74689903},{"id":1833,"name":"Codeforces Round 874 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1684506900,"relativeTimeSeconds":75208303},{"id":1827,"name":"Codeforces Round 873 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1684074900,"relativeTimeSeconds":75640303},{"id":1828,"name":"Codeforces Round 873 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1684074900,"relativeTimeSeconds":75640303},{"id":1832,"name":"Educational Codeforces Round 148 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1683902100,"relativeTimeSeconds":75813103},{"id":1824,"name":"Codeforces Round 872 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1683547500,"relativeTimeSeconds":76167703},{"id":1825,"name":"Codeforces Round 872 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1683547500,"relativeTimeSeconds":76167703},{"id":1829,"name":"Codeforces Round 871 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1683383700,"relativeTimeSeconds":76331503},{"id":1826,"name":"Codeforces Round 870 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1683297300,"relativeTimeSeconds":76417903},{"id":1817,"name":"Codeforces Round 869 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1682778900,"relativeTimeSeconds":76936303},{"id":1818,"name":"Codeforces Round 869 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1682778900,"relativeTimeSeconds":76936303},{"id":1823,"name":"Codeforces Round 868 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1682606100,"relativeTimeSeconds":77109103},{"id":1822,"name":"Codeforces Round 867 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1682346900,"relativeTimeSeconds":77368303},{"id":1821,"name":"Educational Codeforces Round 147 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1682001300,"relativeTimeSeconds":77713903},{"id":1819,"name":"Codeforces Round 866 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1681549500,"relativeTimeSeconds":78165703},{"id":1820,"name":"Codeforces Round 866 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1681549500,"relativeTimeSeconds":78165703},{"id":1813,"name":"ICPC 2023 Online Spring Challenge powered by Huawei","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":1209600,"startTimeSeconds":1681383600,"relativeTimeSeconds":78331603},{"id":1815,"name":"Codeforces Round 865 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1681051500,"relativeTimeSeconds":78663703},{"id":1816,"name":"Codeforces Round 865 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1681051500,"relativeTimeSeconds":78663703},{"id":1797,"name":"Codeforces Round 864 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1680962700,"relativeTimeSeconds":78752503},{"id":1814,"name":"Educational Codeforces Round 146 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1680791700,"relativeTimeSeconds":78923503},{"id":1811,"name":"Codeforces Round 863 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1680618900,"relativeTimeSeconds":79096303},{"id":1805,"name":"Codeforces Round 862 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1680446100,"relativeTimeSeconds":79269103},{"id":1812,"name":"April Fools Day Contest 2023","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1680359700,"relativeTimeSeconds":79355503},{"id":1810,"name":"CodeTON Round 4 (Div. 1 + Div. 2, Rated, Prizes!)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1680273300,"relativeTimeSeconds":79441903},{"id":1808,"name":"Codeforces Round 861 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1680080700,"relativeTimeSeconds":79634503},{"id":1798,"name":"Codeforces Round 860 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1679841300,"relativeTimeSeconds":79873903},{"id":1809,"name":"Educational Codeforces Round 145 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1679582100,"relativeTimeSeconds":80133103},{"id":1807,"name":"Codeforces Round 859 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1679237700,"relativeTimeSeconds":80477503},{"id":1806,"name":"Codeforces Round 858 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1679141100,"relativeTimeSeconds":80574103},{"id":1804,"name":"Nebius Welcome Round (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1678631700,"relativeTimeSeconds":81083503},{"id":1801,"name":"Codeforces Round 857 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1678354500,"relativeTimeSeconds":81360703},{"id":1802,"name":"Codeforces Round 857 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1678354500,"relativeTimeSeconds":81360703},{"id":1794,"name":"Codeforces Round 856 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1677951300,"relativeTimeSeconds":81763903},{"id":1800,"name":"Codeforces Round 855 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1677767700,"relativeTimeSeconds":81947503},{"id":1796,"name":"Educational Codeforces Round 144 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1677594900,"relativeTimeSeconds":82120303},{"id":1799,"name":"Codeforces Round 854 by cybercats (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1677508500,"relativeTimeSeconds":82206703},{"id":1789,"name":"Codeforces Round 853 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1677334800,"relativeTimeSeconds":82380403},{"id":1776,"name":"SWERC 2022-2023 - Online Mirror (Unrated, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1676804700,"relativeTimeSeconds":82910503},{"id":1795,"name":"Educational Codeforces Round 143 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1676558100,"relativeTimeSeconds":83157103},{"id":1793,"name":"Codeforces Round 852 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1676190900,"relativeTimeSeconds":83524303},{"id":1788,"name":"Codeforces Round 851 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1675953300,"relativeTimeSeconds":83761903},{"id":1784,"name":"VK Cup 2022 - Финальный раунд (Engine)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1675598700,"relativeTimeSeconds":84116503},{"id":1785,"name":"Codeforces Round 850 (Div. 1, based on VK Cup 2022 - Final Round)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1675598700,"relativeTimeSeconds":84116503},{"id":1786,"name":"Codeforces Round 850 (Div. 2, based on VK Cup 2022 - Final Round)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1675598700,"relativeTimeSeconds":84116503},{"id":1791,"name":"Codeforces Round 849 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8700,"startTimeSeconds":1675434900,"relativeTimeSeconds":84280303},{"id":1778,"name":"Codeforces Round 848 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1675262100,"relativeTimeSeconds":84453103},{"id":1787,"name":"TypeDB Forces 2023 (Div. 1 + Div. 2, Rated, Prizes!)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1675002900,"relativeTimeSeconds":84712303},{"id":1790,"name":"Codeforces Round 847 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1674830100,"relativeTimeSeconds":84885103},{"id":1780,"name":"Codeforces Round 846 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1674657300,"relativeTimeSeconds":85057903},{"id":1792,"name":"Educational Codeforces Round 142 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1674570900,"relativeTimeSeconds":85144303},{"id":1777,"name":"Codeforces Round 845 (Div. 2) and ByteRace 2023","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1674311700,"relativeTimeSeconds":85403503},{"id":1781,"name":"VK Cup 2022 - Отборочный раунд (Engine)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1673784300,"relativeTimeSeconds":85930903},{"id":1782,"name":"Codeforces Round 844 (Div. 1 + Div. 2, based on VK Cup 2022 - Elimination Round)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1673784300,"relativeTimeSeconds":85930903},{"id":1775,"name":"Codeforces Round 843 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1673349300,"relativeTimeSeconds":86365903},{"id":1783,"name":"Educational Codeforces Round 141 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1673188500,"relativeTimeSeconds":86526703},{"id":1768,"name":"Codeforces Round 842 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1672929300,"relativeTimeSeconds":86785903},{"id":1779,"name":"Hello 2023","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1672756500,"relativeTimeSeconds":86958703},{"id":1770,"name":"Good Bye 2022: 2023 is NEAR","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1672410900,"relativeTimeSeconds":87304303},{"id":1731,"name":"Codeforces Round 841 (Div. 2) and Divide by Zero 2022","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1672151700,"relativeTimeSeconds":87563503},{"id":1763,"name":"Codeforces Round 840 (Div. 2) and Enigma 2022 - Cybros LNMIIT","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1671460500,"relativeTimeSeconds":88254703},{"id":1772,"name":"Codeforces Round 839 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1671374100,"relativeTimeSeconds":88341103},{"id":1774,"name":"Polynomial Round 2022 (Div. 1 + Div. 2, Rated, Prizes!)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1671287700,"relativeTimeSeconds":88427503},{"id":1767,"name":"Educational Codeforces Round 140 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1671201300,"relativeTimeSeconds":88513903},{"id":1762,"name":"Codeforces Round 838 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1671114900,"relativeTimeSeconds":88600303},{"id":1766,"name":"Educational Codeforces Round 139 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1670855700,"relativeTimeSeconds":88859503},{"id":1771,"name":"Codeforces Round 837 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1670772900,"relativeTimeSeconds":88942303},{"id":1773,"name":"2022-2023 ICPC, NERC, Northern Eurasia Onsite (Unrated, Online Mirror, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1670400300,"relativeTimeSeconds":89314903},{"id":1769,"name":"VK Cup 2022 - Квалификация (Engine)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":1339200,"startTimeSeconds":1670058000,"relativeTimeSeconds":89657203},{"id":1765,"name":"2022-2023 ICPC, NERC, Southern and Volga Russian Regional Contest (Online Mirror, ICPC Rules, Preferably Teams)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1669545300,"relativeTimeSeconds":90169903},{"id":1764,"name":"Codeforces Global Round 24","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1669471500,"relativeTimeSeconds":90243703},{"id":1758,"name":"Codeforces Round 836 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1669390500,"relativeTimeSeconds":90324703},{"id":1760,"name":"Codeforces Round 835 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8700,"startTimeSeconds":1669041300,"relativeTimeSeconds":90673903},{"id":1761,"name":"Pinely Round 1 (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1668954900,"relativeTimeSeconds":90760303},{"id":1759,"name":"Codeforces Round  834 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1668782100,"relativeTimeSeconds":90933103},{"id":1752,"name":"45th ICPC World Finals Challenge powered by Huawei - Problem 1","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":1209540,"startTimeSeconds":1668643200,"relativeTimeSeconds":91072003},{"id":1751,"name":"45th ICPC World Finals Challenge powered by Huawei - Problem 2","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":1209540,"startTimeSeconds":1668643200,"relativeTimeSeconds":91072003},{"id":1748,"name":"Codeforces Round 833 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1668263700,"relativeTimeSeconds":91451503},{"id":1755,"name":"Ecnerwala vs Errichto Kotlin Match","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":2400,"startTimeSeconds":1667794620,"relativeTimeSeconds":91920583},{"id":1750,"name":"CodeTON Round 3 (Div. 1 + Div. 2, Rated, Prizes!)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1667745300,"relativeTimeSeconds":91969903},{"id":1747,"name":"Codeforces Round 832 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1667572500,"relativeTimeSeconds":92142703},{"id":1740,"name":"Codeforces Round 831 (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9900,"startTimeSeconds":1667034600,"relativeTimeSeconds":92680603},{"id":1732,"name":"Codeforces Round 830 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1666519500,"relativeTimeSeconds":93195703},{"id":1753,"name":"Codeforces Round 829 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1666511400,"relativeTimeSeconds":93203803},{"id":1754,"name":"Codeforces Round 829 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1666511400,"relativeTimeSeconds":93203803},{"id":1749,"name":"Educational Codeforces Round 138 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1666276500,"relativeTimeSeconds":93438703},{"id":1743,"name":"Educational Codeforces Round 137 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1666017300,"relativeTimeSeconds":93697903},{"id":1744,"name":"Codeforces Round  828 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1665930900,"relativeTimeSeconds":93784303},{"id":1746,"name":"Codeforces Global Round 23","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1665844500,"relativeTimeSeconds":93870703},{"id":1742,"name":"Codeforces Round 827 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8700,"startTimeSeconds":1665671700,"relativeTimeSeconds":94043503},{"id":1741,"name":"Codeforces Round 826 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1665498900,"relativeTimeSeconds":94216301},{"id":1736,"name":"Codeforces Round 825 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1665412500,"relativeTimeSeconds":94302703},{"id":1737,"name":"Dytechlab Cup 2022","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1665153300,"relativeTimeSeconds":94561903},{"id":1735,"name":"Codeforces Round 824 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1664721300,"relativeTimeSeconds":94993903},{"id":1738,"name":"Codeforces Global Round 22","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1664548500,"relativeTimeSeconds":95166703},{"id":1739,"name":"Educational Codeforces Round 136 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1664462100,"relativeTimeSeconds":95253103},{"id":1730,"name":"Codeforces Round 823 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1664116500,"relativeTimeSeconds":95598703},{"id":1734,"name":"Codeforces Round 822 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1663934700,"relativeTimeSeconds":95780503},{"id":1733,"name":"Codeforces Round 821 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1663598100,"relativeTimeSeconds":96117103},{"id":1723,"name":"ICPC 2022 Online Challenge powered by HUAWEI - Problem 1","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":1296000,"startTimeSeconds":1663200000,"relativeTimeSeconds":96515203},{"id":1724,"name":"ICPC 2022 Online Challenge powered by HUAWEI - Problem 2","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":1296000,"startTimeSeconds":1663200000,"relativeTimeSeconds":96515203},{"id":1729,"name":"Codeforces Round 820 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1662993300,"relativeTimeSeconds":96721903},{"id":1728,"name":"Educational Codeforces Round 135 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1662647700,"relativeTimeSeconds":97067503},{"id":1726,"name":"Codeforces Round 819 (Div. 1 + Div. 2) and Grimoire of Code Annual Contest 2022","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1662474900,"relativeTimeSeconds":97240303},{"id":1725,"name":"COMPFEST 14 - Preliminary Online Mirror (Unrated, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"freezeDurationSeconds":3600,"startTimeSeconds":1662298500,"relativeTimeSeconds":97416703},{"id":1717,"name":"Codeforces Round 818 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1662129300,"relativeTimeSeconds":97585903},{"id":1722,"name":"Codeforces Round 817 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1661871000,"relativeTimeSeconds":97844203},{"id":1721,"name":"Educational Codeforces Round 134 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1661610900,"relativeTimeSeconds":98104303},{"id":1715,"name":"Codeforces Round 816 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1661006100,"relativeTimeSeconds":98709103},{"id":1720,"name":"Codeforces Round 815 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1660829700,"relativeTimeSeconds":98885503},{"id":1718,"name":"Codeforces Round 814 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1660660500,"relativeTimeSeconds":99054703},{"id":1719,"name":"Codeforces Round 814 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1660660500,"relativeTimeSeconds":99054703},{"id":1712,"name":"Codeforces Round 813 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1660401300,"relativeTimeSeconds":99313903},{"id":1713,"name":"Codeforces Round 812 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1659796500,"relativeTimeSeconds":99918703},{"id":1716,"name":"Educational Codeforces Round 133 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1659623700,"relativeTimeSeconds":100091503},{"id":1714,"name":"Codeforces Round 811 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1659364500,"relativeTimeSeconds":100350703},{"id":1704,"name":"CodeTON Round 2 (Div. 1 + Div. 2, Rated, Prizes!)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1659276300,"relativeTimeSeconds":100438903},{"id":1710,"name":"Codeforces Round 810 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1658673300,"relativeTimeSeconds":101041903},{"id":1711,"name":"Codeforces Round 810 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1658673300,"relativeTimeSeconds":101041903},{"id":1709,"name":"Educational Codeforces Round 132 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1658414100,"relativeTimeSeconds":101301103},{"id":1706,"name":"Codeforces Round 809 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1658154900,"relativeTimeSeconds":101560303},{"id":1707,"name":"Codeforces Round 808 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1657982100,"relativeTimeSeconds":101733103},{"id":1708,"name":"Codeforces Round 808 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1657982100,"relativeTimeSeconds":101733103},{"id":1705,"name":"Codeforces Round 807 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1657892100,"relativeTimeSeconds":101823103},{"id":1703,"name":"Codeforces Round 806 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1657636500,"relativeTimeSeconds":102078703},{"id":1702,"name":"Codeforces Round 805 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1657463700,"relativeTimeSeconds":102251503},{"id":1701,"name":"Educational Codeforces Round 131 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1657290900,"relativeTimeSeconds":102424303},{"id":1699,"name":"Codeforces Round 804 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1656945300,"relativeTimeSeconds":102769903},{"id":1698,"name":"Codeforces Round 803 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1656426900,"relativeTimeSeconds":103288303},{"id":1696,"name":"Codeforces Global Round 21","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1656167700,"relativeTimeSeconds":103547503},{"id":1700,"name":"Codeforces Round 802 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1655629500,"relativeTimeSeconds":104085703},{"id":1695,"name":"Codeforces Round 801 (Div. 2) and EPIC Institute of Technology Round","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1655562900,"relativeTimeSeconds":104152303},{"id":1693,"name":"Codeforces Round 800 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1655390100,"relativeTimeSeconds":104325103},{"id":1694,"name":"Codeforces Round 800 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1655390100,"relativeTimeSeconds":104325103},{"id":1692,"name":"Codeforces Round 799 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1655217300,"relativeTimeSeconds":104497903},{"id":1697,"name":"Educational Codeforces Round 130 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1655044500,"relativeTimeSeconds":104670703},{"id":1689,"name":"Codeforces Round 798 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1654878900,"relativeTimeSeconds":104836303},{"id":1690,"name":"Codeforces Round 797 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1654612500,"relativeTimeSeconds":105102703},{"id":1687,"name":"Codeforces Round 796 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1654266900,"relativeTimeSeconds":105448303},{"id":1688,"name":"Codeforces Round 796 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1654266900,"relativeTimeSeconds":105448303},{"id":1691,"name":"CodeCraft-22 and Codeforces Round 795 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1654007700,"relativeTimeSeconds":105707503},{"id":1685,"name":"Codeforces Round 794 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1653500100,"relativeTimeSeconds":106215103},{"id":1686,"name":"Codeforces Round 794 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1653500100,"relativeTimeSeconds":106215103},{"id":1681,"name":"Educational Codeforces Round 129 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1653316500,"relativeTimeSeconds":106398703},{"id":1682,"name":"Codeforces Round 793 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1653230100,"relativeTimeSeconds":106485103},{"id":1684,"name":"Codeforces Round 792 (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1652970900,"relativeTimeSeconds":106744303},{"id":1679,"name":"Codeforces Round 791 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1652520900,"relativeTimeSeconds":107194303},{"id":1680,"name":"Educational Codeforces Round 128 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1652452500,"relativeTimeSeconds":107262703},{"id":1676,"name":"Codeforces Round 790 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1652193900,"relativeTimeSeconds":107521303},{"id":1677,"name":"Codeforces Round 789 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1652020500,"relativeTimeSeconds":107694703},{"id":1678,"name":"Codeforces Round 789 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1652020500,"relativeTimeSeconds":107694703},{"id":1670,"name":"Codeforces Round 788 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1651847700,"relativeTimeSeconds":107867503},{"id":1675,"name":"Codeforces Round 787 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1651761300,"relativeTimeSeconds":107953903},{"id":1674,"name":"Codeforces Round 786 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1651502100,"relativeTimeSeconds":108213103},{"id":1673,"name":"Codeforces Round 785 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1651329300,"relativeTimeSeconds":108385903},{"id":1662,"name":"SWERC 2021-2022 - Online Mirror (Unrated, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1650798300,"relativeTimeSeconds":108916903},{"id":1672,"name":"Codeforces Global Round 20","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1650722700,"relativeTimeSeconds":108992503},{"id":1671,"name":"Educational Codeforces Round 127 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1650638100,"relativeTimeSeconds":109077103},{"id":1669,"name":"Codeforces Round 784 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1650551700,"relativeTimeSeconds":109163503},{"id":1667,"name":"Codeforces Round 783 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1650378900,"relativeTimeSeconds":109336303},{"id":1668,"name":"Codeforces Round 783 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1650378900,"relativeTimeSeconds":109336303},{"id":1659,"name":"Codeforces Round 782 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1650206100,"relativeTimeSeconds":109509103},{"id":1666,"name":"2021-2022 ICPC, NERC, Northern Eurasia Onsite (Unrated, Online Mirror, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1649837100,"relativeTimeSeconds":109878103},{"id":1661,"name":"Educational Codeforces Round 126 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1649514900,"relativeTimeSeconds":110200303},{"id":1665,"name":"Codeforces Round 781 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1649428500,"relativeTimeSeconds":110286703},{"id":1663,"name":"April Fools Day Contest 2022","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1648823700,"relativeTimeSeconds":110891503},{"id":1660,"name":"Codeforces Round 780 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1648737300,"relativeTimeSeconds":110977903},{"id":1658,"name":"Codeforces Round 779 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1648391700,"relativeTimeSeconds":111323503},{"id":1656,"name":"CodeTON Round 1 (Div. 1 + Div. 2, Rated, Prizes!)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1648132500,"relativeTimeSeconds":111582703},{"id":1657,"name":"Educational Codeforces Round 125 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1647960300,"relativeTimeSeconds":111754903},{"id":1654,"name":"Codeforces Round 778 (Div. 1 + Div. 2, based on Technocup 2022 Final Round)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1647776100,"relativeTimeSeconds":111939103},{"id":1652,"name":"Технокубок 2022 - Финал","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1647764100,"relativeTimeSeconds":111951103},{"id":1647,"name":"Codeforces Round 777 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1647009300,"relativeTimeSeconds":112705903},{"id":1651,"name":"Educational Codeforces Round 124 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1646922900,"relativeTimeSeconds":112792303},{"id":1650,"name":"Codeforces Round 776 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1646750100,"relativeTimeSeconds":112965103},{"id":1648,"name":"Codeforces Round 775 (Div. 1, based on Moscow Open Olympiad in Informatics)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1646560500,"relativeTimeSeconds":113154703},{"id":1649,"name":"Codeforces Round 775 (Div. 2, based on Moscow Open Olympiad in Informatics)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1646560500,"relativeTimeSeconds":113154703},{"id":1646,"name":"Codeforces Round 774 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1646408100,"relativeTimeSeconds":113307103},{"id":1641,"name":"Codeforces Round 773 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1645611000,"relativeTimeSeconds":114104203},{"id":1642,"name":"Codeforces Round 773 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1645611000,"relativeTimeSeconds":114104203},{"id":1644,"name":"Educational Codeforces Round 123 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1645540500,"relativeTimeSeconds":114174703},{"id":1635,"name":"Codeforces Round 772 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1645367700,"relativeTimeSeconds":114347503},{"id":1638,"name":"Codeforces Round 771 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1644849300,"relativeTimeSeconds":114865903},{"id":1637,"name":"Codeforces Global Round 19","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1644676500,"relativeTimeSeconds":115038703},{"id":1634,"name":"Codeforces Round 770 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1644158100,"relativeTimeSeconds":115557103},{"id":1639,"name":"Pinely Treasure Hunt Contest","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":12600,"startTimeSeconds":1644055200,"relativeTimeSeconds":115660003},{"id":1633,"name":"Educational Codeforces Round 122 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1643639700,"relativeTimeSeconds":116075503},{"id":1632,"name":"Codeforces Round 769 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1643553300,"relativeTimeSeconds":116161903},{"id":1630,"name":"Codeforces Round 768 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1643294100,"relativeTimeSeconds":116421103},{"id":1631,"name":"Codeforces Round 768 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1643294100,"relativeTimeSeconds":116421103},{"id":1628,"name":"Codeforces Round 767 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1642862100,"relativeTimeSeconds":116853103},{"id":1629,"name":"Codeforces Round 767 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1642862100,"relativeTimeSeconds":116853103},{"id":1626,"name":"Educational Codeforces Round 121 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1642343700,"relativeTimeSeconds":117371503},{"id":1627,"name":"Codeforces Round 766 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1642257300,"relativeTimeSeconds":117457903},{"id":1625,"name":"Codeforces Round 765 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1641989100,"relativeTimeSeconds":117726103},{"id":1624,"name":"Codeforces Round 764 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1641825300,"relativeTimeSeconds":117889903},{"id":1621,"name":"Hello 2022","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1641220500,"relativeTimeSeconds":118494703},{"id":1616,"name":"Good Bye 2021: 2022 is NEAR","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1640792100,"relativeTimeSeconds":118923103},{"id":1623,"name":"Codeforces Round 763 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1640698500,"relativeTimeSeconds":119016703},{"id":1622,"name":"Educational Codeforces Round 120 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1640615700,"relativeTimeSeconds":119099503},{"id":1615,"name":"Codeforces Global Round 18","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1640356500,"relativeTimeSeconds":119358703},{"id":1619,"name":"Codeforces Round 762 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1640010900,"relativeTimeSeconds":119704303},{"id":1620,"name":"Educational Codeforces Round 119 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1639841700,"relativeTimeSeconds":119873503},{"id":1617,"name":"Codeforces Round 761 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1639661700,"relativeTimeSeconds":120053501},{"id":1618,"name":"Codeforces Round 760 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1639492500,"relativeTimeSeconds":120222703},{"id":1591,"name":"Codeforces Round 759 (Div. 2, based on Technocup 2022 Elimination Round 3)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1639322100,"relativeTimeSeconds":120393103},{"id":1585,"name":"Technocup 2022 - Elimination Round 3","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1639322100,"relativeTimeSeconds":120393103},{"id":1608,"name":"Codeforces Round 758 (Div.1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1639217100,"relativeTimeSeconds":120498103},{"id":1597,"name":"Технокубок 2022 - Ознакомительный Раунд 3","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":172800,"startTimeSeconds":1639145100,"relativeTimeSeconds":120570103},{"id":1613,"name":"Educational Codeforces Round 118 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1638369300,"relativeTimeSeconds":121345903},{"id":1609,"name":"Deltix Round, Autumn 2021 (open for everyone, rated, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1638110100,"relativeTimeSeconds":121605103},{"id":1614,"name":"Codeforces Round 757 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1637925300,"relativeTimeSeconds":121789903},{"id":1611,"name":"Codeforces Round 756 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1637850900,"relativeTimeSeconds":121864301},{"id":1610,"name":"Codeforces Global Round 17","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1637678100,"relativeTimeSeconds":122037103},{"id":1612,"name":"Educational Codeforces Round 117 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1637573700,"relativeTimeSeconds":122141503},{"id":1588,"name":"Codeforces Round 755 (Div. 1, based on Technocup 2022 Elimination Round 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1636869900,"relativeTimeSeconds":122845303},{"id":1589,"name":"Codeforces Round 755 (Div. 2, based on Technocup 2022 Elimination Round 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1636869900,"relativeTimeSeconds":122845303},{"id":1584,"name":"Technocup 2022 - Elimination Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1636869900,"relativeTimeSeconds":122845303},{"id":1605,"name":"Codeforces Round 754 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1636727700,"relativeTimeSeconds":122987503},{"id":1596,"name":"Технокубок 2022 - Ознакомительный Раунд 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":172800,"startTimeSeconds":1636693500,"relativeTimeSeconds":123021703},{"id":1607,"name":"Codeforces Round 753 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1635863700,"relativeTimeSeconds":123851503},{"id":1603,"name":"Codeforces Round 752 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1635604500,"relativeTimeSeconds":124110703},{"id":1604,"name":"Codeforces Round 752 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1635604500,"relativeTimeSeconds":124110703},{"id":1606,"name":"Educational Codeforces Round 116 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1635518100,"relativeTimeSeconds":124197103},{"id":1601,"name":"Codeforces Round 751 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1635143700,"relativeTimeSeconds":124571503},{"id":1602,"name":"Codeforces Round 751 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1635143700,"relativeTimeSeconds":124571503},{"id":1582,"name":"Codeforces Round 750 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1635069900,"relativeTimeSeconds":124645303},{"id":1586,"name":"Codeforces Round 749 (Div. 1 + Div. 2, based on Technocup 2022 Elimination Round 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1634468700,"relativeTimeSeconds":125246503},{"id":1583,"name":"Technocup 2022 - Elimination Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1634468700,"relativeTimeSeconds":125246503},{"id":1595,"name":"Технокубок 2022 - Ознакомительный Раунд 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":172800,"startTimeSeconds":1634292300,"relativeTimeSeconds":125422903},{"id":1593,"name":"Codeforces Round 748 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1634135700,"relativeTimeSeconds":125579503},{"id":1598,"name":"Educational Codeforces Round 115 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1633856700,"relativeTimeSeconds":125858503},{"id":1599,"name":"Bubble Cup 14 - Finals Online Mirror (Unrated, ICPC Rules, Teams Preferred, Div. 1)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":14400,"startTimeSeconds":1633770300,"relativeTimeSeconds":125944903},{"id":1600,"name":"Bubble Cup 14 - Finals Online Mirror (Unrated, ICPC Rules, Teams Preferred, Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":14400,"startTimeSeconds":1633770300,"relativeTimeSeconds":125944903},{"id":1576,"name":"2021 ICPC Communication Routing Challenge: Marathon","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":432000,"startTimeSeconds":1633737600,"relativeTimeSeconds":125977603},{"id":1594,"name":"Codeforces Round 747 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1633705500,"relativeTimeSeconds":126009703},{"id":1571,"name":"Kotlin Heroes: Episode 8","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9900,"startTimeSeconds":1633617300,"relativeTimeSeconds":126097903},{"id":1592,"name":"Codeforces Round 746 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1633271700,"relativeTimeSeconds":126443503},{"id":1575,"name":"COMPFEST 13 - Finals Online Mirror (Unrated, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"freezeDurationSeconds":3600,"startTimeSeconds":1633181700,"relativeTimeSeconds":126533503},{"id":1570,"name":"Kotlin Heroes: Practice 8","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":518400,"startTimeSeconds":1633095300,"relativeTimeSeconds":126619903},{"id":1578,"name":"ICPC WF Moscow Invitational Contest - Online Mirror (Unrated, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"freezeDurationSeconds":3600,"startTimeSeconds":1633093500,"relativeTimeSeconds":126621703},{"id":1580,"name":"Codeforces Round 745 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1632996900,"relativeTimeSeconds":126718303},{"id":1581,"name":"Codeforces Round 745 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1632996900,"relativeTimeSeconds":126718303},{"id":1579,"name":"Codeforces Round 744 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1632839700,"relativeTimeSeconds":126875503},{"id":1574,"name":"Educational Codeforces Round 114 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1632148500,"relativeTimeSeconds":127566703},{"id":1572,"name":"Codeforces Round 743 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1631975700,"relativeTimeSeconds":127739503},{"id":1573,"name":"Codeforces Round 743 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1631975700,"relativeTimeSeconds":127739503},{"id":1566,"name":"Codeforces Global Round 16","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1631457300,"relativeTimeSeconds":128257903},{"id":1569,"name":"Educational Codeforces Round 113 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1631111700,"relativeTimeSeconds":128603503},{"id":1567,"name":"Codeforces Round 742 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1630852500,"relativeTimeSeconds":128862703},{"id":1556,"name":"Deltix Round, Summer 2021 (open for everyone, rated, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1630247700,"relativeTimeSeconds":129467503},{"id":1562,"name":"Codeforces Round 741 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1629988500,"relativeTimeSeconds":129726703},{"id":1558,"name":"Codeforces Round 740 (Div. 1, based on VK Cup 2021 - Final (Engine))","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1629815700,"relativeTimeSeconds":129899503},{"id":1561,"name":"Codeforces Round 740 (Div. 2, based on VK Cup 2021 - Final (Engine))","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1629815700,"relativeTimeSeconds":129899503},{"id":1563,"name":"VK Cup 2021 - Final (Engine)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1629633900,"relativeTimeSeconds":130081303},{"id":1560,"name":"Codeforces Round 739 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1629297300,"relativeTimeSeconds":130417901},{"id":1559,"name":"Codeforces Round 738 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1629038100,"relativeTimeSeconds":130677103},{"id":1557,"name":"Codeforces Round 737 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1628519700,"relativeTimeSeconds":131195503},{"id":1548,"name":"Codeforces Round 736 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8700,"startTimeSeconds":1627828500,"relativeTimeSeconds":131886701},{"id":1549,"name":"Codeforces Round 736 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8700,"startTimeSeconds":1627828500,"relativeTimeSeconds":131886703},{"id":1555,"name":"Educational Codeforces Round 112 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1627655700,"relativeTimeSeconds":132059503},{"id":1554,"name":"Codeforces Round 735 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1627569300,"relativeTimeSeconds":132145903},{"id":1552,"name":"Codeforces Global Round 15","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9900,"startTimeSeconds":1627223700,"relativeTimeSeconds":132491503},{"id":1551,"name":"Codeforces Round 734 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1627050900,"relativeTimeSeconds":132664301},{"id":1553,"name":"Harbour.Space Scholarship Contest 2021-2022 (open for everyone, rated, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1626964500,"relativeTimeSeconds":132750703},{"id":1530,"name":"Codeforces Round 733 (Div. 1 + Div. 2, based on VK Cup 2021 - Elimination (Engine))","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1626532500,"relativeTimeSeconds":133182703},{"id":1544,"name":"VK Cup 2021 - Elimination (Engine)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1626532500,"relativeTimeSeconds":133182703},{"id":1550,"name":"Educational Codeforces Round 111 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1626273300,"relativeTimeSeconds":133441903},{"id":1545,"name":"Codeforces Round 732 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1626012300,"relativeTimeSeconds":133702903},{"id":1546,"name":"Codeforces Round 732 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1626012300,"relativeTimeSeconds":133702903},{"id":1547,"name":"Codeforces Round 731 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1625927700,"relativeTimeSeconds":133787503},{"id":1543,"name":"Codeforces Round 730 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1625668500,"relativeTimeSeconds":134046703},{"id":1542,"name":"Codeforces Round 729 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1625317500,"relativeTimeSeconds":134397703},{"id":1533,"name":"Kotlin Heroes: Episode 7","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1624977300,"relativeTimeSeconds":134737903},{"id":1540,"name":"Codeforces Round 728 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1624635300,"relativeTimeSeconds":135079903},{"id":1541,"name":"Codeforces Round 728 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1624635300,"relativeTimeSeconds":135079903},{"id":1532,"name":"Kotlin Heroes: Practice 7","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":604800,"startTimeSeconds":1624368900,"relativeTimeSeconds":135346303},{"id":1539,"name":"Codeforces Round 727 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1624183500,"relativeTimeSeconds":135531703},{"id":1537,"name":"Codeforces Round 726 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1624026900,"relativeTimeSeconds":135688303},{"id":1534,"name":"Codeforces LATOKEN Round 1 (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1623598500,"relativeTimeSeconds":136116703},{"id":1538,"name":"Codeforces Round 725 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1623335700,"relativeTimeSeconds":136379503},{"id":1536,"name":"Codeforces Round 724 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1622990100,"relativeTimeSeconds":136725103},{"id":1535,"name":"Educational Codeforces Round 110 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1622817300,"relativeTimeSeconds":136897903},{"id":1523,"name":"Deltix Round, Spring 2021 (open for everyone, rated, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1622385300,"relativeTimeSeconds":137329903},{"id":1526,"name":"Codeforces Round 723 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1622210700,"relativeTimeSeconds":137504503},{"id":1524,"name":"ICPC Challenge 2021: Marathon (powered by Huawei)","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":345600,"startTimeSeconds":1622001600,"relativeTimeSeconds":137713603},{"id":1528,"name":"Codeforces Round 722 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1621866900,"relativeTimeSeconds":137848303},{"id":1529,"name":"Codeforces Round 722 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1621866900,"relativeTimeSeconds":137848303},{"id":1531,"name":"VK Cup 2021 - Квалификация (Engine)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":561600,"startTimeSeconds":1621846800,"relativeTimeSeconds":137868403},{"id":1527,"name":"Codeforces Round 721 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1621521300,"relativeTimeSeconds":138193903},{"id":1522,"name":"Codeforces Raif ML Round 1","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":1209600,"startTimeSeconds":1621267200,"relativeTimeSeconds":138448003},{"id":1525,"name":"Educational Codeforces Round 109 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1621152000,"relativeTimeSeconds":138563203},{"id":1521,"name":"Codeforces Round 720 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1620398100,"relativeTimeSeconds":139317103},{"id":1520,"name":"Codeforces Round 719 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1620225300,"relativeTimeSeconds":139489901},{"id":1515,"name":"Codeforces Global Round 14","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1619966100,"relativeTimeSeconds":139749103},{"id":1519,"name":"Educational Codeforces Round 108 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1619706900,"relativeTimeSeconds":140008303},{"id":1517,"name":"Contest 2050 and Codeforces Round 718 (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9900,"startTimeSeconds":1619188500,"relativeTimeSeconds":140526703},{"id":1516,"name":"Codeforces Round 717 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1619012100,"relativeTimeSeconds":140703103},{"id":1514,"name":"Codeforces Round 716 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1618839300,"relativeTimeSeconds":140875903},{"id":1508,"name":"Codeforces Round 715 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1618583700,"relativeTimeSeconds":141131503},{"id":1509,"name":"Codeforces Round 715 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1618583700,"relativeTimeSeconds":141131501},{"id":1511,"name":"Educational Codeforces Round 107 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1618238100,"relativeTimeSeconds":141477103},{"id":1513,"name":"Divide by Zero 2021 and Codeforces Round 714 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1618151700,"relativeTimeSeconds":141563503},{"id":1512,"name":"Codeforces Round 713 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1618065300,"relativeTimeSeconds":141649903},{"id":1510,"name":"2020-2021 ICPC, NERC, Northern Eurasia Onsite (Unrated, Online Mirror, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1617523500,"relativeTimeSeconds":142191703},{"id":1503,"name":"Codeforces Round 712 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1617460500,"relativeTimeSeconds":142254703},{"id":1504,"name":"Codeforces Round 712 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1617460500,"relativeTimeSeconds":142254703},{"id":1505,"name":"April Fools Day Contest 2021","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1617287700,"relativeTimeSeconds":142427503},{"id":1498,"name":"CodeCraft-21 and Codeforces Round 711 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1617028500,"relativeTimeSeconds":142686703},{"id":1506,"name":"Codeforces Round 710 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1616682900,"relativeTimeSeconds":143032303},{"id":1483,"name":"Codeforces Round 709 (Div. 1, based on Technocup 2021 Final Round)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1616332800,"relativeTimeSeconds":143382403},{"id":1484,"name":"Codeforces Round 709 (Div. 2, based on Technocup 2021 Final Round)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1616332800,"relativeTimeSeconds":143382403},{"id":1482,"name":"Технокубок 2021 - Финал","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1616322000,"relativeTimeSeconds":143393203},{"id":1499,"name":"Educational Codeforces Round 106 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1616079000,"relativeTimeSeconds":143636203},{"id":1497,"name":"Codeforces Round 708 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1615991700,"relativeTimeSeconds":143723503},{"id":1500,"name":"Codeforces Round 707 (Div. 1, based on Moscow Open Olympiad in Informatics)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1615626300,"relativeTimeSeconds":144088903},{"id":1501,"name":"Codeforces Round 707 (Div. 2, based on Moscow Open Olympiad in Informatics)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1615626300,"relativeTimeSeconds":144088903},{"id":1495,"name":"Codeforces Round 706 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1615377900,"relativeTimeSeconds":144337303},{"id":1496,"name":"Codeforces Round 706 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1615377900,"relativeTimeSeconds":144337303},{"id":1488,"name":"Kotlin Heroes: Episode 6","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1615300500,"relativeTimeSeconds":144414703},{"id":1493,"name":"Codeforces Round 705 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1615039500,"relativeTimeSeconds":144675703},{"id":1494,"name":"Educational Codeforces Round 105 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1614696300,"relativeTimeSeconds":145018903},{"id":1489,"name":"Kotlin Heroes: Practice 6","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":604800,"startTimeSeconds":1614692100,"relativeTimeSeconds":145023103},{"id":1491,"name":"Codeforces Global Round 13","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1614519300,"relativeTimeSeconds":145195903},{"id":1492,"name":"Codeforces Round 704 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1614071100,"relativeTimeSeconds":145644103},{"id":1486,"name":"Codeforces Round 703 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1613658900,"relativeTimeSeconds":146056303},{"id":1490,"name":"Codeforces Round 702 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1613486100,"relativeTimeSeconds":146229103},{"id":1487,"name":"Educational Codeforces Round 104 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1613399700,"relativeTimeSeconds":146315503},{"id":1485,"name":"Codeforces Round 701 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1613141400,"relativeTimeSeconds":146573803},{"id":1479,"name":"Codeforces Round 700 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1612708500,"relativeTimeSeconds":147006701},{"id":1480,"name":"Codeforces Round 700 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1612708500,"relativeTimeSeconds":147006703},{"id":1481,"name":"Codeforces Round 699 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1612535700,"relativeTimeSeconds":147179503},{"id":1476,"name":"Educational Codeforces Round 103 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1611930900,"relativeTimeSeconds":147784303},{"id":1477,"name":"Codeforces Round 698 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1611844500,"relativeTimeSeconds":147870703},{"id":1478,"name":"Codeforces Round 698 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1611844500,"relativeTimeSeconds":147870703},{"id":1475,"name":"Codeforces Round 697 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1611586800,"relativeTimeSeconds":148128403},{"id":1474,"name":"Codeforces Round 696 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1611066900,"relativeTimeSeconds":148648303},{"id":1473,"name":"Educational Codeforces Round 102 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1610634900,"relativeTimeSeconds":149080303},{"id":1467,"name":"Codeforces Round 695 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1610116500,"relativeTimeSeconds":149598703},{"id":1470,"name":"Codeforces Round 694 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1609857300,"relativeTimeSeconds":149857903},{"id":1471,"name":"Codeforces Round 694 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1609857300,"relativeTimeSeconds":149857903},{"id":1472,"name":"Codeforces Round 693 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1609770900,"relativeTimeSeconds":149944303},{"id":1466,"name":"Good Bye 2020","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1609338900,"relativeTimeSeconds":150376303},{"id":1469,"name":"Educational Codeforces Round 101 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1609166100,"relativeTimeSeconds":150549103},{"id":1468,"name":"2020-2021 ICPC, NERC, Southern and Volga Russian Regional Contest (Online Mirror, ICPC Rules)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1608896100,"relativeTimeSeconds":150819103},{"id":1464,"name":"Codeforces Round 692 (Div. 1, based on Technocup 2021 Elimination Round 3)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1608476700,"relativeTimeSeconds":151238503},{"id":1465,"name":"Codeforces Round 692 (Div. 2, based on Technocup 2021 Elimination Round 3)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1608476700,"relativeTimeSeconds":151238503},{"id":1411,"name":"Technocup 2021 - Elimination Round 3","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1608476700,"relativeTimeSeconds":151238503},{"id":1458,"name":"Codeforces Round 691 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1608370500,"relativeTimeSeconds":151344703},{"id":1459,"name":"Codeforces Round 691 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1608370500,"relativeTimeSeconds":151344703},{"id":1410,"name":"Технокубок 2021 - Ознакомительный Раунд 3","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":172800,"startTimeSeconds":1608300300,"relativeTimeSeconds":151414903},{"id":1463,"name":"Educational Codeforces Round 100 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1608215700,"relativeTimeSeconds":151499503},{"id":1462,"name":"Codeforces Round 690 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1608042900,"relativeTimeSeconds":151672303},{"id":1460,"name":"NERC Challenge 2020: Marathon","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":691200,"startTimeSeconds":1607763600,"relativeTimeSeconds":151951603},{"id":1461,"name":"Codeforces Round 689 (Div. 2, based on Zed Code Competition)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1607697300,"relativeTimeSeconds":152017903},{"id":1450,"name":"Codeforces Global Round 12","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1607265300,"relativeTimeSeconds":152449903},{"id":1453,"name":"Codeforces Round 688 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1607087100,"relativeTimeSeconds":152628103},{"id":1455,"name":"Educational Codeforces Round 99 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1606746900,"relativeTimeSeconds":152968303},{"id":1456,"name":"Codeforces Round 687 (Div. 1, based on Technocup 2021 Elimination Round 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1606633500,"relativeTimeSeconds":153081703},{"id":1457,"name":"Codeforces Round 687 (Div. 2, based on Technocup 2021 Elimination Round 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1606633500,"relativeTimeSeconds":153081703},{"id":1415,"name":"Technocup 2021 - Elimination Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1606633500,"relativeTimeSeconds":153081703},{"id":1414,"name":"Технокубок 2021 - Ознакомительный Раунд 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":172800,"startTimeSeconds":1606457100,"relativeTimeSeconds":153258103},{"id":1454,"name":"Codeforces Round 686 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1606228500,"relativeTimeSeconds":153486703},{"id":1451,"name":"Codeforces Round 685 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1605969300,"relativeTimeSeconds":153745903},{"id":1452,"name":"Educational Codeforces Round 98 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1605796500,"relativeTimeSeconds":153918703},{"id":1439,"name":"Codeforces Round 684 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1605623700,"relativeTimeSeconds":154091503},{"id":1440,"name":"Codeforces Round 684 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1605623700,"relativeTimeSeconds":154091503},{"id":1446,"name":"Codeforces Round 683 (Div. 1, by Meet IT)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1605450900,"relativeTimeSeconds":154264303},{"id":1447,"name":"Codeforces Round 683 (Div. 2, by Meet IT)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1605450900,"relativeTimeSeconds":154264303},{"id":1438,"name":"Codeforces Round 682 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1605278100,"relativeTimeSeconds":154437103},{"id":1431,"name":"Kotlin Heroes 5: ICPC Round","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1605191700,"relativeTimeSeconds":154523503},{"id":1432,"name":"Kotlin Heroes 5: ICPC Round (Practice)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":604800,"startTimeSeconds":1604583300,"relativeTimeSeconds":155131903},{"id":1442,"name":"Codeforces Round 681 (Div. 1, based on VK Cup 2019-2020 - Final)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1604327700,"relativeTimeSeconds":155387503},{"id":1443,"name":"Codeforces Round 681 (Div. 2, based on VK Cup 2019-2020 - Final)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1604327700,"relativeTimeSeconds":155387503},{"id":1441,"name":"VK Cup 2019-2020 - Final Round (Engine)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1604239500,"relativeTimeSeconds":155475703},{"id":1444,"name":"Codeforces Round 680 (Div. 1, based on Moscow Team Olympiad)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1604228700,"relativeTimeSeconds":155486503},{"id":1445,"name":"Codeforces Round 680 (Div. 2, based on Moscow Team Olympiad)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1604228700,"relativeTimeSeconds":155486503},{"id":1437,"name":"Educational Codeforces Round 97 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1603809300,"relativeTimeSeconds":155905903},{"id":1434,"name":"Codeforces Round 679 (Div. 1, based on Technocup 2021 Elimination Round 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1603623900,"relativeTimeSeconds":156091303},{"id":1435,"name":"Codeforces Round 679 (Div. 2, based on Technocup 2021 Elimination Round 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1603623900,"relativeTimeSeconds":156091303},{"id":1413,"name":"Technocup 2021 - Elimination Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1603623900,"relativeTimeSeconds":156091303},{"id":1436,"name":"Codeforces Round 678 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1603548300,"relativeTimeSeconds":156166903},{"id":1412,"name":"Технокубок 2021 - Ознакомительный Раунд 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":172800,"startTimeSeconds":1603447500,"relativeTimeSeconds":156267703},{"id":1433,"name":"Codeforces Round 677 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1603204500,"relativeTimeSeconds":156510703},{"id":1421,"name":"Codeforces Round 676 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1603011900,"relativeTimeSeconds":156703303},{"id":1428,"name":"Codeforces Raif Round 1 (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1602939900,"relativeTimeSeconds":156775303},{"id":1430,"name":"Educational Codeforces Round 96 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1602407100,"relativeTimeSeconds":157308103},{"id":1427,"name":"Codeforces Global Round 11","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1602341400,"relativeTimeSeconds":157373803},{"id":1423,"name":"Bubble Cup 13 - Finals [Online Mirror, unrated, Div. 1]","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1601903100,"relativeTimeSeconds":157812103},{"id":1424,"name":"Bubble Cup 13 - Finals [Online Mirror, unrated, Div. 2]","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1601903100,"relativeTimeSeconds":157812103},{"id":1422,"name":"Codeforces Round 675 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1601827500,"relativeTimeSeconds":157887703},{"id":1408,"name":"Grakn Forces 2020","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9900,"startTimeSeconds":1601476500,"relativeTimeSeconds":158238703},{"id":1426,"name":"Codeforces Round 674 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1601280300,"relativeTimeSeconds":158434903},{"id":1416,"name":"Codeforces Round 673 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1601219100,"relativeTimeSeconds":158496103},{"id":1417,"name":"Codeforces Round 673 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1601219100,"relativeTimeSeconds":158496103},{"id":1425,"name":"2020 ICPC, COMPFEST 12, Indonesia Multi-Provincial Contest (Unrated, Online Mirror, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1601182800,"relativeTimeSeconds":158532403},{"id":1420,"name":"Codeforces Round 672 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1600958100,"relativeTimeSeconds":158757103},{"id":1419,"name":"Codeforces Round 671 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1600526100,"relativeTimeSeconds":159189103},{"id":1418,"name":"Educational Codeforces Round 95 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1600094100,"relativeTimeSeconds":159621103},{"id":1406,"name":"Codeforces Round 670 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1599918300,"relativeTimeSeconds":159796903},{"id":1407,"name":"Codeforces Round 669 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1599575700,"relativeTimeSeconds":160139503},{"id":1404,"name":"Codeforces Round 668 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1599402900,"relativeTimeSeconds":160312303},{"id":1405,"name":"Codeforces Round 668 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1599402900,"relativeTimeSeconds":160312303},{"id":1409,"name":"Codeforces Round 667 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1599230100,"relativeTimeSeconds":160485103},{"id":1396,"name":"Codeforces Round 666 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1598798100,"relativeTimeSeconds":160917103},{"id":1397,"name":"Codeforces Round 666 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1598798100,"relativeTimeSeconds":160917103},{"id":1403,"name":"Central-European Olympiad in Informatics, CEOI 2020, Day 2 (IOI, Unofficial Mirror Contest, Unrated)","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":18600,"startTimeSeconds":1598616300,"relativeTimeSeconds":161098903},{"id":1402,"name":"Central-European Olympiad in Informatics, CEOI 2020, Day 1 (IOI, Unofficial Mirror Contest, Unrated)","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1598443500,"relativeTimeSeconds":161271703},{"id":1400,"name":"Educational Codeforces Round 94 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1598366100,"relativeTimeSeconds":161349103},{"id":1401,"name":"Codeforces Round 665 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1598020500,"relativeTimeSeconds":161694703},{"id":1392,"name":"Codeforces Global Round 10","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1597588500,"relativeTimeSeconds":162126701},{"id":1398,"name":"Educational Codeforces Round 93 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1597415700,"relativeTimeSeconds":162299503},{"id":1394,"name":"Codeforces Round 664 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1597242900,"relativeTimeSeconds":162472303},{"id":1395,"name":"Codeforces Round 664 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1597242900,"relativeTimeSeconds":162472303},{"id":1391,"name":"Codeforces Round 663 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1596983700,"relativeTimeSeconds":162731503},{"id":1393,"name":"Codeforces Round 662 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1596810900,"relativeTimeSeconds":162904303},{"id":1399,"name":"Codeforces Round 661 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1596638100,"relativeTimeSeconds":163077103},{"id":1388,"name":"Codeforces Round 660 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1596119700,"relativeTimeSeconds":163595503},{"id":1389,"name":"Educational Codeforces Round 92 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1596033300,"relativeTimeSeconds":163681903},{"id":1383,"name":"Codeforces Round 659 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1595601300,"relativeTimeSeconds":164113903},{"id":1384,"name":"Codeforces Round 659 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1595601300,"relativeTimeSeconds":164113903},{"id":1387,"name":"Baltic Olympiad in Informatics 2020, Day 2 (IOI, Unofficial Mirror Contest, Unrated)","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":19800,"startTimeSeconds":1595502300,"relativeTimeSeconds":164212903},{"id":1386,"name":"Baltic Olympiad in Informatics 2020, Day 1 (IOI, Unofficial Mirror Contest, Unrated)","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1595415900,"relativeTimeSeconds":164299303},{"id":1381,"name":"Codeforces Round 658 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1595342100,"relativeTimeSeconds":164373101},{"id":1382,"name":"Codeforces Round 658 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1595342100,"relativeTimeSeconds":164373103},{"id":1379,"name":"Codeforces Round 657 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1595149200,"relativeTimeSeconds":164566003},{"id":1385,"name":"Codeforces Round 656 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1594996500,"relativeTimeSeconds":164718703},{"id":1380,"name":"Educational Codeforces Round 91 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1594565100,"relativeTimeSeconds":165150103},{"id":1372,"name":"Codeforces Round 655 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1594479900,"relativeTimeSeconds":165235303},{"id":1375,"name":"Codeforces Global Round 9","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1593873900,"relativeTimeSeconds":165841303},{"id":1371,"name":"Codeforces Round 654 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1593610500,"relativeTimeSeconds":166104703},{"id":1374,"name":"Codeforces Round 653 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1593354900,"relativeTimeSeconds":166360303},{"id":1378,"name":"ICPC Challenge 2020: Marathon","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":604800,"startTimeSeconds":1593271800,"relativeTimeSeconds":166443403},{"id":1377,"name":"ICPC Challenge 2020","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1593255600,"relativeTimeSeconds":166459603},{"id":1373,"name":"Educational Codeforces Round 90 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1593095700,"relativeTimeSeconds":166619503},{"id":1376,"name":"ICPC Challenge 2020: Practice","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":171000,"startTimeSeconds":1593082800,"relativeTimeSeconds":166632403},{"id":1369,"name":"Codeforces Round 652 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1592921100,"relativeTimeSeconds":166794103},{"id":1370,"name":"Codeforces Round 651 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1592663700,"relativeTimeSeconds":167051503},{"id":1357,"name":"Microsoft Q# Coding Contest - Summer 2020","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":259200,"startTimeSeconds":1592582400,"relativeTimeSeconds":167132803},{"id":1368,"name":"Codeforces Global Round 8","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1592491500,"relativeTimeSeconds":167223703},{"id":1367,"name":"Codeforces Round 650 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1592318100,"relativeTimeSeconds":167397103},{"id":1364,"name":"Codeforces Round 649 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1592060700,"relativeTimeSeconds":167654503},{"id":1356,"name":"Microsoft Q# Coding Contest - Summer 2020 - Warmup","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":259200,"startTimeSeconds":1591977600,"relativeTimeSeconds":167737603},{"id":1366,"name":"Educational Codeforces Round 89 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1591886100,"relativeTimeSeconds":167829103},{"id":1365,"name":"Codeforces Round 648 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1591540500,"relativeTimeSeconds":168174703},{"id":1361,"name":"Codeforces Round 647 (Div. 1) - Thanks, Algo Muse!","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1591281300,"relativeTimeSeconds":168433903},{"id":1362,"name":"Codeforces Round 647 (Div. 2) - Thanks, Algo Muse!","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1591281300,"relativeTimeSeconds":168433903},{"id":1363,"name":"Codeforces Round 646 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1590935700,"relativeTimeSeconds":168779503},{"id":1346,"name":"Kotlin Heroes: Episode 4","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1590762900,"relativeTimeSeconds":168952303},{"id":1359,"name":"Educational Codeforces Round 88 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1590676500,"relativeTimeSeconds":169038703},{"id":1358,"name":"Codeforces Round 645 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1590503700,"relativeTimeSeconds":169211503},{"id":1360,"name":"Codeforces Round 644 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1590327300,"relativeTimeSeconds":169387903},{"id":1347,"name":"Kotlin Heroes: Practice 4","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":604800,"startTimeSeconds":1590154500,"relativeTimeSeconds":169560703},{"id":1354,"name":"Educational Codeforces Round 87 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1589707200,"relativeTimeSeconds":170008003},{"id":1355,"name":"Codeforces Round 643 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1589628900,"relativeTimeSeconds":170086303},{"id":1353,"name":"Codeforces Round 642 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1589466900,"relativeTimeSeconds":170248303},{"id":1349,"name":"Codeforces Round 641 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1589286900,"relativeTimeSeconds":170428301},{"id":1350,"name":"Codeforces Round 641 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1589286900,"relativeTimeSeconds":170428303},{"id":1352,"name":"Codeforces Round 640 (Div. 4)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1589034900,"relativeTimeSeconds":170680303},{"id":1351,"name":"Testing Round 16 (Unrated)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":3600,"startTimeSeconds":1588860300,"relativeTimeSeconds":170854903},{"id":1344,"name":"Codeforces Round 639 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1588775700,"relativeTimeSeconds":170939503},{"id":1345,"name":"Codeforces Round 639 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1588775700,"relativeTimeSeconds":170939503},{"id":1348,"name":"Codeforces Round 638 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1588343700,"relativeTimeSeconds":171371503},{"id":1342,"name":"Educational Codeforces Round 86 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1587911700,"relativeTimeSeconds":171803503},{"id":1340,"name":"Codeforces Round 637 (Div. 1) - Thanks, Ivan Belonogov!","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1587653100,"relativeTimeSeconds":172062103},{"id":1341,"name":"Codeforces Round 637 (Div. 2) - Thanks, Ivan Belonogov!","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1587653100,"relativeTimeSeconds":172062103},{"id":1343,"name":"Codeforces Round 636 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1587479700,"relativeTimeSeconds":172235503},{"id":1336,"name":"Codeforces Round 635 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1586961300,"relativeTimeSeconds":172753903},{"id":1337,"name":"Codeforces Round 635 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1586961300,"relativeTimeSeconds":172753903},{"id":1335,"name":"Codeforces Round 634 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1586788500,"relativeTimeSeconds":172926703},{"id":1338,"name":"Codeforces Round 633 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1586700300,"relativeTimeSeconds":173014903},{"id":1339,"name":"Codeforces Round 633 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1586700300,"relativeTimeSeconds":173014903},{"id":1334,"name":"Educational Codeforces Round 85 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1586529300,"relativeTimeSeconds":173185903},{"id":1333,"name":"Codeforces Round 632 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1586356500,"relativeTimeSeconds":173358703},{"id":1329,"name":"Codeforces Round 631 (Div. 1) - Thanks, Denis aramis Shitov!","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1585924500,"relativeTimeSeconds":173790703},{"id":1330,"name":"Codeforces Round 631 (Div. 2) - Thanks, Denis aramis Shitov!","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1585924500,"relativeTimeSeconds":173790703},{"id":1331,"name":"April Fools Day Contest 2020","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1585751700,"relativeTimeSeconds":173963503},{"id":1332,"name":"Codeforces Round 630 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1585661700,"relativeTimeSeconds":174053503},{"id":1328,"name":"Codeforces Round 629 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1585233300,"relativeTimeSeconds":174481903},{"id":1327,"name":"Educational Codeforces Round 84 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1584974100,"relativeTimeSeconds":174741103},{"id":1326,"name":"Codeforces Global Round 7","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1584628500,"relativeTimeSeconds":175086703},{"id":1325,"name":"Codeforces Round 628 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1584196500,"relativeTimeSeconds":175518703},{"id":1324,"name":"Codeforces Round 627 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1584018300,"relativeTimeSeconds":175696901},{"id":1312,"name":"Educational Codeforces Round 83 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1583764500,"relativeTimeSeconds":175950703},{"id":1322,"name":"Codeforces Round 626 (Div. 1, based on Moscow Open Olympiad in Informatics)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1583573700,"relativeTimeSeconds":176141503},{"id":1323,"name":"Codeforces Round 626 (Div. 2, based on Moscow Open Olympiad in Informatics)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1583573700,"relativeTimeSeconds":176141503},{"id":1316,"name":"CodeCraft-20 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1583332500,"relativeTimeSeconds":176382703},{"id":1305,"name":"Ozon Tech Challenge 2020 (Div.1 + Div.2, Rated, T-shirts + prizes!)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1583246100,"relativeTimeSeconds":176469103},{"id":1320,"name":"Codeforces Round 625 (Div. 1, based on Technocup 2020 Final Round)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1583068500,"relativeTimeSeconds":176646703},{"id":1321,"name":"Codeforces Round 625 (Div. 2, based on Technocup 2020 Final Round)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1583068500,"relativeTimeSeconds":176646703},{"id":1319,"name":"Технокубок 2020 - Финал","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1583057400,"relativeTimeSeconds":176657803},{"id":1297,"name":"Kotlin Heroes: Episode 3","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1582810500,"relativeTimeSeconds":176904703},{"id":1311,"name":"Codeforces Round 624 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1582554900,"relativeTimeSeconds":177160303},{"id":1314,"name":"Codeforces Round 623 (Div. 1, based on VK Cup 2019-2020 - Elimination Round, Engine)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1582473900,"relativeTimeSeconds":177241303},{"id":1315,"name":"Codeforces Round 623 (Div. 2, based on VK Cup 2019-2020 - Elimination Round, Engine)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1582473900,"relativeTimeSeconds":177241303},{"id":1310,"name":"VK Cup 2019-2020 - Elimination Round (Engine)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1582473900,"relativeTimeSeconds":177241303},{"id":1313,"name":"Codeforces Round 622 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1582448700,"relativeTimeSeconds":177266503},{"id":1298,"name":"Kotlin Heroes: Practice 3","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":607500,"startTimeSeconds":1582202100,"relativeTimeSeconds":177513103},{"id":1307,"name":"Codeforces Round 621 (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1581953700,"relativeTimeSeconds":177761503},{"id":1304,"name":"Codeforces Round 620 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1581771900,"relativeTimeSeconds":177943303},{"id":1308,"name":"VK Cup 2019-2020 - Отборочный раунд (Design)","type":"IOI","phase":"PENDING_SYSTEM_TEST","frozen":false,"durationSeconds":799200,"startTimeSeconds":1581692400,"relativeTimeSeconds":178022803},{"id":1309,"name":"VK Cup 2019-2020 - Отборочный раунд (Mobile)","type":"IOI","phase":"PENDING_SYSTEM_TEST","frozen":false,"durationSeconds":1404000,"startTimeSeconds":1581692400,"relativeTimeSeconds":178022803},{"id":1301,"name":"Codeforces Round 619 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1581604500,"relativeTimeSeconds":178110703},{"id":1303,"name":"Educational Codeforces Round 82 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1581518100,"relativeTimeSeconds":178197103},{"id":1299,"name":"Codeforces Round 618 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1581257100,"relativeTimeSeconds":178458103},{"id":1300,"name":"Codeforces Round 618 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1581257100,"relativeTimeSeconds":178458103},{"id":1296,"name":"Codeforces Round 617 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1580826900,"relativeTimeSeconds":178888301},{"id":1302,"name":"AIM Tech Poorly Prepared Contest (unrated, funny, Div. 1 preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1580746500,"relativeTimeSeconds":178968703},{"id":1290,"name":"Codeforces Round 616 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1580652300,"relativeTimeSeconds":179062903},{"id":1291,"name":"Codeforces Round 616 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1580652300,"relativeTimeSeconds":179062903},{"id":1295,"name":"Educational Codeforces Round 81 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1580308500,"relativeTimeSeconds":179406703},{"id":1294,"name":"Codeforces Round 615 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1579703700,"relativeTimeSeconds":180011503},{"id":1292,"name":"Codeforces Round 614 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1579440900,"relativeTimeSeconds":180274303},{"id":1293,"name":"Codeforces Round 614 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1579440900,"relativeTimeSeconds":180274303},{"id":1288,"name":"Educational Codeforces Round 80 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1579012500,"relativeTimeSeconds":180702703},{"id":1285,"name":"Codeforces Round 613 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1578665100,"relativeTimeSeconds":181050103},{"id":1286,"name":"Codeforces Round 612 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1578233100,"relativeTimeSeconds":181482103},{"id":1287,"name":"Codeforces Round 612 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1578233100,"relativeTimeSeconds":181482103},{"id":1284,"name":"Hello 2020","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1578139500,"relativeTimeSeconds":181575703},{"id":1270,"name":"Good Bye 2019","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1577628300,"relativeTimeSeconds":182086903},{"id":1283,"name":"Codeforces Round 611 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1577552700,"relativeTimeSeconds":182162503},{"id":1279,"name":"Educational Codeforces Round 79 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1577457600,"relativeTimeSeconds":182257603},{"id":1282,"name":"Codeforces Round 610 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1577198100,"relativeTimeSeconds":182517103},{"id":1268,"name":"Codeforces Round 609 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1576926300,"relativeTimeSeconds":182788903},{"id":1269,"name":"Codeforces Round 609 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1576926300,"relativeTimeSeconds":182788903},{"id":1278,"name":"Educational Codeforces Round 78 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1576766100,"relativeTimeSeconds":182949103},{"id":1266,"name":"Codeforces Global Round 6","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1576595100,"relativeTimeSeconds":183120103},{"id":1271,"name":"Codeforces Round 608 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1576401300,"relativeTimeSeconds":183313903},{"id":1280,"name":"Codeforces Round 607 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1576386300,"relativeTimeSeconds":183328903},{"id":1281,"name":"Codeforces Round 607 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1576386300,"relativeTimeSeconds":183328903},{"id":1276,"name":"Codeforces Round 606 (Div. 1, based on Technocup 2020 Elimination Round 4)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1576321500,"relativeTimeSeconds":183393703},{"id":1277,"name":"Codeforces Round 606 (Div. 2, based on Technocup 2020 Elimination Round 4)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1576321500,"relativeTimeSeconds":183393703},{"id":1259,"name":"Technocup 2020 - Elimination Round 4","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1576321500,"relativeTimeSeconds":183393703},{"id":1272,"name":"Codeforces Round 605 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1576157700,"relativeTimeSeconds":183557503},{"id":1258,"name":"Технокубок 2020 - Ознакомительный Раунд 4","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":172800,"startTimeSeconds":1576145100,"relativeTimeSeconds":183570103},{"id":1273,"name":"VK Cup 2019 - Квалификация (Design)","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":950400,"startTimeSeconds":1575580200,"relativeTimeSeconds":184135003},{"id":1275,"name":"VK Cup 2019 - Квалификация (Engine)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":950400,"startTimeSeconds":1575580200,"relativeTimeSeconds":184135003},{"id":1274,"name":"VK Cup 2019 - Квалификация (Mobile)","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":950400,"startTimeSeconds":1575580200,"relativeTimeSeconds":184135003},{"id":1264,"name":"Codeforces Round 604 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1575556500,"relativeTimeSeconds":184158703},{"id":1265,"name":"Codeforces Round 604 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1575556500,"relativeTimeSeconds":184158703},{"id":1267,"name":"2019-2020 ICPC, NERC, Northern Eurasia Finals (Unrated, Online Mirror, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1575183600,"relativeTimeSeconds":184531603},{"id":1263,"name":"Codeforces Round 603 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1575038100,"relativeTimeSeconds":184677103},{"id":1260,"name":"Educational Codeforces Round 77 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1574862600,"relativeTimeSeconds":184852603},{"id":1261,"name":"Codeforces Round 602 (Div. 1, based on Technocup 2020 Elimination Round 3)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1574582700,"relativeTimeSeconds":185132503},{"id":1262,"name":"Codeforces Round 602 (Div. 2, based on Technocup 2020 Elimination Round 3)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1574582700,"relativeTimeSeconds":185132503},{"id":1227,"name":"Technocup 2020 - Elimination Round 3","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1574582700,"relativeTimeSeconds":185132503},{"id":1226,"name":"Технокубок 2020 - Ознакомительный Раунд 3","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":172800,"startTimeSeconds":1574406300,"relativeTimeSeconds":185308903},{"id":1254,"name":"Codeforces Round 601 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1574174100,"relativeTimeSeconds":185541101},{"id":1255,"name":"Codeforces Round 601 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1574174100,"relativeTimeSeconds":185541103},{"id":1253,"name":"Codeforces Round 600 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1573914900,"relativeTimeSeconds":185800303},{"id":1257,"name":"Educational Codeforces Round 76 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1573655700,"relativeTimeSeconds":186059503},{"id":1242,"name":"Codeforces Round 599 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1573052700,"relativeTimeSeconds":186662503},{"id":1243,"name":"Codeforces Round 599 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1573052700,"relativeTimeSeconds":186662503},{"id":1256,"name":"Codeforces Round 598 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1572873300,"relativeTimeSeconds":186841903},{"id":1245,"name":"Codeforces Round 597 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1572618900,"relativeTimeSeconds":187096303},{"id":1250,"name":"2019-2020 ICPC, NERC, Southern and Volga Russian Regional Contest (Online Mirror, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1572168900,"relativeTimeSeconds":187546303},{"id":1252,"name":"2019-2020 ICPC, Asia Jakarta Regional Contest (Online Mirror, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1572147000,"relativeTimeSeconds":187568203},{"id":1246,"name":"Codeforces Round 596 (Div. 1, based on Technocup 2020 Elimination Round 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1572087900,"relativeTimeSeconds":187627303},{"id":1247,"name":"Codeforces Round 596 (Div. 2, based on Technocup 2020 Elimination Round 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1572087900,"relativeTimeSeconds":187627303},{"id":1225,"name":"Technocup 2020 - Elimination Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1572087900,"relativeTimeSeconds":187627303},{"id":1251,"name":"Educational Codeforces Round 75 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1571929500,"relativeTimeSeconds":187785703},{"id":1224,"name":"Технокубок 2020 - Ознакомительный Раунд 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":172800,"startTimeSeconds":1571911500,"relativeTimeSeconds":187803703},{"id":1249,"name":"Codeforces Round 595 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1571754900,"relativeTimeSeconds":187960303},{"id":1239,"name":"Codeforces Round 594 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1571562300,"relativeTimeSeconds":188152903},{"id":1248,"name":"Codeforces Round 594 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1571562300,"relativeTimeSeconds":188152903},{"id":1236,"name":"Codeforces Round 593 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1571319300,"relativeTimeSeconds":188395903},{"id":1237,"name":"Codeforces Global Round 5","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1571236500,"relativeTimeSeconds":188478703},{"id":1244,"name":"Codeforces Round 592 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1570957500,"relativeTimeSeconds":188757703},{"id":1238,"name":"Educational Codeforces Round 74 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8400,"startTimeSeconds":1570545300,"relativeTimeSeconds":189169903},{"id":1240,"name":"Codeforces Round 591 (Div. 1, based on Technocup 2020 Elimination Round 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1570374300,"relativeTimeSeconds":189340903},{"id":1241,"name":"Codeforces Round 591 (Div. 2, based on Technocup 2020 Elimination Round 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1570374300,"relativeTimeSeconds":189340903},{"id":1223,"name":"Technocup 2020 - Elimination Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1570374300,"relativeTimeSeconds":189340903},{"id":1222,"name":"Технокубок 2020 - Ознакомительный Раунд 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":172800,"startTimeSeconds":1570197900,"relativeTimeSeconds":189517303},{"id":1234,"name":"Codeforces Round 590 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1569940500,"relativeTimeSeconds":189774703},{"id":1235,"name":"Huawei Honorcup Marathon 2","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":1209600,"startTimeSeconds":1569866400,"relativeTimeSeconds":189848803},{"id":1228,"name":"Codeforces Round 589 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1569762300,"relativeTimeSeconds":189952903},{"id":1229,"name":"Codeforces Round 588 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1569247500,"relativeTimeSeconds":190467703},{"id":1230,"name":"Codeforces Round 588 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1569247500,"relativeTimeSeconds":190467703},{"id":1231,"name":"Dasha Code Championship - Novosibirsk Finals Round (only for onsite-finalists)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1569143100,"relativeTimeSeconds":190572103},{"id":1210,"name":"Dasha Code Championship - SPb Finals Round (only for onsite-finalists)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1569143100,"relativeTimeSeconds":190572103},{"id":1216,"name":"Codeforces Round 587 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1569049500,"relativeTimeSeconds":190665701},{"id":1221,"name":"Educational Codeforces Round 73 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1568903700,"relativeTimeSeconds":190811503},{"id":1220,"name":"Codeforces Round 586 (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1568822700,"relativeTimeSeconds":190892503},{"id":1218,"name":"Bubble Cup 12 - Finals [Online Mirror, unrated, Div. 1]","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1568554500,"relativeTimeSeconds":191160703},{"id":1219,"name":"Bubble Cup 12 - Finals [Online Mirror, unrated, Div. 2]","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1568554500,"relativeTimeSeconds":191160703},{"id":1215,"name":"Codeforces Round 585 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1568543700,"relativeTimeSeconds":191171503},{"id":1209,"name":"Codeforces Round 584 - Dasha Code Championship - Elimination Round (rated, open for everyone, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1568466300,"relativeTimeSeconds":191248901},{"id":1211,"name":"Kotlin Heroes: Episode 2","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1567866900,"relativeTimeSeconds":191848303},{"id":1217,"name":"Educational Codeforces Round 72 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1567694100,"relativeTimeSeconds":192021103},{"id":1214,"name":"Codeforces Round 583 (Div. 1 + Div. 2, based on Olympiad of Metropolises)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1567587900,"relativeTimeSeconds":192127303},{"id":1212,"name":"Kotlin Heroes: Practice 2","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":604800,"startTimeSeconds":1567258500,"relativeTimeSeconds":192456703},{"id":1213,"name":"Codeforces Round 582 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1567175700,"relativeTimeSeconds":192539501},{"id":1208,"name":"Manthan, Codefest 19 (open for everyone, rated, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7500,"startTimeSeconds":1566743700,"relativeTimeSeconds":192971503},{"id":1207,"name":"Educational Codeforces Round 71 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1566484500,"relativeTimeSeconds":193230703},{"id":1204,"name":"Codeforces Round 581 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1566311700,"relativeTimeSeconds":193403503},{"id":1205,"name":"Codeforces Round 580 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1566135900,"relativeTimeSeconds":193579303},{"id":1206,"name":"Codeforces Round 580 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1566135900,"relativeTimeSeconds":193579303},{"id":1203,"name":"Codeforces Round 579 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8400,"startTimeSeconds":1565706900,"relativeTimeSeconds":194008303},{"id":1200,"name":"Codeforces Round 578 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1565526900,"relativeTimeSeconds":194188303},{"id":1202,"name":"Educational Codeforces Round 70 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1565188500,"relativeTimeSeconds":194526703},{"id":1201,"name":"Codeforces Round 577 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1564936500,"relativeTimeSeconds":194778703},{"id":1198,"name":"Codeforces Round 576 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1564497300,"relativeTimeSeconds":195217903},{"id":1199,"name":"Codeforces Round 576 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1564497300,"relativeTimeSeconds":195217903},{"id":1193,"name":"CEOI 2019 day 2 online mirror (unrated, IOI format)","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1564301100,"relativeTimeSeconds":195414103},{"id":1192,"name":"CEOI 2019 day 1 online mirror (unrated, IOI format)","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1564063500,"relativeTimeSeconds":195651703},{"id":1196,"name":"Codeforces Round 575 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1563978900,"relativeTimeSeconds":195736303},{"id":1197,"name":"Educational Codeforces Round 69 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1563806100,"relativeTimeSeconds":195909103},{"id":1178,"name":"Codeforces Global Round 4","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1563636900,"relativeTimeSeconds":196078303},{"id":1195,"name":"Codeforces Round 574 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1563374100,"relativeTimeSeconds":196341103},{"id":1194,"name":"Educational Codeforces Round 68 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1563115500,"relativeTimeSeconds":196599703},{"id":1190,"name":"Codeforces Round 573 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1562942100,"relativeTimeSeconds":196773103},{"id":1191,"name":"Codeforces Round 573 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1562942100,"relativeTimeSeconds":196773103},{"id":1184,"name":"Helvetic Coding Contest 2019 online mirror (teams allowed, unrated)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":16200,"freezeDurationSeconds":3600,"startTimeSeconds":1562483100,"relativeTimeSeconds":197232101},{"id":1188,"name":"Codeforces Round 572 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1562339100,"relativeTimeSeconds":197376103},{"id":1189,"name":"Codeforces Round 572 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1562339100,"relativeTimeSeconds":197376103},{"id":1187,"name":"Educational Codeforces Round 67 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1561905900,"relativeTimeSeconds":197809303},{"id":1186,"name":"Codeforces Round 571 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1561710000,"relativeTimeSeconds":198005203},{"id":1183,"name":"Codeforces Round 570 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1561559700,"relativeTimeSeconds":198155503},{"id":1179,"name":"Codeforces Round 569 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1561136700,"relativeTimeSeconds":198578503},{"id":1180,"name":"Codeforces Round 569 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1561136700,"relativeTimeSeconds":198578503},{"id":1185,"name":"Codeforces Round 568 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1560955500,"relativeTimeSeconds":198759703},{"id":1181,"name":"Codeforces Round 567 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1560677700,"relativeTimeSeconds":199037503},{"id":1182,"name":"Codeforces Round 566 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1560258300,"relativeTimeSeconds":199456903},{"id":1176,"name":"Codeforces Round 565 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1560090900,"relativeTimeSeconds":199624303},{"id":1172,"name":"Codeforces Round 564 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1559909100,"relativeTimeSeconds":199806103},{"id":1173,"name":"Codeforces Round 564 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1559909100,"relativeTimeSeconds":199806103},{"id":1175,"name":"Educational Codeforces Round 66 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1559745300,"relativeTimeSeconds":199969903},{"id":1174,"name":"Codeforces Round 563 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1559570700,"relativeTimeSeconds":200144503},{"id":1148,"name":"Codeforces Global Round 3","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1559399700,"relativeTimeSeconds":200315503},{"id":1177,"name":"Testing Round 15 (Unrated)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":2700,"startTimeSeconds":1559375100,"relativeTimeSeconds":200340103},{"id":1170,"name":"Kotlin Heroes: Episode 1","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1559054100,"relativeTimeSeconds":200661103},{"id":1168,"name":"Codeforces Round 562 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1558884900,"relativeTimeSeconds":200830303},{"id":1169,"name":"Codeforces Round 562 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1558884900,"relativeTimeSeconds":200830303},{"id":1171,"name":"Kotlin Heroes: Practice 1","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":518400,"startTimeSeconds":1558535700,"relativeTimeSeconds":201179503},{"id":1166,"name":"Codeforces Round 561 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1558105500,"relativeTimeSeconds":201609703},{"id":1167,"name":"Educational Codeforces Round 65 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1557930900,"relativeTimeSeconds":201784303},{"id":1165,"name":"Codeforces Round 560 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1557844500,"relativeTimeSeconds":201870703},{"id":1158,"name":"Codeforces Round 559 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1557671700,"relativeTimeSeconds":202043503},{"id":1159,"name":"Codeforces Round 559 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1557671700,"relativeTimeSeconds":202043503},{"id":1163,"name":"Codeforces Round 558 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1557414300,"relativeTimeSeconds":202300903},{"id":1164,"name":"Mathforces: Tech Scouts Online Test 2018 (just fun and practice, unofficial, unrated)","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1557043500,"relativeTimeSeconds":202671703},{"id":1161,"name":"Codeforces Round 557 (Div. 1) [based on Forethought Future Cup - Final Round]","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1556989500,"relativeTimeSeconds":202725703},{"id":1162,"name":"Codeforces Round 557 (Div. 2) [based on Forethought Future Cup - Final Round]","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1556989500,"relativeTimeSeconds":202725703},{"id":1147,"name":"Forethought Future Cup - Final Round (Onsite Finalists Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1556989500,"relativeTimeSeconds":202725703},{"id":1156,"name":"Educational Codeforces Round 64 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1556721300,"relativeTimeSeconds":202993903},{"id":1160,"name":"VRt Contest 2019 (marathon)","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":1209600,"startTimeSeconds":1556614800,"relativeTimeSeconds":203100403},{"id":1149,"name":"Codeforces Round 556 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1556548500,"relativeTimeSeconds":203166703},{"id":1150,"name":"Codeforces Round 556 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1556548500,"relativeTimeSeconds":203166703},{"id":1157,"name":"Codeforces Round 555 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1556289300,"relativeTimeSeconds":203425903},{"id":1152,"name":"Codeforces Round 554 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1556116500,"relativeTimeSeconds":203598703},{"id":1155,"name":"Educational Codeforces Round 63 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1555943700,"relativeTimeSeconds":203771503},{"id":1146,"name":"Forethought Future Cup - Elimination Round","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1555783500,"relativeTimeSeconds":203931703},{"id":1151,"name":"Codeforces Round 553 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1555601700,"relativeTimeSeconds":204113503},{"id":1154,"name":"Codeforces Round 552 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1555425300,"relativeTimeSeconds":204289903},{"id":1153,"name":"Codeforces Round 551 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1555164300,"relativeTimeSeconds":204550903},{"id":1119,"name":"Codeforces Global Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1554550500,"relativeTimeSeconds":205164703},{"id":1145,"name":"April Fools Day Contest 2019","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1554131100,"relativeTimeSeconds":205584103},{"id":1144,"name":"Codeforces Round 550 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1554041100,"relativeTimeSeconds":205674103},{"id":1142,"name":"Codeforces Round 549 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1553965800,"relativeTimeSeconds":205749403},{"id":1143,"name":"Codeforces Round 549 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1553965800,"relativeTimeSeconds":205749403},{"id":1140,"name":"Educational Codeforces Round 62 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1553267100,"relativeTimeSeconds":206448103},{"id":1139,"name":"Codeforces Round 548 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1553182500,"relativeTimeSeconds":206532703},{"id":1141,"name":"Codeforces Round 547 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1553006100,"relativeTimeSeconds":206709103},{"id":1136,"name":"Codeforces Round 546 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1552322100,"relativeTimeSeconds":207393103},{"id":1137,"name":"Codeforces Round 545 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1552035900,"relativeTimeSeconds":207679303},{"id":1138,"name":"Codeforces Round 545 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1552035900,"relativeTimeSeconds":207679303},{"id":1133,"name":"Codeforces Round 544 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1551971100,"relativeTimeSeconds":207744103},{"id":1132,"name":"Educational Codeforces Round 61 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1551798300,"relativeTimeSeconds":207916903},{"id":1120,"name":"Codeforces Round 543 (Div. 1, based on Technocup 2019 Final Round)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1551627300,"relativeTimeSeconds":208087903},{"id":1121,"name":"Codeforces Round 543 (Div. 2, based on Technocup 2019 Final Round)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1551627300,"relativeTimeSeconds":208087903},{"id":1112,"name":"Technocup 2019 - Final","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1551601800,"relativeTimeSeconds":208113403},{"id":1116,"name":"Microsoft Q# Coding Contest - Winter 2019","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":259200,"startTimeSeconds":1551459600,"relativeTimeSeconds":208255603},{"id":1129,"name":"Codeforces Round 542 [Alex Lopashev Thanks-Round] (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1551022500,"relativeTimeSeconds":208692703},{"id":1130,"name":"Codeforces Round 542 [Alex Lopashev Thanks-Round] (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1551022500,"relativeTimeSeconds":208692703},{"id":1131,"name":"Codeforces Round 541 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1550917200,"relativeTimeSeconds":208798003},{"id":1115,"name":"Microsoft Q# Coding Contest - Winter 2019 - Warmup","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":259200,"startTimeSeconds":1550854800,"relativeTimeSeconds":208860403},{"id":1118,"name":"Codeforces Round 540 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1550586900,"relativeTimeSeconds":209128303},{"id":1117,"name":"Educational Codeforces Round 60 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1550504400,"relativeTimeSeconds":209210803},{"id":1109,"name":"Codeforces Round 539 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1550334900,"relativeTimeSeconds":209380303},{"id":1113,"name":"Codeforces Round 539 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1550334900,"relativeTimeSeconds":209380303},{"id":1114,"name":"Codeforces Round 538 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1549807500,"relativeTimeSeconds":209907703},{"id":1110,"name":"Codeforces Global Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1549546500,"relativeTimeSeconds":210168703},{"id":1111,"name":"CodeCraft-19 and Codeforces Round 537 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1549208100,"relativeTimeSeconds":210507103},{"id":1106,"name":"Codeforces Round 536 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9600,"startTimeSeconds":1548938100,"relativeTimeSeconds":210777103},{"id":1107,"name":"Educational Codeforces Round 59 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1548516900,"relativeTimeSeconds":211198303},{"id":1108,"name":"Codeforces Round 535 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1548254100,"relativeTimeSeconds":211461103},{"id":1103,"name":"Codeforces Round 534 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1548167700,"relativeTimeSeconds":211547503},{"id":1104,"name":"Codeforces Round 534 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1548167700,"relativeTimeSeconds":211547503},{"id":1105,"name":"Codeforces Round 533 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1547985900,"relativeTimeSeconds":211729303},{"id":1100,"name":"Codeforces Round 532 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1547390100,"relativeTimeSeconds":212325103},{"id":1101,"name":"Educational Codeforces Round 58 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1547217300,"relativeTimeSeconds":212497903},{"id":1102,"name":"Codeforces Round 531 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1547044500,"relativeTimeSeconds":212670703},{"id":1098,"name":"Codeforces Round 530 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1546706100,"relativeTimeSeconds":213009103},{"id":1099,"name":"Codeforces Round 530 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1546706100,"relativeTimeSeconds":213009103},{"id":1097,"name":"Hello 2019","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1546613100,"relativeTimeSeconds":213102103},{"id":1091,"name":"Good Bye 2018","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9600,"startTimeSeconds":1546180500,"relativeTimeSeconds":213534703},{"id":1096,"name":"Educational Codeforces Round 57 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1546007700,"relativeTimeSeconds":213707503},{"id":1095,"name":"Codeforces Round 529 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1545921300,"relativeTimeSeconds":213793903},{"id":1086,"name":"Codeforces Round 528 (Div. 1, based on Technocup 2019 Elimination Round 4)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1545572100,"relativeTimeSeconds":214143103},{"id":1087,"name":"Codeforces Round 528 (Div. 2, based on Technocup 2019 Elimination Round 4)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1545572100,"relativeTimeSeconds":214143103},{"id":1085,"name":"Technocup 2019 - Elimination Round 4","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1545572100,"relativeTimeSeconds":214143103},{"id":1094,"name":"Технокубок 2019 - Ознакомительный Раунд 4","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":172800,"startTimeSeconds":1545395700,"relativeTimeSeconds":214319503},{"id":1092,"name":"Codeforces Round 527 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1545143700,"relativeTimeSeconds":214571503},{"id":1081,"name":"Avito Cool Challenge 2018","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1544970900,"relativeTimeSeconds":214744303},{"id":1093,"name":"Educational Codeforces Round 56 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1544884500,"relativeTimeSeconds":214830703},{"id":1083,"name":"Codeforces Round 526 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1544459700,"relativeTimeSeconds":215255503},{"id":1084,"name":"Codeforces Round 526 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1544459700,"relativeTimeSeconds":215255503},{"id":1090,"name":"2018-2019 Russia Open High School Programming Contest (Unrated, Online Mirror, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1544342700,"relativeTimeSeconds":215372503},{"id":1088,"name":"Codeforces Round 525 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1543934100,"relativeTimeSeconds":215781103},{"id":1089,"name":"2018-2019 ICPC, NEERC, Northern Eurasia Finals (Unrated, Online Mirror, ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1543734300,"relativeTimeSeconds":215980903},{"id":1082,"name":"Educational Codeforces Round 55 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1543415700,"relativeTimeSeconds":216299503},{"id":1056,"name":"Mail.Ru Cup 2018 Round 3","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1543163700,"relativeTimeSeconds":216551503},{"id":1080,"name":"Codeforces Round 524 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1543044900,"relativeTimeSeconds":216670303},{"id":1061,"name":"Codeforces Round 523 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1542901500,"relativeTimeSeconds":216813703},{"id":1078,"name":"Codeforces Round 522 (Div. 1, based on Technocup 2019 Elimination Round 3)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8400,"startTimeSeconds":1542557100,"relativeTimeSeconds":217158103},{"id":1079,"name":"Codeforces Round 522 (Div. 2, based on Technocup 2019 Elimination Round 3)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8400,"startTimeSeconds":1542557100,"relativeTimeSeconds":217158103},{"id":1032,"name":"Technocup 2019 - Elimination Round 3","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8400,"startTimeSeconds":1542557100,"relativeTimeSeconds":217158103},{"id":1050,"name":"Технокубок 2019 - Ознакомительный Раунд 3","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":172800,"startTimeSeconds":1542380700,"relativeTimeSeconds":217334503},{"id":1077,"name":"Codeforces Round 521 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1542378900,"relativeTimeSeconds":217336303},{"id":1062,"name":"Codeforces Round 520 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1542209700,"relativeTimeSeconds":217505503},{"id":1076,"name":"Educational Codeforces Round 54 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1542033300,"relativeTimeSeconds":217681903},{"id":1055,"name":"Mail.Ru Cup 2018 Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1541860500,"relativeTimeSeconds":217854703},{"id":1044,"name":"Lyft Level 5 Challenge 2018 - Final Round","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1541355000,"relativeTimeSeconds":218360203},{"id":1074,"name":"Lyft Level 5 Challenge 2018 - Final Round (Open Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1541355000,"relativeTimeSeconds":218360203},{"id":1075,"name":"Lyft Level 5 Challenge 2018 - Final Round (Open Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1541355000,"relativeTimeSeconds":218360203},{"id":1043,"name":"Codeforces Round 519 by Botan Investments","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1540740900,"relativeTimeSeconds":218974303},{"id":1073,"name":"Educational Codeforces Round 53 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1540478100,"relativeTimeSeconds":219237103},{"id":1067,"name":"Codeforces Round 518 (Div. 1) [Thanks, Mail.Ru!]","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1540398900,"relativeTimeSeconds":219316303},{"id":1068,"name":"Codeforces Round 518 (Div. 2) [Thanks, Mail.Ru!]","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1540398900,"relativeTimeSeconds":219316303},{"id":1071,"name":"Codeforces Round 517 (Div. 1, based on Technocup 2019 Elimination Round 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1540109400,"relativeTimeSeconds":219605803},{"id":1072,"name":"Codeforces Round 517 (Div. 2, based on Technocup 2019 Elimination Round 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1540109400,"relativeTimeSeconds":219605803},{"id":1031,"name":"Technocup 2019 - Elimination Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1540109400,"relativeTimeSeconds":219605803},{"id":1070,"name":"2018-2019 ICPC, NEERC, Southern Subregional Contest (Online Mirror, ACM-ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1540022700,"relativeTimeSeconds":219692503},{"id":1049,"name":"Технокубок 2019 - Ознакомительный Раунд 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":172800,"startTimeSeconds":1539932700,"relativeTimeSeconds":219782503},{"id":1054,"name":"Mail.Ru Cup 2018 Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1539880500,"relativeTimeSeconds":219834703},{"id":1063,"name":"Codeforces Round 516 (Div. 1, by Moscow Team Olympiad)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1539511500,"relativeTimeSeconds":220203703},{"id":1064,"name":"Codeforces Round 516 (Div. 2, by Moscow Team Olympiad)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1539511500,"relativeTimeSeconds":220203703},{"id":1066,"name":"Codeforces Round 515 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1539354900,"relativeTimeSeconds":220360303},{"id":1057,"name":"Mail.Ru Cup 2018 - Practice Round","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":259200,"startTimeSeconds":1539335100,"relativeTimeSeconds":220380103},{"id":1065,"name":"Educational Codeforces Round 52 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1539269400,"relativeTimeSeconds":220445803},{"id":1033,"name":"Lyft Level 5 Challenge 2018 - Elimination Round","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1538931900,"relativeTimeSeconds":220783303},{"id":1059,"name":"Codeforces Round 514 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1538750100,"relativeTimeSeconds":220965103},{"id":1060,"name":"Codeforces Round 513 by Barcelona Bootcamp (rated, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1538636700,"relativeTimeSeconds":221078503},{"id":1053,"name":"Codeforces Round 512 (Div. 1, based on Technocup 2019 Elimination Round 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1537707900,"relativeTimeSeconds":222007303},{"id":1058,"name":"Codeforces Round 512 (Div. 2, based on Technocup 2019 Elimination Round 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1537707900,"relativeTimeSeconds":222007303},{"id":1030,"name":"Technocup 2019 - Elimination Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1537707900,"relativeTimeSeconds":222007303},{"id":1045,"name":"Bubble Cup 11 - Finals [Online Mirror, Div. 1]","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"freezeDurationSeconds":3600,"startTimeSeconds":1537612500,"relativeTimeSeconds":222102703},{"id":1046,"name":"Bubble Cup 11 - Finals [Online Mirror, Div. 2]","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"freezeDurationSeconds":3600,"startTimeSeconds":1537612500,"relativeTimeSeconds":222102703},{"id":1034,"name":"Codeforces Round 511 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1537540500,"relativeTimeSeconds":222174703},{"id":1047,"name":"Codeforces Round 511 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1537540500,"relativeTimeSeconds":222174703},{"id":1048,"name":"Технокубок 2019 - Ознакомительный Раунд 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":172800,"startTimeSeconds":1537531500,"relativeTimeSeconds":222183703},{"id":1052,"name":"Huawei Honorcup Marathon 1","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":1209600,"startTimeSeconds":1537462800,"relativeTimeSeconds":222252403},{"id":1051,"name":"Educational Codeforces Round 51 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1537454700,"relativeTimeSeconds":222260503},{"id":1042,"name":"Codeforces Round 510 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1537171500,"relativeTimeSeconds":222543703},{"id":1041,"name":"Codeforces Round 509 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1537094100,"relativeTimeSeconds":222621103},{"id":1036,"name":"Educational Codeforces Round 50 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1536330900,"relativeTimeSeconds":223384301},{"id":1038,"name":"Codeforces Round 508 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1536248100,"relativeTimeSeconds":223467103},{"id":1039,"name":"Codeforces Round 507 (Div. 1, based on Olympiad of Metropolises)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1536165300,"relativeTimeSeconds":223549903},{"id":1040,"name":"Codeforces Round 507 (Div. 2, based on Olympiad of Metropolises)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1536165300,"relativeTimeSeconds":223549903},{"id":1037,"name":"Manthan, Codefest 18 (rated, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1535898900,"relativeTimeSeconds":223816303},{"id":1028,"name":"AIM Tech Round 5 (rated, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1535387700,"relativeTimeSeconds":224327503},{"id":1029,"name":"Codeforces Round 506 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1535122200,"relativeTimeSeconds":224593003},{"id":1025,"name":"Codeforces Round 505 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Final)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1534685700,"relativeTimeSeconds":225029503},{"id":1027,"name":"Educational Codeforces Round 49 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1534602900,"relativeTimeSeconds":225112303},{"id":1023,"name":"Codeforces Round 504 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Final)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1534516500,"relativeTimeSeconds":225198703},{"id":951,"name":"VK Cup 2018 - Final","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1534059600,"relativeTimeSeconds":225655603},{"id":1019,"name":"Codeforces Round 503 (by SIS, Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1533994500,"relativeTimeSeconds":225720703},{"id":1020,"name":"Codeforces Round 503 (by SIS, Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1533994500,"relativeTimeSeconds":225720703},{"id":1017,"name":"Codeforces Round 502 (in memory of Leopoldo Taravilse, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9600,"startTimeSeconds":1533737100,"relativeTimeSeconds":225978103},{"id":1016,"name":"Educational Codeforces Round 48 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1533307500,"relativeTimeSeconds":226407703},{"id":1015,"name":"Codeforces Round 501 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1533047700,"relativeTimeSeconds":226667503},{"id":1012,"name":"Codeforces Round 500 (Div. 1) [based on EJOI]","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1532938500,"relativeTimeSeconds":226776703},{"id":1013,"name":"Codeforces Round 500 (Div. 2) [based on EJOI]","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1532938500,"relativeTimeSeconds":226776703},{"id":1010,"name":"Codeforces Round 499 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1532617500,"relativeTimeSeconds":227097703},{"id":1011,"name":"Codeforces Round 499 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1532617500,"relativeTimeSeconds":227097703},{"id":1014,"name":"Codeforces Marathon Round 2","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":604800,"startTimeSeconds":1532434500,"relativeTimeSeconds":227280703},{"id":1006,"name":"Codeforces Round 498 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1531751700,"relativeTimeSeconds":227963503},{"id":1009,"name":"Educational Codeforces Round 47 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1531578900,"relativeTimeSeconds":228136303},{"id":1007,"name":"Codeforces Round 497 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1531492500,"relativeTimeSeconds":228222703},{"id":1008,"name":"Codeforces Round 497 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1531492500,"relativeTimeSeconds":228222703},{"id":1005,"name":"Codeforces Round 496 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1531150500,"relativeTimeSeconds":228564703},{"id":1002,"name":"Microsoft Q# Coding Contest - Summer 2018","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":259200,"startTimeSeconds":1530892800,"relativeTimeSeconds":228822403},{"id":1004,"name":"Codeforces Round 495 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1530808500,"relativeTimeSeconds":228906703},{"id":1003,"name":"Codeforces Round 494 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1530628500,"relativeTimeSeconds":229086703},{"id":997,"name":"Codeforces Round 493 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1530453900,"relativeTimeSeconds":229261303},{"id":998,"name":"Codeforces Round 493 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1530453900,"relativeTimeSeconds":229261303},{"id":1001,"name":"Microsoft Q# Coding Contest - Summer 2018 - Warmup","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":259200,"startTimeSeconds":1530288000,"relativeTimeSeconds":229427203},{"id":1000,"name":"Educational Codeforces Round 46 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1530110100,"relativeTimeSeconds":229605101},{"id":995,"name":"Codeforces Round 492 (Div. 1) [Thanks, uDebug!]","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1529858100,"relativeTimeSeconds":229857103},{"id":996,"name":"Codeforces Round 492 (Div. 2) [Thanks, uDebug!]","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1529858100,"relativeTimeSeconds":229857103},{"id":991,"name":"Codeforces Round 491 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1529768100,"relativeTimeSeconds":229947103},{"id":999,"name":"Codeforces Round 490 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1529591700,"relativeTimeSeconds":230123503},{"id":992,"name":"Codeforces Round 489 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1529339700,"relativeTimeSeconds":230375503},{"id":993,"name":"Codeforces Round 488 by NEAR (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1529166900,"relativeTimeSeconds":230548303},{"id":994,"name":"Codeforces Round 488 by NEAR (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1529166900,"relativeTimeSeconds":230548303},{"id":989,"name":"Codeforces Round 487 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1528724100,"relativeTimeSeconds":230991103},{"id":990,"name":"Educational Codeforces Round 45 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1528625100,"relativeTimeSeconds":231090103},{"id":988,"name":"Codeforces Round 486 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1527863700,"relativeTimeSeconds":231851503},{"id":986,"name":"Codeforces Round 485 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1527608100,"relativeTimeSeconds":232107103},{"id":987,"name":"Codeforces Round 485 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1527608100,"relativeTimeSeconds":232107103},{"id":981,"name":"Avito Code Challenge 2018","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1527432600,"relativeTimeSeconds":232282603},{"id":985,"name":"Educational Codeforces Round 44 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1526913900,"relativeTimeSeconds":232801303},{"id":982,"name":"Codeforces Round 484 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1526574900,"relativeTimeSeconds":233140303},{"id":983,"name":"Codeforces Round 483 (Div. 1) [Thanks, Botan Investments and Victor Shaburov!]","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1526395500,"relativeTimeSeconds":233319703},{"id":984,"name":"Codeforces Round 483 (Div. 2) [Thanks, Botan Investments and Victor Shaburov!]","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1526395500,"relativeTimeSeconds":233319703},{"id":979,"name":"Codeforces Round 482 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1526308500,"relativeTimeSeconds":233406703},{"id":978,"name":"Codeforces Round 481 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1526202300,"relativeTimeSeconds":233512903},{"id":980,"name":"Codeforces Round 480 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1525791900,"relativeTimeSeconds":233923303},{"id":977,"name":"Codeforces Round 479 (Div. 3)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1525615500,"relativeTimeSeconds":234099703},{"id":975,"name":"Codeforces Round 478 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1525183500,"relativeTimeSeconds":234531703},{"id":976,"name":"Educational Codeforces Round 43 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1525099200,"relativeTimeSeconds":234616003},{"id":966,"name":"Codeforces Round 477 (rated, Div. 1, based on VK Cup 2018 Round 3)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1525007700,"relativeTimeSeconds":234707503},{"id":967,"name":"Codeforces Round 477 (rated, Div. 2, based on VK Cup 2018 Round 3)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1525007700,"relativeTimeSeconds":234707503},{"id":925,"name":"VK Cup 2018 - Round 3","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1525007700,"relativeTimeSeconds":234707503},{"id":965,"name":"Codeforces Round 476 (Div. 2) [Thanks, Telegram!]","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1524677700,"relativeTimeSeconds":235037503},{"id":927,"name":"VK Cup 2018 - Wild-card Round 2","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":604800,"startTimeSeconds":1524152100,"relativeTimeSeconds":235563103},{"id":963,"name":"Tinkoff Internship Warmup Round 2018 and Codeforces Round 475 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1523973900,"relativeTimeSeconds":235741303},{"id":964,"name":"Tinkoff Internship Warmup Round 2018 and Codeforces Round 475 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1523973900,"relativeTimeSeconds":235741303},{"id":958,"name":"Helvetic Coding Contest 2018 online mirror (teams allowed, unrated)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1523689500,"relativeTimeSeconds":236025703},{"id":962,"name":"Educational Codeforces Round 42 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1523370900,"relativeTimeSeconds":236344303},{"id":960,"name":"Divide by Zero 2018 and Codeforces Round 474 (Div. 1 + Div. 2, combined)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1523117100,"relativeTimeSeconds":236598103},{"id":961,"name":"Educational Codeforces Round 41 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1522850700,"relativeTimeSeconds":236864501},{"id":959,"name":"Codeforces Round 473 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1522771500,"relativeTimeSeconds":236943703},{"id":952,"name":"April Fools Contest 2018","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1522596900,"relativeTimeSeconds":237118303},{"id":956,"name":"Codeforces Round 472 (rated, Div. 1, based on VK Cup 2018 Round 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1521905700,"relativeTimeSeconds":237809503},{"id":957,"name":"Codeforces Round 472 (rated, Div. 2, based on VK Cup 2018 Round 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1521905700,"relativeTimeSeconds":237809503},{"id":924,"name":"VK Cup 2018 - Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1521905700,"relativeTimeSeconds":237809503},{"id":955,"name":"Codeforces Round 471 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1521822900,"relativeTimeSeconds":237892303},{"id":954,"name":"Educational Codeforces Round 40 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1521698700,"relativeTimeSeconds":238016503},{"id":926,"name":"VK Cup 2018 - Wild-card Round 1","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1521300900,"relativeTimeSeconds":238414303},{"id":953,"name":"VK Cup 2018 - Wild-card Round 1 (unofficial unrated mirror)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1521300900,"relativeTimeSeconds":238414303},{"id":947,"name":"Codeforces Round 470 (rated, Div. 1, based on VK Cup 2018 Round 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1520696100,"relativeTimeSeconds":239019103},{"id":948,"name":"Codeforces Round 470 (rated, Div. 2, based on VK Cup 2018 Round 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1520696100,"relativeTimeSeconds":239019103},{"id":923,"name":"VK Cup 2018 - Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1520696100,"relativeTimeSeconds":239019103},{"id":949,"name":"Codeforces Round 469 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1520583000,"relativeTimeSeconds":239132203},{"id":950,"name":"Codeforces Round 469 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1520583000,"relativeTimeSeconds":239132203},{"id":946,"name":"Educational Codeforces Round 39 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1520348700,"relativeTimeSeconds":239366503},{"id":930,"name":"Codeforces Round 468 (Div. 1, based on Technocup 2018 Final Round)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1520177700,"relativeTimeSeconds":239537501},{"id":931,"name":"Codeforces Round 468 (Div. 2, based on Technocup 2018 Final Round)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1520177700,"relativeTimeSeconds":239537503},{"id":944,"name":"Технокубок 2018 - Финал (только для онсайт-финалистов)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1520152800,"relativeTimeSeconds":239562403},{"id":929,"name":"VK Cup 2018 - Квалификация 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":86400,"startTimeSeconds":1520004900,"relativeTimeSeconds":239710303},{"id":936,"name":"Codeforces Round 467 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1519574700,"relativeTimeSeconds":240140503},{"id":937,"name":"Codeforces Round 467 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1519574700,"relativeTimeSeconds":240140503},{"id":928,"name":"VK Cup 2018 - Квалификация 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":86400,"startTimeSeconds":1519486500,"relativeTimeSeconds":240228703},{"id":940,"name":"Codeforces Round 466 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1519464900,"relativeTimeSeconds":240250303},{"id":935,"name":"Codeforces Round 465 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1519058100,"relativeTimeSeconds":240657101},{"id":939,"name":"Codeforces Round 464 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1518861900,"relativeTimeSeconds":240853301},{"id":938,"name":"Educational Codeforces Round 38 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1518793500,"relativeTimeSeconds":240921703},{"id":932,"name":"ICM Technex 2018 and Codeforces Round 463 (Div. 1 + Div. 2, combined)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1518705300,"relativeTimeSeconds":241009903},{"id":933,"name":"Codeforces Round 462 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1518609900,"relativeTimeSeconds":241105303},{"id":934,"name":"Codeforces Round 462 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1518609900,"relativeTimeSeconds":241105303},{"id":922,"name":"Codeforces Round 461 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1518023700,"relativeTimeSeconds":241691503},{"id":920,"name":"Educational Codeforces Round 37 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1517582100,"relativeTimeSeconds":242133103},{"id":921,"name":"AIM Tech Mini Marathon 1","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1517500800,"relativeTimeSeconds":242214403},{"id":919,"name":"Codeforces Round 460 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1517403900,"relativeTimeSeconds":242311303},{"id":917,"name":"Codeforces Round 459 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1517236500,"relativeTimeSeconds":242478703},{"id":918,"name":"Codeforces Round 459 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1517236500,"relativeTimeSeconds":242478703},{"id":914,"name":"Codecraft-18 and Codeforces Round 458 (Div. 1 + Div. 2, combined)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1516462500,"relativeTimeSeconds":243252703},{"id":916,"name":"Codeforces Round 457 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1516372500,"relativeTimeSeconds":243342703},{"id":915,"name":"Educational Codeforces Round 36 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1515848700,"relativeTimeSeconds":243866503},{"id":913,"name":"Hello 2018","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1515422700,"relativeTimeSeconds":244292501},{"id":912,"name":"Codeforces Round 456 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1515162900,"relativeTimeSeconds":244552303},{"id":908,"name":"Good Bye 2017","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1514562000,"relativeTimeSeconds":245153203},{"id":911,"name":"Educational Codeforces Round 35 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1514469900,"relativeTimeSeconds":245245303},{"id":909,"name":"Codeforces Round 455 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1514392500,"relativeTimeSeconds":245322703},{"id":904,"name":"Технокубок 2018 - Отборочный Раунд 4","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1514037900,"relativeTimeSeconds":245677303},{"id":906,"name":"Codeforces Round 454 (Div. 1, based on Technocup 2018 Elimination Round 4)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1514037900,"relativeTimeSeconds":245677303},{"id":907,"name":"Codeforces Round 454 (Div. 2, based on Technocup 2018 Elimination Round 4)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1514037900,"relativeTimeSeconds":245677303},{"id":910,"name":"Testing Round 14 (Unrated)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":5400,"startTimeSeconds":1513940700,"relativeTimeSeconds":245774503},{"id":905,"name":"Технокубок 2018 - Ознакомительный Раунд 4","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":172800,"startTimeSeconds":1513861200,"relativeTimeSeconds":245854003},{"id":901,"name":"Codeforces Round 453 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1513697700,"relativeTimeSeconds":246017503},{"id":902,"name":"Codeforces Round 453 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1513697700,"relativeTimeSeconds":246017503},{"id":899,"name":"Codeforces Round 452 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1513492500,"relativeTimeSeconds":246222703},{"id":898,"name":"Codeforces Round 451 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1513424100,"relativeTimeSeconds":246291103},{"id":903,"name":"Educational Codeforces Round 34 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1513091100,"relativeTimeSeconds":246624103},{"id":900,"name":"Codeforces Round 450 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1513008300,"relativeTimeSeconds":246706903},{"id":896,"name":"Codeforces Round 449 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1512223500,"relativeTimeSeconds":247491703},{"id":897,"name":"Codeforces Round 449 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1512223500,"relativeTimeSeconds":247491703},{"id":895,"name":"Codeforces Round 448 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1511712300,"relativeTimeSeconds":248002903},{"id":893,"name":"Educational Codeforces Round 33 (Rated for Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1511449500,"relativeTimeSeconds":248265701},{"id":894,"name":"Codeforces Round 447 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1511099700,"relativeTimeSeconds":248615501},{"id":891,"name":"Codeforces Round 446 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1510929300,"relativeTimeSeconds":248785903},{"id":892,"name":"Codeforces Round 446 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1510929300,"relativeTimeSeconds":248785903},{"id":886,"name":"Технокубок 2018 - Отборочный Раунд 3","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1510502700,"relativeTimeSeconds":249212503},{"id":889,"name":"Codeforces Round 445 (Div. 1, based on Technocup 2018 Elimination Round 3)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1510502700,"relativeTimeSeconds":249212503},{"id":890,"name":"Codeforces Round 445 (Div. 2, based on Technocup 2018 Elimination Round 3)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1510502700,"relativeTimeSeconds":249212503},{"id":888,"name":"Educational Codeforces Round 32","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1510239900,"relativeTimeSeconds":249475303},{"id":885,"name":"Технокубок 2018 - Ознакомительный Раунд 3","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":259200,"startTimeSeconds":1510239600,"relativeTimeSeconds":249475603},{"id":887,"name":"Codeforces Round 444 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1509725100,"relativeTimeSeconds":249990103},{"id":884,"name":"Educational Codeforces Round 31","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1509113100,"relativeTimeSeconds":250602103},{"id":878,"name":"Codeforces Round 443 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1509029100,"relativeTimeSeconds":250686103},{"id":879,"name":"Codeforces Round 443 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1509029100,"relativeTimeSeconds":250686103},{"id":877,"name":"Codeforces Round 442 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1508773500,"relativeTimeSeconds":250941703},{"id":883,"name":"2017-2018 ACM-ICPC, NEERC, Southern Subregional Contest (Online Mirror, ACM-ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1508573100,"relativeTimeSeconds":251142103},{"id":875,"name":"Codeforces Round 441 (Div. 1, by Moscow Team Olympiad)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1508151900,"relativeTimeSeconds":251563303},{"id":876,"name":"Codeforces Round 441 (Div. 2, by Moscow Team Olympiad)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1508151900,"relativeTimeSeconds":251563303},{"id":871,"name":"Codeforces Round 440 (Div. 1, based on Technocup 2018 Elimination Round 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1508054700,"relativeTimeSeconds":251660503},{"id":872,"name":"Codeforces Round 440 (Div. 2, based on Technocup 2018 Elimination Round 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1508054700,"relativeTimeSeconds":251660503},{"id":870,"name":"Technocup 2018 - Elimination Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1508054700,"relativeTimeSeconds":251660503},{"id":873,"name":"Educational Codeforces Round 30","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1507817100,"relativeTimeSeconds":251898103},{"id":874,"name":"Technocup 2018 - Practice Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":259200,"startTimeSeconds":1507791600,"relativeTimeSeconds":251923603},{"id":869,"name":"Codeforces Round 439 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1507296900,"relativeTimeSeconds":252418303},{"id":868,"name":"Codeforces Round 438 by Sberbank and Barcelona Bootcamp (Div. 1 + Div. 2 combined)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1507187100,"relativeTimeSeconds":252528101},{"id":867,"name":"Codeforces Round 437 (Div. 2, based on MemSQL Start[c]UP 3.0 - Round 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1506791100,"relativeTimeSeconds":252924101},{"id":865,"name":"MemSQL Start[c]UP 3.0 - Round 2 (onsite finalists)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1506791100,"relativeTimeSeconds":252924103},{"id":866,"name":"MemSQL Start[c]UP 3.0 - Round 2 and Codeforces Round 437 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1506791100,"relativeTimeSeconds":252924103},{"id":864,"name":"Codeforces Round 436 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1506335700,"relativeTimeSeconds":253379503},{"id":855,"name":"Manthan, Codefest 17","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1506263700,"relativeTimeSeconds":253451501},{"id":863,"name":"Educational Codeforces Round 29","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1506006300,"relativeTimeSeconds":253708903},{"id":862,"name":"Codeforces Round 435 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1505833500,"relativeTimeSeconds":253881703},{"id":847,"name":"2017-2018 ACM-ICPC, NEERC, Southern Subregional Contest, qualification stage (Online Mirror, ACM-ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":14400,"startTimeSeconds":1505739900,"relativeTimeSeconds":253975303},{"id":858,"name":"Технокубок 2018 - Отборочный Раунд 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8400,"startTimeSeconds":1505653500,"relativeTimeSeconds":254061703},{"id":860,"name":"Codeforces Round 434 (Div. 1, based on Technocup 2018 Elimination Round 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8400,"startTimeSeconds":1505653500,"relativeTimeSeconds":254061703},{"id":861,"name":"Codeforces Round 434 (Div. 2, based on Technocup 2018 Elimination Round 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8400,"startTimeSeconds":1505653500,"relativeTimeSeconds":254061703},{"id":859,"name":"MemSQL Start[c]UP 3.0 - Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1505583300,"relativeTimeSeconds":254131903},{"id":857,"name":"Технокубок 2018 - Ознакомительный Раунд 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":259200,"startTimeSeconds":1505390400,"relativeTimeSeconds":254324803},{"id":856,"name":"Russian Code Cup 2017 - Finals [Unofficial Mirror, Div. 1 Only Recommended, Teams Allowed]","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1505050500,"relativeTimeSeconds":254664703},{"id":853,"name":"Codeforces Round 433 (Div. 1, based on Olympiad of Metropolises)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1504702500,"relativeTimeSeconds":255012703},{"id":854,"name":"Codeforces Round 433 (Div. 2, based on Olympiad of Metropolises)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1504702500,"relativeTimeSeconds":255012703},{"id":846,"name":"Educational Codeforces Round 28","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1504623900,"relativeTimeSeconds":255091303},{"id":850,"name":"Codeforces Round 432 (Div. 1, based on IndiaHacks Final Round 2017)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1504535700,"relativeTimeSeconds":255179503},{"id":851,"name":"Codeforces Round 432 (Div. 2, based on IndiaHacks Final Round 2017)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1504535700,"relativeTimeSeconds":255179503},{"id":852,"name":"Bubble Cup X - Finals [Online Mirror]","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1504432800,"relativeTimeSeconds":255282403},{"id":848,"name":"Codeforces Round 431 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1504272900,"relativeTimeSeconds":255442303},{"id":849,"name":"Codeforces Round 431 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1504272900,"relativeTimeSeconds":255442303},{"id":842,"name":"Codeforces Round 430 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1504019100,"relativeTimeSeconds":255696103},{"id":843,"name":"AIM Tech Round 4 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1503592500,"relativeTimeSeconds":256122703},{"id":844,"name":"AIM Tech Round 4 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1503592500,"relativeTimeSeconds":256122703},{"id":845,"name":"Educational Codeforces Round 27","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1503327900,"relativeTimeSeconds":256387303},{"id":840,"name":"Codeforces Round 429 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1503068700,"relativeTimeSeconds":256646503},{"id":841,"name":"Codeforces Round 429 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1503068700,"relativeTimeSeconds":256646503},{"id":839,"name":"Codeforces Round 428 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1502548500,"relativeTimeSeconds":257166703},{"id":838,"name":"IndiaHacks 2nd Elimination 2017 (unofficial, unrated mirror, ICPC rules)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1502085900,"relativeTimeSeconds":257629303},{"id":837,"name":"Educational Codeforces Round 26","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1501773300,"relativeTimeSeconds":257941903},{"id":835,"name":"Codeforces Round 427 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1501511700,"relativeTimeSeconds":258203503},{"id":833,"name":"Codeforces Round 426 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1501425300,"relativeTimeSeconds":258289903},{"id":834,"name":"Codeforces Round 426 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1501425300,"relativeTimeSeconds":258289903},{"id":832,"name":"Codeforces Round 425 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1500906900,"relativeTimeSeconds":258808303},{"id":825,"name":"Educational Codeforces Round 25","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1500217500,"relativeTimeSeconds":259497703},{"id":830,"name":"Codeforces Round 424 (Div. 1, rated, based on VK Cup Finals)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1499958300,"relativeTimeSeconds":259756903},{"id":831,"name":"Codeforces Round 424 (Div. 2, rated, based on VK Cup Finals)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1499958300,"relativeTimeSeconds":259756901},{"id":827,"name":"Codeforces Round 423 (Div. 1, rated, based on VK Cup Finals)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1499791500,"relativeTimeSeconds":259923703},{"id":828,"name":"Codeforces Round 423 (Div. 2, rated, based on VK Cup Finals)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1499791500,"relativeTimeSeconds":259923701},{"id":823,"name":"VK Cup 2017 - Finals","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1499587500,"relativeTimeSeconds":260127703},{"id":826,"name":"VK Cup 2017 - Finals (practice session)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":4800,"startTimeSeconds":1499502000,"relativeTimeSeconds":260213203},{"id":822,"name":"Codeforces Round 422 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1499011500,"relativeTimeSeconds":260703703},{"id":818,"name":"Educational Codeforces Round 24","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1498748700,"relativeTimeSeconds":260966503},{"id":819,"name":"Codeforces Round 421 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1498574100,"relativeTimeSeconds":261141103},{"id":820,"name":"Codeforces Round 421 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1498574100,"relativeTimeSeconds":261141103},{"id":821,"name":"Codeforces Round 420 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1498401300,"relativeTimeSeconds":261313903},{"id":815,"name":"Codeforces Round 419 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1497710100,"relativeTimeSeconds":262005103},{"id":816,"name":"Codeforces Round 419 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1497710100,"relativeTimeSeconds":262005103},{"id":817,"name":"Educational Codeforces Round 23","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1497539100,"relativeTimeSeconds":262176103},{"id":814,"name":"Codeforces Round 418 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1496837700,"relativeTimeSeconds":262877503},{"id":813,"name":"Educational Codeforces Round 22","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1496675100,"relativeTimeSeconds":263040103},{"id":812,"name":"Codeforces Round 417 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1496326500,"relativeTimeSeconds":263388703},{"id":802,"name":"Helvetic Coding Contest 2017 online mirror (teams allowed, unrated)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":16200,"freezeDurationSeconds":3600,"startTimeSeconds":1495958700,"relativeTimeSeconds":263756503},{"id":811,"name":"Codeforces Round 416 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1495877700,"relativeTimeSeconds":263837503},{"id":809,"name":"Codeforces Round 415 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1495303500,"relativeTimeSeconds":264411703},{"id":810,"name":"Codeforces Round 415 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1495303500,"relativeTimeSeconds":264411703},{"id":808,"name":"Educational Codeforces Round 21","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1494860700,"relativeTimeSeconds":264854503},{"id":794,"name":"Tinkoff Challenge - Final Round (Codeforces Round 414, rated, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1494668100,"relativeTimeSeconds":265047103},{"id":799,"name":"Playrix Codescapes Cup (Codeforces Round 413, rated, Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1494516900,"relativeTimeSeconds":265198303},{"id":806,"name":"Codeforces Round 412 (rated, Div. 1, based on VK Cup 2017 Round 3)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1494171900,"relativeTimeSeconds":265543303},{"id":807,"name":"Codeforces Round 412 (rated, Div. 2, base on VK Cup 2017 Round 3)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1494171900,"relativeTimeSeconds":265543303},{"id":773,"name":"VK Cup 2017 - Round 3","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1494171900,"relativeTimeSeconds":265543303},{"id":804,"name":"Codeforces Round 411 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1493909400,"relativeTimeSeconds":265805803},{"id":805,"name":"Codeforces Round 411 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1493909400,"relativeTimeSeconds":265805803},{"id":803,"name":"Educational Codeforces Round 20","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1493391900,"relativeTimeSeconds":266323303},{"id":775,"name":"VK Cup 2017 - Wild Card Round 2","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":604800,"startTimeSeconds":1493220900,"relativeTimeSeconds":266494303},{"id":793,"name":"Tinkoff Challenge - Elimination Round","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1492965900,"relativeTimeSeconds":266749303},{"id":798,"name":"Codeforces Round 410 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1492785300,"relativeTimeSeconds":266929903},{"id":800,"name":"Codeforces Round 409 (rated, Div. 1, based on VK Cup 2017 Round 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1492356900,"relativeTimeSeconds":267358303},{"id":801,"name":"Codeforces Round 409 (rated, Div. 2, based on VK Cup 2017 Round 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1492356900,"relativeTimeSeconds":267358303},{"id":772,"name":"VK Cup 2017 - Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1492356900,"relativeTimeSeconds":267358303},{"id":797,"name":"Educational Codeforces Round 19","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1492266900,"relativeTimeSeconds":267448303},{"id":796,"name":"Codeforces Round 408 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1491842100,"relativeTimeSeconds":267873103},{"id":774,"name":"VK Cup 2017 - Wild Card Round 1","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1491406500,"relativeTimeSeconds":268308703},{"id":795,"name":"VK Cup 2017 - Wild Card Round 1 (Unofficial Public Mirror)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1491406500,"relativeTimeSeconds":268308703},{"id":784,"name":"April Fools Contest 2017","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1490972400,"relativeTimeSeconds":268742803},{"id":788,"name":"Codeforces Round 407 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1490803500,"relativeTimeSeconds":268911703},{"id":789,"name":"Codeforces Round 407 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1490803500,"relativeTimeSeconds":268911703},{"id":792,"name":"Educational Codeforces Round 18","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1490625300,"relativeTimeSeconds":269089903},{"id":786,"name":"Codeforces Round 406 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1490281500,"relativeTimeSeconds":269433703},{"id":787,"name":"Codeforces Round 406 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1490281500,"relativeTimeSeconds":269433703},{"id":790,"name":"Codeforces Round 405 (rated, Div. 1, based on VK Cup 2017 Round 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1489851300,"relativeTimeSeconds":269863903},{"id":791,"name":"Codeforces Round 405 (rated, Div. 2, based on VK Cup 2017 Round 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1489851300,"relativeTimeSeconds":269863903},{"id":771,"name":"VK Cup 2017 - Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1489851300,"relativeTimeSeconds":269863903},{"id":785,"name":"Codeforces Round 404 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1489590300,"relativeTimeSeconds":270124903},{"id":770,"name":"VK Cup 2017 - Qualification 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":86400,"startTimeSeconds":1489233600,"relativeTimeSeconds":270481603},{"id":781,"name":"Codeforces Round 403 (Div. 1, based on Technocup 2017 Finals)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1488719100,"relativeTimeSeconds":270996103},{"id":782,"name":"Codeforces Round 403 (Div. 2, based on Technocup 2017 Finals)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1488719100,"relativeTimeSeconds":270996103},{"id":780,"name":"Технокубок 2017 - Финал (только для онсайт-финалистов)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1488705300,"relativeTimeSeconds":271009903},{"id":769,"name":"VK Cup 2017 - Qualification 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":86400,"startTimeSeconds":1488628800,"relativeTimeSeconds":271086403},{"id":778,"name":"Codeforces Round 402 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1488096300,"relativeTimeSeconds":271618903},{"id":779,"name":"Codeforces Round 402 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1488096300,"relativeTimeSeconds":271618903},{"id":777,"name":"Codeforces Round 401 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1487930700,"relativeTimeSeconds":271784503},{"id":776,"name":"ICM Technex 2017 and Codeforces Round 400 (Div. 1 + Div. 2, combined)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1487861100,"relativeTimeSeconds":271854103},{"id":768,"name":"Divide by Zero 2017 and Codeforces Round 399 (Div. 1 + Div. 2, combined)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9600,"startTimeSeconds":1487606700,"relativeTimeSeconds":272108503},{"id":767,"name":"Codeforces Round 398 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1487408700,"relativeTimeSeconds":272306503},{"id":765,"name":"Codeforces Round 397 by Kaspersky Lab and Barcelona Bootcamp (Div. 1 + Div. 2 combined)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1487059500,"relativeTimeSeconds":272655703},{"id":766,"name":"Codeforces Round 396 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1486487100,"relativeTimeSeconds":273228103},{"id":763,"name":"Codeforces Round 395 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1486042500,"relativeTimeSeconds":273672701},{"id":764,"name":"Codeforces Round 395 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1486042500,"relativeTimeSeconds":273672703},{"id":761,"name":"Codeforces Round 394 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1485873300,"relativeTimeSeconds":273841903},{"id":762,"name":"Educational Codeforces Round 17","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1485354900,"relativeTimeSeconds":274360303},{"id":756,"name":"8VC Venture Cup 2017 - Final Round","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1485108900,"relativeTimeSeconds":274606303},{"id":759,"name":"Codeforces Round 393 (Div. 1) (8VC Venture Cup 2017 - Final Round Div. 1 Edition)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1485108900,"relativeTimeSeconds":274606303},{"id":760,"name":"Codeforces Round 393 (Div. 2) (8VC Venture Cup 2017 - Final Round Div. 2 Edition)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1485108900,"relativeTimeSeconds":274606303},{"id":758,"name":"Codeforces Round 392 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1484838300,"relativeTimeSeconds":274876903},{"id":755,"name":"8VC Venture Cup 2017 - Elimination Round","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1484499900,"relativeTimeSeconds":275215303},{"id":757,"name":"Codecraft-17 and Codeforces Round 391 (Div. 1 + Div. 2, combined)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1484235300,"relativeTimeSeconds":275479903},{"id":754,"name":"Codeforces Round 390 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1483713300,"relativeTimeSeconds":276001903},{"id":750,"name":"Good Bye 2016","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1483107300,"relativeTimeSeconds":276607903},{"id":753,"name":"Testing Round 13","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":4500,"startTimeSeconds":1483002300,"relativeTimeSeconds":276712903},{"id":752,"name":"Codeforces Round 389 (Div. 2, Rated, Based on Technocup 2017 - Elimination Round 3)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1482656700,"relativeTimeSeconds":277058503},{"id":748,"name":"Technocup 2017 - Elimination Round 3","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1482656700,"relativeTimeSeconds":277058503},{"id":751,"name":"Технокубок 2017 - Ознакомительный Раунд 3","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":257400,"startTimeSeconds":1482395400,"relativeTimeSeconds":277319803},{"id":749,"name":"Codeforces Round 388 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1482165300,"relativeTimeSeconds":277549903},{"id":747,"name":"Codeforces Round 387 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1482113100,"relativeTimeSeconds":277602103},{"id":746,"name":"Codeforces Round 386 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1482057300,"relativeTimeSeconds":277657903},{"id":744,"name":"Codeforces Round 385 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1481992500,"relativeTimeSeconds":277722703},{"id":745,"name":"Codeforces Round 385 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1481992500,"relativeTimeSeconds":277722703},{"id":743,"name":"Codeforces Round 384 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1481726100,"relativeTimeSeconds":277989103},{"id":741,"name":"Codeforces Round 383 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1481034900,"relativeTimeSeconds":278680303},{"id":742,"name":"Codeforces Round 383 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1481034900,"relativeTimeSeconds":278680303},{"id":736,"name":"Codeforces Round 382 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1480264500,"relativeTimeSeconds":279450703},{"id":735,"name":"Codeforces Round 382 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1480264500,"relativeTimeSeconds":279450703},{"id":739,"name":"Codeforces Round 381 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1479918900,"relativeTimeSeconds":279796303},{"id":740,"name":"Codeforces Round 381 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1479918900,"relativeTimeSeconds":279796303},{"id":737,"name":"Codeforces Round 380 (Div. 1, Rated, Based on Technocup 2017 - Elimination Round 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1479632700,"relativeTimeSeconds":280082503},{"id":738,"name":"Codeforces Round 380 (Div. 2, Rated, Based on Technocup 2017 - Elimination Round 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1479632700,"relativeTimeSeconds":280082503},{"id":729,"name":"Technocup 2017 - Elimination Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1479632700,"relativeTimeSeconds":280082503},{"id":728,"name":"Технокубок 2017 - Ознакомительный Раунд 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":259200,"startTimeSeconds":1479369600,"relativeTimeSeconds":280345603},{"id":734,"name":"Codeforces Round 379 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1479227700,"relativeTimeSeconds":280487503},{"id":733,"name":"Codeforces Round 378 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1477922700,"relativeTimeSeconds":281792503},{"id":730,"name":"2016-2017 ACM-ICPC, NEERC, Southern Subregional Contest (Online Mirror, ACM-ICPC Rules, Teams Preferred)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1477209600,"relativeTimeSeconds":282505603},{"id":725,"name":"Canada Cup 2016","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1477148700,"relativeTimeSeconds":282566503},{"id":732,"name":"Codeforces Round 377 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1476714900,"relativeTimeSeconds":283000303},{"id":731,"name":"Codeforces Round 376 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1476611100,"relativeTimeSeconds":283104103},{"id":727,"name":"Technocup 2017 - Elimination Round 1 (Unofficially Open for Everyone, Rated for Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1476522300,"relativeTimeSeconds":283192903},{"id":726,"name":"Технокубок 2017 - Ознакомительный Раунд 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":255600,"startTimeSeconds":1476262800,"relativeTimeSeconds":283452403},{"id":724,"name":"Intel Code Challenge Final Round (Div. 1 + Div. 2, Combined)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1475928900,"relativeTimeSeconds":283786303},{"id":723,"name":"Codeforces Round 375 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1475494500,"relativeTimeSeconds":284220703},{"id":722,"name":"Intel Code Challenge Elimination Round (Div. 1 + Div. 2, combined)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1475330700,"relativeTimeSeconds":284384503},{"id":721,"name":"Codeforces Round 374 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1475244300,"relativeTimeSeconds":284470903},{"id":718,"name":"Codeforces Round 373 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1474635900,"relativeTimeSeconds":285079303},{"id":719,"name":"Codeforces Round 373 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1474635900,"relativeTimeSeconds":285079303},{"id":720,"name":"Russian Code Cup 2016 - Finals [Unofficial Mirror, Div. 1 Only Recommended]","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1474196700,"relativeTimeSeconds":285518503},{"id":715,"name":"Codeforces Round 372 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1474119900,"relativeTimeSeconds":285595303},{"id":716,"name":"Codeforces Round 372 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1474119900,"relativeTimeSeconds":285595303},{"id":713,"name":"Codeforces Round 371 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1473784500,"relativeTimeSeconds":285930703},{"id":714,"name":"Codeforces Round 371 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1473784500,"relativeTimeSeconds":285930703},{"id":717,"name":"Bubble Cup 9 - Finals [Online Mirror]","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1473584400,"relativeTimeSeconds":286130803},{"id":712,"name":"Codeforces Round 370 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1473525900,"relativeTimeSeconds":286189303},{"id":711,"name":"Codeforces Round 369 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1472472300,"relativeTimeSeconds":287242901},{"id":708,"name":"AIM Tech Round 3 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1472056500,"relativeTimeSeconds":287658703},{"id":709,"name":"AIM Tech Round 3 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1472056500,"relativeTimeSeconds":287658703},{"id":710,"name":"Educational Codeforces Round 16","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1471875000,"relativeTimeSeconds":287840203},{"id":707,"name":"Codeforces Round 368 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1471698300,"relativeTimeSeconds":288016903},{"id":706,"name":"Codeforces Round 367 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1470933300,"relativeTimeSeconds":288781903},{"id":704,"name":"Codeforces Round 366 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1470578700,"relativeTimeSeconds":289136503},{"id":705,"name":"Codeforces Round 366 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1470578700,"relativeTimeSeconds":289136503},{"id":703,"name":"Codeforces Round 365 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1470323700,"relativeTimeSeconds":289391503},{"id":702,"name":"Educational Codeforces Round 15","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1469804400,"relativeTimeSeconds":289910803},{"id":700,"name":"Codeforces Round 364 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1469205300,"relativeTimeSeconds":290509903},{"id":701,"name":"Codeforces Round 364 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1469205300,"relativeTimeSeconds":290509903},{"id":698,"name":"Codeforces Round 363 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1468933500,"relativeTimeSeconds":290781703},{"id":699,"name":"Codeforces Round 363 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1468933500,"relativeTimeSeconds":290781703},{"id":696,"name":"Codeforces Round 362 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1468514100,"relativeTimeSeconds":291201103},{"id":697,"name":"Codeforces Round 362 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1468514100,"relativeTimeSeconds":291201103},{"id":691,"name":"Educational Codeforces Round 14","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1468425600,"relativeTimeSeconds":291289603},{"id":690,"name":"Helvetic Coding Contest 2016 online mirror (teams, unrated)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":16200,"freezeDurationSeconds":3600,"startTimeSeconds":1468137600,"relativeTimeSeconds":291577603},{"id":689,"name":"Codeforces Round 361 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1467822900,"relativeTimeSeconds":291892303},{"id":695,"name":"VK Cup 2016 - Finals","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":12600,"startTimeSeconds":1467534000,"relativeTimeSeconds":292181203},{"id":693,"name":"VK Cup 2016 - Finals (trial contest)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":3600,"startTimeSeconds":1467447900,"relativeTimeSeconds":292267303},{"id":687,"name":"Codeforces Round 360 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1467219900,"relativeTimeSeconds":292495303},{"id":688,"name":"Codeforces Round 360 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1467219900,"relativeTimeSeconds":292495303},{"id":685,"name":"Codeforces Round 359 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1466699700,"relativeTimeSeconds":293015503},{"id":686,"name":"Codeforces Round 359 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1466699700,"relativeTimeSeconds":293015503},{"id":682,"name":"Codeforces Round 358 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1466181300,"relativeTimeSeconds":293533903},{"id":683,"name":"Surprise Language Round 8","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1466092800,"relativeTimeSeconds":293622403},{"id":681,"name":"Codeforces Round 357 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1465922100,"relativeTimeSeconds":293793103},{"id":678,"name":"Educational Codeforces Round 13","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1465834200,"relativeTimeSeconds":293881003},{"id":684,"name":"Codeforces Marathon Round 1","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":864000,"startTimeSeconds":1465722000,"relativeTimeSeconds":293993203},{"id":679,"name":"Codeforces Round 356 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1465403700,"relativeTimeSeconds":294311503},{"id":680,"name":"Codeforces Round 356 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1465403700,"relativeTimeSeconds":294311503},{"id":677,"name":"Codeforces Round 355 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1464798900,"relativeTimeSeconds":294916303},{"id":676,"name":"Codeforces Round 354 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1464188700,"relativeTimeSeconds":295526503},{"id":675,"name":"Codeforces Round 353 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1463416500,"relativeTimeSeconds":296298703},{"id":671,"name":"Codeforces Round 352 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1462984500,"relativeTimeSeconds":296730703},{"id":672,"name":"Codeforces Round 352 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1462984500,"relativeTimeSeconds":296730703},{"id":674,"name":"Codeforces Round 351 (VK Cup 2016 Round 3, Div. 1 Edition)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1462633500,"relativeTimeSeconds":297081703},{"id":673,"name":"Codeforces Round 351 (VK Cup 2016 Round 3, Div. 2 Edition)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1462633500,"relativeTimeSeconds":297081703},{"id":643,"name":"VK Cup 2016 - Round 3","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1462633500,"relativeTimeSeconds":297081703},{"id":670,"name":"Codeforces Round 350 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1462464300,"relativeTimeSeconds":297250901},{"id":666,"name":"Codeforces Round 349 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1461947700,"relativeTimeSeconds":297767501},{"id":667,"name":"Codeforces Round 349 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1461947700,"relativeTimeSeconds":297767501},{"id":642,"name":"VK Cup 2016 - Wild Card Round 2","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":604800,"startTimeSeconds":1461596400,"relativeTimeSeconds":298118803},{"id":668,"name":"Codeforces Round 348 (VK Cup 2016 Round 2, Div. 1 Edition)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1461515700,"relativeTimeSeconds":298199503},{"id":669,"name":"Codeforces Round 348 (VK Cup 2016 Round 2, Div. 2 Edition)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1461515700,"relativeTimeSeconds":298199503},{"id":641,"name":"VK Cup 2016 - Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1461515700,"relativeTimeSeconds":298199503},{"id":665,"name":"Educational Codeforces Round 12","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1461164400,"relativeTimeSeconds":298550803},{"id":663,"name":"Codeforces Round 347 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1460824500,"relativeTimeSeconds":298890703},{"id":664,"name":"Codeforces Round 347 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1460824500,"relativeTimeSeconds":298890703},{"id":662,"name":"CROC 2016 - Final Round [Private, For Onsite Finalists Only]","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1460729700,"relativeTimeSeconds":298985503},{"id":640,"name":"VK Cup 2016 - Wild Card Round 1","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1460306100,"relativeTimeSeconds":299409103},{"id":661,"name":"VK Cup 2016 - Wild Card Round 1 (Unofficial Open Online Mirror)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1460306100,"relativeTimeSeconds":299409103},{"id":660,"name":"Educational Codeforces Round 11","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1460127600,"relativeTimeSeconds":299587603},{"id":656,"name":"April Fools Day Contest 2016","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1459526400,"relativeTimeSeconds":300188803},{"id":659,"name":"Codeforces Round 346 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1459353900,"relativeTimeSeconds":300361303},{"id":639,"name":"VK Cup 2016 - Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1459182900,"relativeTimeSeconds":300532303},{"id":658,"name":"VK Cup 2016 - Round 1 (Div. 2 Edition)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1459182900,"relativeTimeSeconds":300532303},{"id":657,"name":"VK Cup 2016 - Round 1 (Div.1 Edition)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1459182900,"relativeTimeSeconds":300532303},{"id":649,"name":"Технокубок 2016 - Отборочный Раунд 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1458975600,"relativeTimeSeconds":300739603},{"id":652,"name":"Educational Codeforces Round 10","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1458910800,"relativeTimeSeconds":300804403},{"id":647,"name":"Технокубок 2016 - Ознакомительный Раунд 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":172800,"startTimeSeconds":1458799200,"relativeTimeSeconds":300916003},{"id":648,"name":"Технокубок 2016 - Отборочный Раунд 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1458745200,"relativeTimeSeconds":300970003},{"id":646,"name":"Технокубок 2016 - Ознакомительный Раунд 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":172800,"startTimeSeconds":1458568800,"relativeTimeSeconds":301146403},{"id":638,"name":"VK Cup 2016 - Qualification Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":86400,"startTimeSeconds":1458475200,"relativeTimeSeconds":301240003},{"id":653,"name":"IndiaHacks 2016 - Online Edition (Div. 1 + Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1458376500,"relativeTimeSeconds":301338703},{"id":645,"name":"CROC 2016 - Elimination Round","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1458318900,"relativeTimeSeconds":301396303},{"id":655,"name":"CROC 2016 - Elimination Round  (Rated Unofficial Edition)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1458318900,"relativeTimeSeconds":301396303},{"id":644,"name":"CROC 2016 - Qualification","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":172800,"startTimeSeconds":1458118800,"relativeTimeSeconds":301596403},{"id":637,"name":"VK Cup 2016 - Qualification Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":86400,"startTimeSeconds":1457870400,"relativeTimeSeconds":301844803},{"id":650,"name":"Codeforces Round 345 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1457342700,"relativeTimeSeconds":302372503},{"id":651,"name":"Codeforces Round 345 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1457342700,"relativeTimeSeconds":302372503},{"id":631,"name":"Codeforces Round 344 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1457022900,"relativeTimeSeconds":302692303},{"id":632,"name":"Educational Codeforces Round 9","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1456844400,"relativeTimeSeconds":302870803},{"id":636,"name":"VeeRoute Marathon","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":1209600,"startTimeSeconds":1456765200,"relativeTimeSeconds":302950003},{"id":627,"name":"8VC Venture Cup 2016 - Final Round","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1456683000,"relativeTimeSeconds":303032203},{"id":634,"name":"8VC Venture Cup 2016 - Final Round (Div. 1 Edition)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1456683000,"relativeTimeSeconds":303032203},{"id":635,"name":"8VC Venture Cup 2016 - Final Round (Div. 2 Edition)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1456683000,"relativeTimeSeconds":303032203},{"id":633,"name":"Manthan, Codefest 16","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1456506900,"relativeTimeSeconds":303208303},{"id":629,"name":"Codeforces Round 343 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1455986100,"relativeTimeSeconds":303729103},{"id":628,"name":"Educational Codeforces Round 8","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1455894000,"relativeTimeSeconds":303821203},{"id":630,"name":"Experimental Educational Round: VolBIT Formulas Blitz","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1455807600,"relativeTimeSeconds":303907603},{"id":626,"name":"8VC Venture Cup 2016 - Elimination Round","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1455384900,"relativeTimeSeconds":304330303},{"id":622,"name":"Educational Codeforces Round 7","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1455116400,"relativeTimeSeconds":304598803},{"id":625,"name":"Codeforces Round 342 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1454835900,"relativeTimeSeconds":304879303},{"id":623,"name":"AIM Tech Round (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1454605500,"relativeTimeSeconds":305109703},{"id":624,"name":"AIM Tech Round (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1454605500,"relativeTimeSeconds":305109703},{"id":621,"name":"Codeforces Round 341 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1454249100,"relativeTimeSeconds":305466103},{"id":618,"name":"Wunder Fund Round 2016 (Div. 1 + Div. 2 combined)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1454087400,"relativeTimeSeconds":305627803},{"id":617,"name":"Codeforces Round 340 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1453563300,"relativeTimeSeconds":306151903},{"id":620,"name":"Educational Codeforces Round 6","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1453388400,"relativeTimeSeconds":306326803},{"id":613,"name":"Codeforces Round 339 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1452789300,"relativeTimeSeconds":306925903},{"id":614,"name":"Codeforces Round 339 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1452789300,"relativeTimeSeconds":306925903},{"id":616,"name":"Educational Codeforces Round 5","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1452524400,"relativeTimeSeconds":307190803},{"id":615,"name":"Codeforces Round 338 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1452261900,"relativeTimeSeconds":307453303},{"id":611,"name":"Good Bye 2015","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1451487900,"relativeTimeSeconds":308227303},{"id":610,"name":"Codeforces Round 337 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1451215200,"relativeTimeSeconds":308500003},{"id":612,"name":"Educational Codeforces Round 4","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1451055600,"relativeTimeSeconds":308659603},{"id":607,"name":"Codeforces Round 336 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1450888500,"relativeTimeSeconds":308826703},{"id":608,"name":"Codeforces Round 336 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1450888500,"relativeTimeSeconds":308826703},{"id":609,"name":"Educational Codeforces Round 3","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1450537200,"relativeTimeSeconds":309178003},{"id":605,"name":"Codeforces Round 335 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1449677100,"relativeTimeSeconds":310038103},{"id":606,"name":"Codeforces Round 335 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1449677100,"relativeTimeSeconds":310038103},{"id":603,"name":"Codeforces Round 334 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1448984100,"relativeTimeSeconds":310731103},{"id":604,"name":"Codeforces Round 334 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1448984100,"relativeTimeSeconds":310731103},{"id":600,"name":"Educational Codeforces Round 2","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1448636400,"relativeTimeSeconds":311078803},{"id":601,"name":"Codeforces Round 333 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1448382900,"relativeTimeSeconds":311332303},{"id":602,"name":"Codeforces Round 333 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1448382900,"relativeTimeSeconds":311332303},{"id":599,"name":"Codeforces Round 332 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1448037300,"relativeTimeSeconds":311677903},{"id":596,"name":"Codeforces Round 331 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1447605300,"relativeTimeSeconds":312109903},{"id":598,"name":"Educational Codeforces Round 1","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1447426800,"relativeTimeSeconds":312288403},{"id":597,"name":"Testing Round 12","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":5400,"startTimeSeconds":1447264800,"relativeTimeSeconds":312450403},{"id":594,"name":"Codeforces Round 330 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1447000200,"relativeTimeSeconds":312715003},{"id":595,"name":"Codeforces Round 330 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1447000200,"relativeTimeSeconds":312715003},{"id":593,"name":"Codeforces Round 329 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1446655500,"relativeTimeSeconds":313059703},{"id":592,"name":"Codeforces Round 328 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1446309000,"relativeTimeSeconds":313406203},{"id":590,"name":"Codeforces Round 327 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1445763600,"relativeTimeSeconds":313951603},{"id":591,"name":"Codeforces Round 327 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1445763600,"relativeTimeSeconds":313951603},{"id":587,"name":"Codeforces Round 326 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1444926600,"relativeTimeSeconds":314788603},{"id":588,"name":"Codeforces Round 326 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1444926600,"relativeTimeSeconds":314788603},{"id":585,"name":"Codeforces Round 325 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1444641000,"relativeTimeSeconds":315074203},{"id":586,"name":"Codeforces Round 325 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1444641000,"relativeTimeSeconds":315074203},{"id":584,"name":"Codeforces Round 324 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1444149000,"relativeTimeSeconds":315566203},{"id":582,"name":"Codeforces Round 323 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1443890700,"relativeTimeSeconds":315824503},{"id":583,"name":"Codeforces Round 323 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1443890700,"relativeTimeSeconds":315824503},{"id":581,"name":"Codeforces Round 322 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1443430800,"relativeTimeSeconds":316284403},{"id":580,"name":"Codeforces Round 321 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1442939400,"relativeTimeSeconds":316775803},{"id":578,"name":"Codeforces Round 320 (Div. 1) [Bayan Thanks-Round]","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1442416500,"relativeTimeSeconds":317298703},{"id":579,"name":"Codeforces Round 320 (Div. 2) [Bayan Thanks-Round]","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1442416500,"relativeTimeSeconds":317298703},{"id":576,"name":"Codeforces Round 319 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1441902600,"relativeTimeSeconds":317812603},{"id":577,"name":"Codeforces Round 319 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1441902600,"relativeTimeSeconds":317812603},{"id":575,"name":"Bubble Cup 8 - Finals [Online Mirror]","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1441526400,"relativeTimeSeconds":318188803},{"id":573,"name":"Codeforces Round 318 [RussianCodeCup Thanks-Round] (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1440865800,"relativeTimeSeconds":318849403},{"id":574,"name":"Codeforces Round 318 [RussianCodeCup Thanks-Round] (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1440865800,"relativeTimeSeconds":318849403},{"id":571,"name":"Codeforces Round 317 [AimFund Thanks-Round] (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1440261000,"relativeTimeSeconds":319454203},{"id":572,"name":"Codeforces Round 317 [AimFund Thanks-Round] (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1440261000,"relativeTimeSeconds":319454203},{"id":570,"name":"Codeforces Round 316 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1439483400,"relativeTimeSeconds":320231803},{"id":568,"name":"Codeforces Round 315 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1439224200,"relativeTimeSeconds":320491003},{"id":569,"name":"Codeforces Round 315 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1439224200,"relativeTimeSeconds":320491003},{"id":567,"name":"Codeforces Round #Pi (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1438790400,"relativeTimeSeconds":320924803},{"id":566,"name":"VK Cup 2015 - Finals, online mirror","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1438273200,"relativeTimeSeconds":321442003},{"id":562,"name":"VK Cup 2015 - Finals","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1437898500,"relativeTimeSeconds":321816703},{"id":559,"name":"Codeforces Round 313 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1437573600,"relativeTimeSeconds":322141603},{"id":560,"name":"Codeforces Round 313 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1437573600,"relativeTimeSeconds":322141603},{"id":558,"name":"Codeforces Round 312 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1436886600,"relativeTimeSeconds":322828603},{"id":557,"name":"Codeforces Round 311 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1435676400,"relativeTimeSeconds":324038803},{"id":555,"name":"Codeforces Round 310 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1435414200,"relativeTimeSeconds":324301003},{"id":556,"name":"Codeforces Round 310 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1435414200,"relativeTimeSeconds":324301003},{"id":553,"name":"Codeforces Round 309 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1435163400,"relativeTimeSeconds":324551803},{"id":554,"name":"Codeforces Round 309 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1435163400,"relativeTimeSeconds":324551803},{"id":552,"name":"Codeforces Round 308 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1434645000,"relativeTimeSeconds":325070203},{"id":551,"name":"Codeforces Round 307 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1434127500,"relativeTimeSeconds":325587703},{"id":549,"name":"Looksery Cup 2015","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1433595600,"relativeTimeSeconds":326119603},{"id":550,"name":"Codeforces Round 306 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1433435400,"relativeTimeSeconds":326279803},{"id":547,"name":"Codeforces Round 305 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1432658100,"relativeTimeSeconds":327057103},{"id":548,"name":"Codeforces Round 305 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1432658100,"relativeTimeSeconds":327057103},{"id":546,"name":"Codeforces Round 304 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1432312200,"relativeTimeSeconds":327403003},{"id":545,"name":"Codeforces Round 303 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1432053000,"relativeTimeSeconds":327662203},{"id":543,"name":"Codeforces Round 302 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1431016200,"relativeTimeSeconds":328699003},{"id":544,"name":"Codeforces Round 302 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1431016200,"relativeTimeSeconds":328699003},{"id":541,"name":"VK Cup 2015 - Раунд 3","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1430668800,"relativeTimeSeconds":329046403},{"id":542,"name":"VK Cup 2015 - Round 3 (unofficial online mirror, Div. 1 only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1430668800,"relativeTimeSeconds":329046403},{"id":540,"name":"Codeforces Round 301 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1430411400,"relativeTimeSeconds":329303803},{"id":538,"name":"Codeforces Round 300","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1430064000,"relativeTimeSeconds":329651203},{"id":537,"name":"VK Cup 2015 - Wild Card Round 2","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":604800,"startTimeSeconds":1429381800,"relativeTimeSeconds":330333403},{"id":532,"name":"VK Cup 2015 - Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1429286400,"relativeTimeSeconds":330428803},{"id":533,"name":"VK Cup 2015 - Round 2 (unofficial online mirror, Div. 1 only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1429286400,"relativeTimeSeconds":330428803},{"id":536,"name":"Codeforces Round 299 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1429029300,"relativeTimeSeconds":330685903},{"id":535,"name":"Codeforces Round 299 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1429029300,"relativeTimeSeconds":330685903},{"id":534,"name":"Codeforces Round 298 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1428854400,"relativeTimeSeconds":330860803},{"id":526,"name":"ZeptoLab Code Rush 2015","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1428165300,"relativeTimeSeconds":331549903},{"id":530,"name":"VK Cup 2015 - Wild Card Round 1","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1427562000,"relativeTimeSeconds":332153203},{"id":531,"name":"VK Cup 2015 - Wild Card Round 1 (Online Mirror)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1427562000,"relativeTimeSeconds":332153203},{"id":525,"name":"Codeforces Round 297 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1427387400,"relativeTimeSeconds":332327803},{"id":529,"name":"VK Cup 2015 - Round 1 (unofficial online mirror, Div. 1 only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1426956300,"relativeTimeSeconds":332758903},{"id":524,"name":"VK Cup 2015 - Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1426946400,"relativeTimeSeconds":332768803},{"id":528,"name":"Codeforces Round 296 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1426610700,"relativeTimeSeconds":333104503},{"id":527,"name":"Codeforces Round 296 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1426610700,"relativeTimeSeconds":333104503},{"id":523,"name":"VK Cup 2015 - Qualification Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":86400,"startTimeSeconds":1426345200,"relativeTimeSeconds":333370003},{"id":522,"name":"VK Cup 2015 - Qualification Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":86400,"startTimeSeconds":1425740400,"relativeTimeSeconds":333974803},{"id":521,"name":"Codeforces Round 295 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7500,"startTimeSeconds":1425279600,"relativeTimeSeconds":334435603},{"id":520,"name":"Codeforces Round 295 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7500,"startTimeSeconds":1425279600,"relativeTimeSeconds":334435603},{"id":519,"name":"Codeforces Round 294 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1425128400,"relativeTimeSeconds":334586803},{"id":518,"name":"Codeforces Round 293 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1424795400,"relativeTimeSeconds":334919803},{"id":516,"name":"Codeforces Round 292 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1424190900,"relativeTimeSeconds":335524303},{"id":515,"name":"Codeforces Round 292 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1424190900,"relativeTimeSeconds":335524303},{"id":514,"name":"Codeforces Round 291 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1423931400,"relativeTimeSeconds":335783803},{"id":513,"name":"Rockethon 2015","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":11700,"startTimeSeconds":1423328400,"relativeTimeSeconds":336386803},{"id":512,"name":"Codeforces Round 290 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7500,"startTimeSeconds":1422894600,"relativeTimeSeconds":336820603},{"id":510,"name":"Codeforces Round 290 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7500,"startTimeSeconds":1422894600,"relativeTimeSeconds":336820603},{"id":509,"name":"Codeforces Round 289 (Div. 2, ACM ICPC Rules)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":10800,"freezeDurationSeconds":2160,"startTimeSeconds":1422705600,"relativeTimeSeconds":337009603},{"id":508,"name":"Codeforces Round 288 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1422376200,"relativeTimeSeconds":337339003},{"id":507,"name":"Codeforces Round 287 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1422028800,"relativeTimeSeconds":337686403},{"id":506,"name":"Codeforces Round 286 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1421586000,"relativeTimeSeconds":338129203},{"id":505,"name":"Codeforces Round 286 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1421586000,"relativeTimeSeconds":338129203},{"id":504,"name":"Codeforces Round 285 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1421053200,"relativeTimeSeconds":338662003},{"id":501,"name":"Codeforces Round 285 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1421053200,"relativeTimeSeconds":338662003},{"id":500,"name":"Good Bye 2014","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1419951600,"relativeTimeSeconds":339763603},{"id":498,"name":"Codeforces Round 284 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1419438600,"relativeTimeSeconds":340276603},{"id":499,"name":"Codeforces Round 284 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1419438600,"relativeTimeSeconds":340276603},{"id":497,"name":"Codeforces Round 283 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1418833800,"relativeTimeSeconds":340881403},{"id":496,"name":"Codeforces Round 283 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1418833800,"relativeTimeSeconds":340881403},{"id":494,"name":"Codeforces Round 282 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1418488200,"relativeTimeSeconds":341227003},{"id":495,"name":"Codeforces Round 282 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1418488200,"relativeTimeSeconds":341227003},{"id":493,"name":"Codeforces Round 281 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1417618800,"relativeTimeSeconds":342096403},{"id":492,"name":"Codeforces Round 280 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1417451400,"relativeTimeSeconds":342263803},{"id":490,"name":"Codeforces Round 279 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1416733800,"relativeTimeSeconds":342981403},{"id":487,"name":"Codeforces Round 278 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1416590400,"relativeTimeSeconds":343124803},{"id":488,"name":"Codeforces Round 278 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1416590400,"relativeTimeSeconds":343124803},{"id":491,"name":"Testing Round 11","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":5400,"startTimeSeconds":1416519000,"relativeTimeSeconds":343196203},{"id":489,"name":"Codeforces Round 277.5 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1416238500,"relativeTimeSeconds":343476703},{"id":486,"name":"Codeforces Round 277 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1415718000,"relativeTimeSeconds":343997203},{"id":484,"name":"Codeforces Round 276 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1415205000,"relativeTimeSeconds":344510203},{"id":485,"name":"Codeforces Round 276 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1415205000,"relativeTimeSeconds":344510203},{"id":482,"name":"Codeforces Round 275 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1414170000,"relativeTimeSeconds":345545203},{"id":483,"name":"Codeforces Round 275 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1414170000,"relativeTimeSeconds":345545203},{"id":480,"name":"Codeforces Round 274 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1413709200,"relativeTimeSeconds":346006003},{"id":479,"name":"Codeforces Round 274 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1413709200,"relativeTimeSeconds":346006003},{"id":478,"name":"Codeforces Round 273 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1413474000,"relativeTimeSeconds":346241203},{"id":477,"name":"Codeforces Round 272 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1413122400,"relativeTimeSeconds":346592803},{"id":476,"name":"Codeforces Round 272 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1413122400,"relativeTimeSeconds":346592803},{"id":474,"name":"Codeforces Round 271 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1412609400,"relativeTimeSeconds":347105803},{"id":475,"name":"Bayan 2015 Contest Warm Up","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1412514000,"relativeTimeSeconds":347201203},{"id":472,"name":"Codeforces Round 270","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1411918500,"relativeTimeSeconds":347796703},{"id":471,"name":"Codeforces Round 269 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1411745400,"relativeTimeSeconds":347969803},{"id":468,"name":"Codeforces Round 268 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1411218000,"relativeTimeSeconds":348497203},{"id":469,"name":"Codeforces Round 268 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1411218000,"relativeTimeSeconds":348497203},{"id":467,"name":"Codeforces Round 267 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1411054200,"relativeTimeSeconds":348661003},{"id":470,"name":"Surprise Language Round 7","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1410622200,"relativeTimeSeconds":349093003},{"id":466,"name":"Codeforces Round 266 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1410535800,"relativeTimeSeconds":349179403},{"id":464,"name":"Codeforces Round 265 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1410103800,"relativeTimeSeconds":349611403},{"id":465,"name":"Codeforces Round 265 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1410103800,"relativeTimeSeconds":349611403},{"id":463,"name":"Codeforces Round 264 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1409383800,"relativeTimeSeconds":350331403},{"id":461,"name":"Codeforces Round 263 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1409061600,"relativeTimeSeconds":350653603},{"id":462,"name":"Codeforces Round 263 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1409061600,"relativeTimeSeconds":350653603},{"id":460,"name":"Codeforces Round 262 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1408548600,"relativeTimeSeconds":351166603},{"id":459,"name":"Codeforces Round 261 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1408116600,"relativeTimeSeconds":351598603},{"id":457,"name":"MemSQL Start[c]UP 2.0 - Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1407690000,"relativeTimeSeconds":352025203},{"id":458,"name":"MemSQL Start[c]UP 2.0 - Round 2 - Online Round","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1407690000,"relativeTimeSeconds":352025203},{"id":455,"name":"Codeforces Round 260 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1407511800,"relativeTimeSeconds":352203403},{"id":456,"name":"Codeforces Round 260 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1407511800,"relativeTimeSeconds":352203403},{"id":453,"name":"Codeforces Round 259 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1406907000,"relativeTimeSeconds":352808203},{"id":454,"name":"Codeforces Round 259 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1406907000,"relativeTimeSeconds":352808203},{"id":452,"name":"MemSQL Start[c]UP 2.0 - Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1406480400,"relativeTimeSeconds":353234803},{"id":451,"name":"Codeforces Round 258 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1406215800,"relativeTimeSeconds":353499403},{"id":449,"name":"Codeforces Round 257 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1405774800,"relativeTimeSeconds":353940403},{"id":450,"name":"Codeforces Round 257 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1405774800,"relativeTimeSeconds":353940403},{"id":448,"name":"Codeforces Round 256 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1405605600,"relativeTimeSeconds":354109603},{"id":446,"name":"Codeforces Round #FF (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1405256400,"relativeTimeSeconds":354458803},{"id":447,"name":"Codeforces Round #FF (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1405256400,"relativeTimeSeconds":354458803},{"id":444,"name":"Codeforces Round 254 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1404651900,"relativeTimeSeconds":355063303},{"id":445,"name":"Codeforces Round 254 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1404651900,"relativeTimeSeconds":355063303},{"id":442,"name":"Codeforces Round 253 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1403191800,"relativeTimeSeconds":356523403},{"id":443,"name":"Codeforces Round 253 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1403191800,"relativeTimeSeconds":356523403},{"id":436,"name":"Zepto Code Rush 2014","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1402673400,"relativeTimeSeconds":357041803},{"id":441,"name":"Codeforces Round 252 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1402241400,"relativeTimeSeconds":357473803},{"id":439,"name":"Codeforces Round 251 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1401895800,"relativeTimeSeconds":357819403},{"id":440,"name":"Testing Round 10","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":5400,"startTimeSeconds":1401809400,"relativeTimeSeconds":357905803},{"id":438,"name":"Codeforces Round 250 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1401627600,"relativeTimeSeconds":358087603},{"id":437,"name":"Codeforces Round 250 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1401627600,"relativeTimeSeconds":358087603},{"id":435,"name":"Codeforces Round 249 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1401463800,"relativeTimeSeconds":358251403},{"id":434,"name":"Codeforces Round 248 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1400914800,"relativeTimeSeconds":358800403},{"id":433,"name":"Codeforces Round 248 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1400914800,"relativeTimeSeconds":358800403},{"id":431,"name":"Codeforces Round 247 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1400686200,"relativeTimeSeconds":359029003},{"id":432,"name":"Codeforces Round 246 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1400167800,"relativeTimeSeconds":359547403},{"id":429,"name":"Codeforces Round 245 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1399822800,"relativeTimeSeconds":359892403},{"id":430,"name":"Codeforces Round 245 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1399822800,"relativeTimeSeconds":359892403},{"id":427,"name":"Codeforces Round 244 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1399044600,"relativeTimeSeconds":360670603},{"id":425,"name":"Codeforces Round 243 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1398612600,"relativeTimeSeconds":361102603},{"id":426,"name":"Codeforces Round 243 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1398612600,"relativeTimeSeconds":361102603},{"id":424,"name":"Codeforces Round 242 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1398409200,"relativeTimeSeconds":361306003},{"id":419,"name":"Coder-Strike 2014 - Finals","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1398169200,"relativeTimeSeconds":361546003},{"id":420,"name":"Coder-Strike 2014 - Finals (online edition, Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1398169140,"relativeTimeSeconds":361546063},{"id":421,"name":"Coder-Strike 2014 - Finals (online edition, Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1398168900,"relativeTimeSeconds":361546303},{"id":413,"name":"Coder-Strike 2014 - Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1397977200,"relativeTimeSeconds":361738003},{"id":412,"name":"Coder-Strike 2014 - Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1397837400,"relativeTimeSeconds":361877803},{"id":418,"name":"RCC 2014 Warmup (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1397749200,"relativeTimeSeconds":361966003},{"id":417,"name":"RCC 2014 Warmup (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1397749200,"relativeTimeSeconds":361966003},{"id":411,"name":"Coder-Strike 2014 - Qualification Round","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":86400,"startTimeSeconds":1397505600,"relativeTimeSeconds":362209603},{"id":416,"name":"Codeforces Round 241 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1397376000,"relativeTimeSeconds":362339203},{"id":414,"name":"Codeforces Round 240 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1396798800,"relativeTimeSeconds":362916403},{"id":415,"name":"Codeforces Round 240 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1396798800,"relativeTimeSeconds":362916403},{"id":409,"name":"April Fools Day Contest 2014","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1396366200,"relativeTimeSeconds":363349003},{"id":407,"name":"Codeforces Round 239 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1396162800,"relativeTimeSeconds":363552403},{"id":408,"name":"Codeforces Round 239 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1396162800,"relativeTimeSeconds":363552403},{"id":406,"name":"Codeforces Round 238 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1395502200,"relativeTimeSeconds":364213003},{"id":405,"name":"Codeforces Round 238 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1395502200,"relativeTimeSeconds":364213003},{"id":404,"name":"Codeforces Round 237 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1395243000,"relativeTimeSeconds":364472203},{"id":403,"name":"Codeforces Round 236 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1394983800,"relativeTimeSeconds":364731403},{"id":402,"name":"Codeforces Round 236 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1394983800,"relativeTimeSeconds":364731403},{"id":401,"name":"Codeforces Round 235 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1394465400,"relativeTimeSeconds":365249803},{"id":400,"name":"Codeforces Round 234 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1394033400,"relativeTimeSeconds":365681803},{"id":398,"name":"Codeforces Round 233 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1393687800,"relativeTimeSeconds":366027403},{"id":399,"name":"Codeforces Round 233 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1393687800,"relativeTimeSeconds":366027403},{"id":396,"name":"Codeforces Round 232 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1393428600,"relativeTimeSeconds":366286603},{"id":397,"name":"Codeforces Round 232 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1393428600,"relativeTimeSeconds":366286603},{"id":394,"name":"Codeforces Round 231 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1392910200,"relativeTimeSeconds":366805003},{"id":392,"name":"Codeforces Round 230 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1392728400,"relativeTimeSeconds":366986803},{"id":393,"name":"Codeforces Round 230 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1392728400,"relativeTimeSeconds":366986803},{"id":391,"name":"Rockethon 2014","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1392573600,"relativeTimeSeconds":367141603},{"id":390,"name":"Codeforces Round 229 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1392132600,"relativeTimeSeconds":367582603},{"id":388,"name":"Codeforces Round 228 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7500,"startTimeSeconds":1391442000,"relativeTimeSeconds":368273203},{"id":389,"name":"Codeforces Round 228 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7500,"startTimeSeconds":1391442000,"relativeTimeSeconds":368273203},{"id":387,"name":"Codeforces Round 227 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1391095800,"relativeTimeSeconds":368619403},{"id":385,"name":"Codeforces Round 226 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1390577700,"relativeTimeSeconds":369137503},{"id":383,"name":"Codeforces Round 225 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1390231800,"relativeTimeSeconds":369483403},{"id":384,"name":"Codeforces Round 225 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1390231800,"relativeTimeSeconds":369483403},{"id":382,"name":"Codeforces Round 224 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1389972600,"relativeTimeSeconds":369742603},{"id":386,"name":"Testing Round 9","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":5400,"startTimeSeconds":1389906900,"relativeTimeSeconds":369808303},{"id":380,"name":"Codeforces Round 223 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1389540600,"relativeTimeSeconds":370174603},{"id":381,"name":"Codeforces Round 223 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1389540600,"relativeTimeSeconds":370174603},{"id":379,"name":"Good Bye 2013","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1388417400,"relativeTimeSeconds":371297803},{"id":377,"name":"Codeforces Round 222 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1388331000,"relativeTimeSeconds":371384203},{"id":378,"name":"Codeforces Round 222 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1388331000,"relativeTimeSeconds":371384203},{"id":375,"name":"Codeforces Round 221 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1387893600,"relativeTimeSeconds":371821603},{"id":376,"name":"Codeforces Round 221 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1387893600,"relativeTimeSeconds":371821603},{"id":374,"name":"Codeforces Round 220 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1387380600,"relativeTimeSeconds":372334603},{"id":372,"name":"Codeforces Round 219 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1386943200,"relativeTimeSeconds":372772003},{"id":373,"name":"Codeforces Round 219 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1386943200,"relativeTimeSeconds":372772003},{"id":371,"name":"Codeforces Round 218 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1386493200,"relativeTimeSeconds":373222003},{"id":370,"name":"Codeforces Round 217 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1386399600,"relativeTimeSeconds":373315603},{"id":369,"name":"Codeforces Round 216 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1385739000,"relativeTimeSeconds":373976201},{"id":367,"name":"Codeforces Round 215 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1385479800,"relativeTimeSeconds":374235403},{"id":368,"name":"Codeforces Round 215 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1385479800,"relativeTimeSeconds":374235403},{"id":366,"name":"Codeforces Round 214 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1385307000,"relativeTimeSeconds":374408203},{"id":364,"name":"Codeforces Round 213 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7500,"startTimeSeconds":1384875000,"relativeTimeSeconds":374840203},{"id":365,"name":"Codeforces Round 213 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7500,"startTimeSeconds":1384875000,"relativeTimeSeconds":374840203},{"id":362,"name":"Codeforces Round 212 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1384443000,"relativeTimeSeconds":375272203},{"id":363,"name":"Codeforces Round 211 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1384156800,"relativeTimeSeconds":375558403},{"id":360,"name":"Codeforces Round 210 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1384102800,"relativeTimeSeconds":375612403},{"id":361,"name":"Codeforces Round 210 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1384102800,"relativeTimeSeconds":375612403},{"id":359,"name":"Codeforces Round 209 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1383379200,"relativeTimeSeconds":376336003},{"id":358,"name":"Codeforces Round 208 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1382715000,"relativeTimeSeconds":377000203},{"id":356,"name":"Codeforces Round 207 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1381838400,"relativeTimeSeconds":377876803},{"id":357,"name":"Codeforces Round 207 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1381838400,"relativeTimeSeconds":377876803},{"id":354,"name":"Codeforces Round 206 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1381678200,"relativeTimeSeconds":378037003},{"id":355,"name":"Codeforces Round 206 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1381678200,"relativeTimeSeconds":378037003},{"id":353,"name":"Codeforces Round 205 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1381419000,"relativeTimeSeconds":378296203},{"id":351,"name":"Codeforces Round 204 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1380900600,"relativeTimeSeconds":378814603},{"id":352,"name":"Codeforces Round 204 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1380900600,"relativeTimeSeconds":378814603},{"id":350,"name":"Codeforces Round 203 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1380641400,"relativeTimeSeconds":379073803},{"id":348,"name":"Codeforces Round 202 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1380295800,"relativeTimeSeconds":379419403},{"id":349,"name":"Codeforces Round 202 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1380295800,"relativeTimeSeconds":379419403},{"id":346,"name":"Codeforces Round 201 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1379691000,"relativeTimeSeconds":380024203},{"id":347,"name":"Codeforces Round 201 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1379691000,"relativeTimeSeconds":380024203},{"id":343,"name":"Codeforces Round 200 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1379172600,"relativeTimeSeconds":380542603},{"id":344,"name":"Codeforces Round 200 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1379172600,"relativeTimeSeconds":380542603},{"id":345,"name":"Friday the 13th, Programmers Day","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1379086800,"relativeTimeSeconds":380628403},{"id":342,"name":"Codeforces Round 199 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1378540800,"relativeTimeSeconds":381174403},{"id":341,"name":"Codeforces Round 198 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1377876600,"relativeTimeSeconds":381838603},{"id":340,"name":"Codeforces Round 198 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1377876600,"relativeTimeSeconds":381838603},{"id":339,"name":"Codeforces Round 197 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1377531000,"relativeTimeSeconds":382184203},{"id":338,"name":"Codeforces Round 196 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1376668800,"relativeTimeSeconds":383046403},{"id":337,"name":"Codeforces Round 196 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1376668800,"relativeTimeSeconds":383046403},{"id":336,"name":"Codeforces Round 195 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1376062200,"relativeTimeSeconds":383653003},{"id":326,"name":"MemSQL start[c]up Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1375549200,"relativeTimeSeconds":384166003},{"id":335,"name":"MemSQL start[c]up Round 2 - online version","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1375549200,"relativeTimeSeconds":384166003},{"id":333,"name":"Codeforces Round 194 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1374913800,"relativeTimeSeconds":384801403},{"id":334,"name":"Codeforces Round 194 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1374913800,"relativeTimeSeconds":384801403},{"id":332,"name":"Codeforces Round 193 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1374679800,"relativeTimeSeconds":385035403},{"id":329,"name":"Codeforces Round 192 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1374327000,"relativeTimeSeconds":385388203},{"id":330,"name":"Codeforces Round 192 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1374327000,"relativeTimeSeconds":385388203},{"id":331,"name":"ABBYY Cup 3.0 - Finals (online version)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1374075000,"relativeTimeSeconds":385640203},{"id":324,"name":"ABBYY Cup 3.0 - Finals","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1374043200,"relativeTimeSeconds":385672003},{"id":325,"name":"MemSQL start[c]up Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1373734800,"relativeTimeSeconds":385980403},{"id":328,"name":"Testing Round 8","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":3600,"startTimeSeconds":1373662800,"relativeTimeSeconds":386052403},{"id":327,"name":"Codeforces Round 191 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1372941000,"relativeTimeSeconds":386774203},{"id":321,"name":"Codeforces Round 190 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1372433400,"relativeTimeSeconds":387281803},{"id":322,"name":"Codeforces Round 190 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1372433400,"relativeTimeSeconds":387281803},{"id":323,"name":"Testing Round 7","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":3600,"startTimeSeconds":1372363200,"relativeTimeSeconds":387352003},{"id":319,"name":"Codeforces Round 189 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1371992400,"relativeTimeSeconds":387722803},{"id":320,"name":"Codeforces Round 189 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1371992400,"relativeTimeSeconds":387722803},{"id":317,"name":"Codeforces Round 188 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1371223800,"relativeTimeSeconds":388491403},{"id":318,"name":"Codeforces Round 188 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1371223800,"relativeTimeSeconds":388491403},{"id":316,"name":"ABBYY Cup 3.0","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":14400,"startTimeSeconds":1371042000,"relativeTimeSeconds":388673203},{"id":314,"name":"Codeforces Round 187 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1370619000,"relativeTimeSeconds":389096203},{"id":315,"name":"Codeforces Round 187 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1370619000,"relativeTimeSeconds":389096203},{"id":313,"name":"Codeforces Round 186 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1369927800,"relativeTimeSeconds":389787403},{"id":311,"name":"Codeforces Round 185 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1369582200,"relativeTimeSeconds":390133003},{"id":312,"name":"Codeforces Round 185 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1369582200,"relativeTimeSeconds":390133003},{"id":305,"name":"Codeforces Round 184 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1368968400,"relativeTimeSeconds":390746803},{"id":309,"name":"Croc Champ 2013 - Finals (online version, Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1368803400,"relativeTimeSeconds":390911803},{"id":308,"name":"Croc Champ 2013 - Finals","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1368784800,"relativeTimeSeconds":390930403},{"id":303,"name":"Codeforces Round 183 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1368363600,"relativeTimeSeconds":391351603},{"id":304,"name":"Codeforces Round 183 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1368363600,"relativeTimeSeconds":391351603},{"id":306,"name":"Testing Round 6","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":6000,"startTimeSeconds":1368302400,"relativeTimeSeconds":391412803},{"id":301,"name":"Codeforces Round 182 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1367769900,"relativeTimeSeconds":391945303},{"id":302,"name":"Codeforces Round 182 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1367769900,"relativeTimeSeconds":391945303},{"id":300,"name":"Codeforces Round 181 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1366903800,"relativeTimeSeconds":392811403},{"id":293,"name":"Croc Champ 2013 - Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1366644900,"relativeTimeSeconds":393070303},{"id":299,"name":"Croc Champ 2013 - Round 2 (Div. 2 Edition)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1366644600,"relativeTimeSeconds":393070603},{"id":297,"name":"Codeforces Round 180 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1366385400,"relativeTimeSeconds":393329803},{"id":298,"name":"Codeforces Round 180 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1366385400,"relativeTimeSeconds":393329803},{"id":292,"name":"Croc Champ 2013 - Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1366040100,"relativeTimeSeconds":393675103},{"id":291,"name":"Croc Champ 2013 - Qualification Round","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":172800,"startTimeSeconds":1365796800,"relativeTimeSeconds":393918403},{"id":295,"name":"Codeforces Round 179 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1365694200,"relativeTimeSeconds":394021003},{"id":296,"name":"Codeforces Round 179 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1365694200,"relativeTimeSeconds":394021003},{"id":294,"name":"Codeforces Round 178 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1365348600,"relativeTimeSeconds":394366603},{"id":288,"name":"Codeforces Round 177 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1364916600,"relativeTimeSeconds":394798603},{"id":289,"name":"Codeforces Round 177 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1364916600,"relativeTimeSeconds":394798603},{"id":290,"name":"April Fools Day Contest 2013","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1364830200,"relativeTimeSeconds":394885003},{"id":286,"name":"Codeforces Round 176 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1364025600,"relativeTimeSeconds":395689603},{"id":287,"name":"Codeforces Round 176 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1364025600,"relativeTimeSeconds":395689603},{"id":285,"name":"Codeforces Round 175 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1363879800,"relativeTimeSeconds":395835403},{"id":283,"name":"Codeforces Round 174 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7500,"startTimeSeconds":1363534200,"relativeTimeSeconds":396181003},{"id":284,"name":"Codeforces Round 174 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7500,"startTimeSeconds":1363534200,"relativeTimeSeconds":396181003},{"id":282,"name":"Codeforces Round 173 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1363188600,"relativeTimeSeconds":396526603},{"id":280,"name":"Codeforces Round 172 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1362929400,"relativeTimeSeconds":396785803},{"id":281,"name":"Codeforces Round 172 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1362929400,"relativeTimeSeconds":396785803},{"id":279,"name":"Codeforces Round 171 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1362411000,"relativeTimeSeconds":397304203},{"id":277,"name":"Codeforces Round 170 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1362065400,"relativeTimeSeconds":397649803},{"id":278,"name":"Codeforces Round 170 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1362065400,"relativeTimeSeconds":397649803},{"id":276,"name":"Codeforces Round 169 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1361719800,"relativeTimeSeconds":397995403},{"id":274,"name":"Codeforces Round 168 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1361374200,"relativeTimeSeconds":398341003},{"id":275,"name":"Codeforces Round 168 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1361374200,"relativeTimeSeconds":398341003},{"id":273,"name":"Codeforces Round 167 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1360769400,"relativeTimeSeconds":398945803},{"id":272,"name":"Codeforces Round 167 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1360769400,"relativeTimeSeconds":398945803},{"id":271,"name":"Codeforces Round 166 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1360596600,"relativeTimeSeconds":399118603},{"id":269,"name":"Codeforces Round 165 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1359732600,"relativeTimeSeconds":399982603},{"id":270,"name":"Codeforces Round 165 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1359732600,"relativeTimeSeconds":399982603},{"id":268,"name":"Codeforces Round 164 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1359387000,"relativeTimeSeconds":400328203},{"id":266,"name":"Codeforces Round 163 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1358868600,"relativeTimeSeconds":400846603},{"id":264,"name":"Codeforces Round 162 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1358686800,"relativeTimeSeconds":401028403},{"id":265,"name":"Codeforces Round 162 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1358686800,"relativeTimeSeconds":401028403},{"id":263,"name":"Codeforces Round 161 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1358350200,"relativeTimeSeconds":401365003},{"id":261,"name":"Codeforces Round 160 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1358091000,"relativeTimeSeconds":401624203},{"id":262,"name":"Codeforces Round 160 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1358091000,"relativeTimeSeconds":401624203},{"id":267,"name":"Codeforces Testing Round 5","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":6300,"startTimeSeconds":1358002800,"relativeTimeSeconds":401712403},{"id":257,"name":"Codeforces Round 159 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1357659000,"relativeTimeSeconds":402056203},{"id":260,"name":"Codeforces Round 158 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1356622500,"relativeTimeSeconds":403092703},{"id":258,"name":"Codeforces Round 157 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1356190200,"relativeTimeSeconds":403525003},{"id":259,"name":"Codeforces Round 157 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1356190200,"relativeTimeSeconds":403525003},{"id":256,"name":"Codeforces Round 156 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1355671800,"relativeTimeSeconds":404043403},{"id":255,"name":"Codeforces Round 156 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1355671800,"relativeTimeSeconds":404043403},{"id":254,"name":"Codeforces Round 155 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1355047200,"relativeTimeSeconds":404668003},{"id":253,"name":"Codeforces Round 154 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1354960800,"relativeTimeSeconds":404754403},{"id":251,"name":"Codeforces Round 153 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1354807800,"relativeTimeSeconds":404907403},{"id":252,"name":"Codeforces Round 153 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1354807800,"relativeTimeSeconds":404907403},{"id":250,"name":"CROC-MBTU 2012, Final Round (Online version, Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1353938400,"relativeTimeSeconds":405776803},{"id":247,"name":"CROC-MBTU 2012, Final Round","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1353927300,"relativeTimeSeconds":405787903},{"id":249,"name":"Codeforces Round 152 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1353857400,"relativeTimeSeconds":405857803},{"id":248,"name":"Codeforces Round 152 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1353857400,"relativeTimeSeconds":405857803},{"id":246,"name":"Codeforces Round 151 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1353511800,"relativeTimeSeconds":406203403},{"id":245,"name":"CROC-MBTU 2012, Elimination Round (ACM-ICPC)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1353339000,"relativeTimeSeconds":406376203},{"id":243,"name":"Codeforces Round 150 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1353079800,"relativeTimeSeconds":406635403},{"id":244,"name":"Codeforces Round 150 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1353079800,"relativeTimeSeconds":406635403},{"id":242,"name":"Codeforces Round 149 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1352647800,"relativeTimeSeconds":407067403},{"id":238,"name":"Codeforces Round 148 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1352044800,"relativeTimeSeconds":407670403},{"id":239,"name":"Codeforces Round 148 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1352044800,"relativeTimeSeconds":407670403},{"id":241,"name":"Bayan 2012-2013 Elimination Round (ACM ICPC Rules, English statements)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1351783800,"relativeTimeSeconds":407931403},{"id":237,"name":"Codeforces Round 147 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1351179000,"relativeTimeSeconds":408536203},{"id":235,"name":"Codeforces Round 146 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1350803400,"relativeTimeSeconds":408911803},{"id":236,"name":"Codeforces Round 146 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1350803400,"relativeTimeSeconds":408911803},{"id":240,"name":"Codeforces Round 145 (Div. 1, ACM-ICPC Rules)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1350370800,"relativeTimeSeconds":409344403},{"id":234,"name":"Codeforces Round 145 (Div. 2, ACM-ICPC Rules)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":12600,"startTimeSeconds":1350370800,"relativeTimeSeconds":409344403},{"id":232,"name":"Codeforces Round 144 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1349969400,"relativeTimeSeconds":409745803},{"id":233,"name":"Codeforces Round 144 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1349969400,"relativeTimeSeconds":409745803},{"id":231,"name":"Codeforces Round 143 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1349623800,"relativeTimeSeconds":410091403},{"id":229,"name":"Codeforces Round 142 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7500,"startTimeSeconds":1349105400,"relativeTimeSeconds":410609803},{"id":230,"name":"Codeforces Round 142 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7500,"startTimeSeconds":1349105400,"relativeTimeSeconds":410609803},{"id":228,"name":"Codeforces Round 141 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1348759800,"relativeTimeSeconds":410955403},{"id":226,"name":"Codeforces Round 140 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1348500600,"relativeTimeSeconds":411214603},{"id":227,"name":"Codeforces Round 140 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1348500600,"relativeTimeSeconds":411214603},{"id":225,"name":"Codeforces Round 139 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1348069500,"relativeTimeSeconds":411645703},{"id":223,"name":"Codeforces Round 138 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1347809400,"relativeTimeSeconds":411905803},{"id":224,"name":"Codeforces Round 138 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1347809400,"relativeTimeSeconds":411905803},{"id":222,"name":"Codeforces Round 137 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1347291900,"relativeTimeSeconds":412423303},{"id":220,"name":"Codeforces Round 136 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1346427000,"relativeTimeSeconds":413288203},{"id":221,"name":"Codeforces Round 136 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1346427000,"relativeTimeSeconds":413288203},{"id":219,"name":"Codeforces Round 135 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1346081400,"relativeTimeSeconds":413633803},{"id":217,"name":"Codeforces Round 134 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1345273500,"relativeTimeSeconds":414441703},{"id":218,"name":"Codeforces Round 134 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1345273500,"relativeTimeSeconds":414441703},{"id":216,"name":"Codeforces Round 133 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1344958200,"relativeTimeSeconds":414757003},{"id":215,"name":"Codeforces Round 132 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1344267000,"relativeTimeSeconds":415448203},{"id":213,"name":"Codeforces Round 131 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1343662200,"relativeTimeSeconds":416053003},{"id":214,"name":"Codeforces Round 131 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1343662200,"relativeTimeSeconds":416053003},{"id":208,"name":"Codeforces Round 130 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7800,"startTimeSeconds":1343057400,"relativeTimeSeconds":416657803},{"id":212,"name":"VK Cup 2012 Finals (unofficial online-version)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1342450800,"relativeTimeSeconds":417264403},{"id":211,"name":"VK Cup 2012 Finals","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1342335600,"relativeTimeSeconds":417379603},{"id":209,"name":"VK Cup 2012 Finals, Practice Session","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":5400,"startTimeSeconds":1342252500,"relativeTimeSeconds":417462703},{"id":204,"name":"Codeforces Round 129 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1342020600,"relativeTimeSeconds":417694603},{"id":205,"name":"Codeforces Round 129 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1342020600,"relativeTimeSeconds":417694603},{"id":207,"name":"Abbyy Cup 2.0 - Final (unofficial)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1341730800,"relativeTimeSeconds":417984403},{"id":206,"name":"Abbyy Cup 2.0 - Final","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1341576900,"relativeTimeSeconds":418138303},{"id":203,"name":"Codeforces Round 128 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1341329400,"relativeTimeSeconds":418385803},{"id":201,"name":"Codeforces Round 127 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1340983800,"relativeTimeSeconds":418731403},{"id":202,"name":"Codeforces Round 127 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1340983800,"relativeTimeSeconds":418731403},{"id":200,"name":"Codeforces Round 126 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1340551800,"relativeTimeSeconds":419163403},{"id":198,"name":"Codeforces Round 125 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1340379000,"relativeTimeSeconds":419336203},{"id":199,"name":"Codeforces Round 125 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1340379000,"relativeTimeSeconds":419336203},{"id":196,"name":"Codeforces Round 124 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1339506000,"relativeTimeSeconds":420209203},{"id":197,"name":"Codeforces Round 124 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1339506000,"relativeTimeSeconds":420209203},{"id":195,"name":"Codeforces Round 123 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1339342200,"relativeTimeSeconds":420373003},{"id":193,"name":"Codeforces Round 122 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1338737400,"relativeTimeSeconds":420977803},{"id":194,"name":"Codeforces Round 122 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1338737400,"relativeTimeSeconds":420977803},{"id":191,"name":"Codeforces Round 121 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1338132600,"relativeTimeSeconds":421582603},{"id":192,"name":"Codeforces Round 121 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1338132600,"relativeTimeSeconds":421582603},{"id":188,"name":"Surprise Language Round 6","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1337959800,"relativeTimeSeconds":421755403},{"id":190,"name":"Codeforces Round 120 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1337182200,"relativeTimeSeconds":422533003},{"id":187,"name":"Codeforces Round 119 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1336663800,"relativeTimeSeconds":423051403},{"id":189,"name":"Codeforces Round 119 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1336663800,"relativeTimeSeconds":423051403},{"id":185,"name":"Codeforces Round 118 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1336145400,"relativeTimeSeconds":423569803},{"id":186,"name":"Codeforces Round 118 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1336145400,"relativeTimeSeconds":423569803},{"id":178,"name":"ABBYY Cup 2.0 - Hard","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1335614400,"relativeTimeSeconds":424100803},{"id":183,"name":"Croc Champ 2012 - Final","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1335532800,"relativeTimeSeconds":424182403},{"id":182,"name":"Codeforces Round 117 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1335280200,"relativeTimeSeconds":424435003},{"id":180,"name":"Codeforces Round 116 (Div. 2, ACM-ICPC Rules)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1335078000,"relativeTimeSeconds":424637203},{"id":177,"name":"ABBYY Cup 2.0 - Easy","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":14400,"startTimeSeconds":1335016800,"relativeTimeSeconds":424698401},{"id":176,"name":"Croc Champ 2012 - Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1334934300,"relativeTimeSeconds":424780903},{"id":181,"name":"Croc Champ 2012 - Round 2 (Unofficial Div. 2 Edition)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1334934300,"relativeTimeSeconds":424780903},{"id":175,"name":"Codeforces Round 115","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1334390400,"relativeTimeSeconds":425324803},{"id":164,"name":"VK Cup 2012 Round 3","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1333897500,"relativeTimeSeconds":425817703},{"id":174,"name":"VK Cup 2012 Round 3 (Unofficial Div. 2 Edition)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1333897500,"relativeTimeSeconds":425817703},{"id":173,"name":"Croc Champ 2012 - Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1333724400,"relativeTimeSeconds":425990803},{"id":172,"name":"Croc Champ 2012 - Qualification Round","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":86400,"startTimeSeconds":1333440000,"relativeTimeSeconds":426275203},{"id":171,"name":"April Fools Day Contest","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1333292400,"relativeTimeSeconds":426422803},{"id":170,"name":"VK Cup 2012 Wild-card Round 2","type":"IOI","phase":"FINISHED","frozen":false,"durationSeconds":604800,"startTimeSeconds":1332954000,"relativeTimeSeconds":426761203},{"id":167,"name":"Codeforces Round 114 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1332860400,"relativeTimeSeconds":426854803},{"id":168,"name":"Codeforces Round 114 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1332860400,"relativeTimeSeconds":426854803},{"id":163,"name":"VK Cup 2012 Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1332687900,"relativeTimeSeconds":427027303},{"id":169,"name":"VK Cup 2012 Round 2 (Unofficial Div. 2 Edition)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1332687900,"relativeTimeSeconds":427027303},{"id":166,"name":"Codeforces Round 113 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1332516600,"relativeTimeSeconds":427198603},{"id":162,"name":"VK Cup 2012 Wild-card Round 1","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1332083400,"relativeTimeSeconds":427631803},{"id":165,"name":"Codeforces Round 112 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1331911800,"relativeTimeSeconds":427803403},{"id":161,"name":"VK Cup 2012 Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1331478300,"relativeTimeSeconds":428236903},{"id":159,"name":"VK Cup 2012 Qualification Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":86400,"startTimeSeconds":1331280000,"relativeTimeSeconds":428435203},{"id":160,"name":"Codeforces Round 111 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1331046000,"relativeTimeSeconds":428669203},{"id":158,"name":"VK Cup 2012 Qualification Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":86400,"startTimeSeconds":1330804800,"relativeTimeSeconds":428910403},{"id":156,"name":"Codeforces Round 110 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1330536600,"relativeTimeSeconds":429178603},{"id":157,"name":"Codeforces Round 110 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1330536600,"relativeTimeSeconds":429178603},{"id":154,"name":"Codeforces Round 109 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1330095600,"relativeTimeSeconds":429619603},{"id":155,"name":"Codeforces Round 109 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1330095600,"relativeTimeSeconds":429619603},{"id":153,"name":"Surprise Language Round 5","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1329922800,"relativeTimeSeconds":429792403},{"id":152,"name":"Codeforces Round 108 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1329750000,"relativeTimeSeconds":429965203},{"id":150,"name":"Codeforces Round 107 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1329490800,"relativeTimeSeconds":430224403},{"id":151,"name":"Codeforces Round 107 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1329490800,"relativeTimeSeconds":430224403},{"id":149,"name":"Codeforces Round 106 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1328886000,"relativeTimeSeconds":430829203},{"id":148,"name":"Codeforces Round 105 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1328198400,"relativeTimeSeconds":431516803},{"id":145,"name":"Codeforces Round 104 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1327215600,"relativeTimeSeconds":432499603},{"id":146,"name":"Codeforces Round 104 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1327215600,"relativeTimeSeconds":432499603},{"id":144,"name":"Codeforces Round 103 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1326899100,"relativeTimeSeconds":432816103},{"id":142,"name":"Codeforces Round 102 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1326380700,"relativeTimeSeconds":433334503},{"id":143,"name":"Codeforces Round 102 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1326380700,"relativeTimeSeconds":433334503},{"id":141,"name":"Codeforces Round 101 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1326034800,"relativeTimeSeconds":433680403},{"id":140,"name":"Codeforces Round 100","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1325689200,"relativeTimeSeconds":434026003},{"id":147,"name":"Codeforces Testing Round 4","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":3600,"startTimeSeconds":1325602800,"relativeTimeSeconds":434112403},{"id":138,"name":"Codeforces Beta Round 99 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1324728000,"relativeTimeSeconds":434987203},{"id":139,"name":"Codeforces Beta Round 99 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1324728000,"relativeTimeSeconds":434987203},{"id":137,"name":"Codeforces Beta Round 98 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1324015200,"relativeTimeSeconds":435700003},{"id":135,"name":"Codeforces Beta Round 97 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1323443100,"relativeTimeSeconds":436272103},{"id":136,"name":"Codeforces Beta Round 97 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1323443100,"relativeTimeSeconds":436272103},{"id":132,"name":"Codeforces Beta Round 96 (Div. 1)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1322924400,"relativeTimeSeconds":436790803},{"id":133,"name":"Codeforces Beta Round 96 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1322924400,"relativeTimeSeconds":436790803},{"id":134,"name":"Codeforces Testing Round 3","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":3600,"startTimeSeconds":1322838000,"relativeTimeSeconds":436877203},{"id":131,"name":"Codeforces Beta Round 95 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1322233200,"relativeTimeSeconds":437482003},{"id":130,"name":"Unknown Language Round 4","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1321801200,"relativeTimeSeconds":437914003},{"id":128,"name":"Codeforces Beta Round 94 (Div. 1 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1321337400,"relativeTimeSeconds":438377803},{"id":129,"name":"Codeforces Beta Round 94 (Div. 2 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1321337400,"relativeTimeSeconds":438377803},{"id":126,"name":"Codeforces Beta Round 93 (Div. 1 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1320858000,"relativeTimeSeconds":438857203},{"id":127,"name":"Codeforces Beta Round 93 (Div. 2 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1320858000,"relativeTimeSeconds":438857203},{"id":123,"name":"Codeforces Beta Round 92 (Div. 1 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1320333000,"relativeTimeSeconds":439382203},{"id":124,"name":"Codeforces Beta Round 92 (Div. 2 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1320333000,"relativeTimeSeconds":439382203},{"id":125,"name":"Codeforces Testing Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1319893200,"relativeTimeSeconds":439822003},{"id":121,"name":"Codeforces Beta Round 91 (Div. 1 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1319727600,"relativeTimeSeconds":439987603},{"id":122,"name":"Codeforces Beta Round 91 (Div. 2 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1319727600,"relativeTimeSeconds":439987603},{"id":120,"name":"School Regional Team Contest, Saratov, 2011","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1318919400,"relativeTimeSeconds":440795803},{"id":119,"name":"Codeforces Beta Round 90","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1318604400,"relativeTimeSeconds":441110803},{"id":118,"name":"Codeforces Beta Round 89 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1317999600,"relativeTimeSeconds":441715603},{"id":117,"name":"Codeforces Beta Round 88","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1316790000,"relativeTimeSeconds":442925203},{"id":115,"name":"Codeforces Beta Round 87 (Div. 1 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1316098800,"relativeTimeSeconds":443616403},{"id":116,"name":"Codeforces Beta Round 87 (Div. 2 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1316098800,"relativeTimeSeconds":443616403},{"id":113,"name":"Codeforces Beta Round 86 (Div. 1 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1315494000,"relativeTimeSeconds":444221203},{"id":114,"name":"Codeforces Beta Round 86 (Div. 2 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1315494000,"relativeTimeSeconds":444221203},{"id":111,"name":"Codeforces Beta Round 85 (Div. 1 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1315051200,"relativeTimeSeconds":444664003},{"id":112,"name":"Codeforces Beta Round 85 (Div. 2 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1315051200,"relativeTimeSeconds":444664003},{"id":109,"name":"Codeforces Beta Round 84 (Div. 1 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1314633600,"relativeTimeSeconds":445081603},{"id":110,"name":"Codeforces Beta Round 84 (Div. 2 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1314633600,"relativeTimeSeconds":445081603},{"id":107,"name":"Codeforces Beta Round 83 (Div. 1 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1314111600,"relativeTimeSeconds":445603603},{"id":108,"name":"Codeforces Beta Round 83 (Div. 2 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1314111600,"relativeTimeSeconds":445603603},{"id":106,"name":"Codeforces Beta Round 82 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1313766000,"relativeTimeSeconds":445949203},{"id":105,"name":"Codeforces Beta Round 81","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1313247600,"relativeTimeSeconds":446467603},{"id":103,"name":"Codeforces Beta Round 80 (Div. 1 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1312714800,"relativeTimeSeconds":447000403},{"id":104,"name":"Codeforces Beta Round 80 (Div. 2 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1312714800,"relativeTimeSeconds":447000403},{"id":101,"name":"Codeforces Beta Round 79 (Div. 1 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1312390800,"relativeTimeSeconds":447324403},{"id":102,"name":"Codeforces Beta Round 79 (Div. 2 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1312390800,"relativeTimeSeconds":447324403},{"id":100,"name":"Unknown Language Round 3","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1312005600,"relativeTimeSeconds":447709603},{"id":98,"name":"Codeforces Beta Round 78 (Div. 1 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1311346800,"relativeTimeSeconds":448368403},{"id":99,"name":"Codeforces Beta Round 78 (Div. 2 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1311346800,"relativeTimeSeconds":448368403},{"id":97,"name":"Yandex.Algorithm 2011: Finals","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1310731200,"relativeTimeSeconds":448984003},{"id":95,"name":"Codeforces Beta Round 77 (Div. 1 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1310137200,"relativeTimeSeconds":449578003},{"id":96,"name":"Codeforces Beta Round 77 (Div. 2 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1310137200,"relativeTimeSeconds":449578003},{"id":93,"name":"Codeforces Beta Round 76 (Div. 1 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1309446000,"relativeTimeSeconds":450269203},{"id":94,"name":"Codeforces Beta Round 76 (Div. 2 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1309446000,"relativeTimeSeconds":450269203},{"id":91,"name":"Codeforces Beta Round 75 (Div. 1 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1308582000,"relativeTimeSeconds":451133203},{"id":92,"name":"Codeforces Beta Round 75 (Div. 2 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1308582000,"relativeTimeSeconds":451133203},{"id":89,"name":"Codeforces Beta Round 74 (Div. 1 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1308236400,"relativeTimeSeconds":451478803},{"id":90,"name":"Codeforces Beta Round 74 (Div. 2 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1308236400,"relativeTimeSeconds":451478803},{"id":87,"name":"Codeforces Beta Round 73 (Div. 1 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1307458800,"relativeTimeSeconds":452256403},{"id":88,"name":"Codeforces Beta Round 73 (Div. 2 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1307458800,"relativeTimeSeconds":452256403},{"id":86,"name":"Yandex.Algorithm 2011: Round 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1306077000,"relativeTimeSeconds":453638203},{"id":85,"name":"Yandex.Algorithm 2011: Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1305903600,"relativeTimeSeconds":453811603},{"id":83,"name":"Codeforces Beta Round 72 (Div. 1 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1305299400,"relativeTimeSeconds":454415803},{"id":84,"name":"Codeforces Beta Round 72 (Div. 2 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1305299400,"relativeTimeSeconds":454415803},{"id":82,"name":"Yandex.Algorithm 2011: Qualification 2","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1304694000,"relativeTimeSeconds":455021203},{"id":81,"name":"Yandex.Algorithm Open 2011: Qualification 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1304485200,"relativeTimeSeconds":455230003},{"id":79,"name":"Codeforces Beta Round 71","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1304175600,"relativeTimeSeconds":455539603},{"id":78,"name":"Codeforces Beta Round 70 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1303916400,"relativeTimeSeconds":455798803},{"id":77,"name":"Codeforces Beta Round 69 (Div. 1 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1303226100,"relativeTimeSeconds":456489103},{"id":80,"name":"Codeforces Beta Round 69 (Div. 2 Only)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1303226100,"relativeTimeSeconds":456489103},{"id":74,"name":"Codeforces Beta Round 68","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1302879600,"relativeTimeSeconds":456835603},{"id":75,"name":"Codeforces Beta Round 67 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1302706800,"relativeTimeSeconds":457008403},{"id":76,"name":"All-Ukrainian School Olympiad in Informatics","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1302609600,"relativeTimeSeconds":457105603},{"id":73,"name":"Codeforces Beta Round 66","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1302422400,"relativeTimeSeconds":457292803},{"id":71,"name":"Codeforces Beta Round 65 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1301410800,"relativeTimeSeconds":458304403},{"id":70,"name":"Codeforces Beta Round 64","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1301155200,"relativeTimeSeconds":458560003},{"id":69,"name":"Codeforces Beta Round 63 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1300809600,"relativeTimeSeconds":458905603},{"id":72,"name":"Unknown Language Round 2","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1300637400,"relativeTimeSeconds":459077803},{"id":68,"name":"Codeforces Beta Round 62","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1300464000,"relativeTimeSeconds":459251203},{"id":67,"name":"Manthan 2011","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1300033800,"relativeTimeSeconds":459681403},{"id":66,"name":"Codeforces Beta Round 61 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1299513600,"relativeTimeSeconds":460201603},{"id":65,"name":"Codeforces Beta Round 60","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1299340800,"relativeTimeSeconds":460374403},{"id":63,"name":"Codeforces Beta Round 59 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1298908800,"relativeTimeSeconds":460806403},{"id":62,"name":"Codeforces Beta Round 58","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1298649600,"relativeTimeSeconds":461065603},{"id":61,"name":"Codeforces Beta Round 57 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1298390400,"relativeTimeSeconds":461324803},{"id":64,"name":"Unknown Language Round 1","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1298304000,"relativeTimeSeconds":461411203},{"id":60,"name":"Codeforces Beta Round 56","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1298131200,"relativeTimeSeconds":461584003},{"id":59,"name":"Codeforces Beta Round 55 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1297440000,"relativeTimeSeconds":462275203},{"id":58,"name":"Codeforces Beta Round 54 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1296489600,"relativeTimeSeconds":463225603},{"id":57,"name":"Codeforces Beta Round 53","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1295971200,"relativeTimeSeconds":463744003},{"id":56,"name":"Codeforces Beta Round 52 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1295626200,"relativeTimeSeconds":464089003},{"id":55,"name":"Codeforces Beta Round 51","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1294992000,"relativeTimeSeconds":464723203},{"id":54,"name":"Codeforces Beta Round 50","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1294733700,"relativeTimeSeconds":464981503},{"id":53,"name":"Codeforces Beta Round 49 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1294329600,"relativeTimeSeconds":465385603},{"id":52,"name":"Codeforces Testing Round 1","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":3600,"startTimeSeconds":1294160400,"relativeTimeSeconds":465554803},{"id":51,"name":"Codeforces Beta Round 48","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":9000,"startTimeSeconds":1293552000,"relativeTimeSeconds":466163203},{"id":50,"name":"Codeforces Beta Round 47","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1292862000,"relativeTimeSeconds":466853203},{"id":49,"name":"Codeforces Beta Round 46 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1292601600,"relativeTimeSeconds":467113603},{"id":48,"name":"School Personal Contest #3 (Winter Computer School 2010/11) - Codeforces Beta Round 45 (ACM-ICPC Rules)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1292140800,"relativeTimeSeconds":467574403},{"id":47,"name":"Codeforces Beta Round 44 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1291737600,"relativeTimeSeconds":467977603},{"id":46,"name":"School Personal Contest #2 (Winter Computer School 2010/11) - Codeforces Beta Round 43 (ACM-ICPC Rules)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":10800,"startTimeSeconds":1291536000,"relativeTimeSeconds":468179203},{"id":43,"name":"Codeforces Beta Round 42 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1291046400,"relativeTimeSeconds":468668803},{"id":42,"name":"Codeforces Beta Round 41","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1290096000,"relativeTimeSeconds":469619203},{"id":45,"name":"School Team Contest 3 (Winter Computer School 2010/11)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1289646000,"relativeTimeSeconds":470069203},{"id":41,"name":"Codeforces Beta Round 40 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1289232000,"relativeTimeSeconds":470483203},{"id":44,"name":"School Team Contest 2 (Winter Computer School 2010/11)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1289041200,"relativeTimeSeconds":470674003},{"id":40,"name":"Codeforces Beta Round 39","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1288972800,"relativeTimeSeconds":470742403},{"id":38,"name":"School Personal Contest #1 (Winter Computer School 2010/11) - Codeforces Beta Round 38 (ACM-ICPC Rules)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":14400,"startTimeSeconds":1288440000,"relativeTimeSeconds":471275203},{"id":37,"name":"Codeforces Beta Round 37","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1288018800,"relativeTimeSeconds":471696403},{"id":39,"name":"School Team Contest 1 (Winter Computer School 2010/11)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":18000,"startTimeSeconds":1287904200,"relativeTimeSeconds":471811003},{"id":36,"name":"Codeforces Beta Round 36","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1287482400,"relativeTimeSeconds":472232803},{"id":35,"name":"Codeforces Beta Round 35 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1287471600,"relativeTimeSeconds":472243603},{"id":34,"name":"Codeforces Beta Round 34 (Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1286802000,"relativeTimeSeconds":472913203},{"id":33,"name":"Codeforces Beta Round 33 (Codeforces format)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1286463600,"relativeTimeSeconds":473251603},{"id":32,"name":"Codeforces Beta Round 32 (Div. 2, Codeforces format)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1286002800,"relativeTimeSeconds":473712403},{"id":31,"name":"Codeforces Beta Round 31 (Div. 2, Codeforces format)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1285599600,"relativeTimeSeconds":474115603},{"id":30,"name":"Codeforces Beta Round 30 (Codeforces format)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1285340400,"relativeTimeSeconds":474374803},{"id":29,"name":"Codeforces Beta Round 29 (Div. 2, Codeforces format)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1284994800,"relativeTimeSeconds":474720403},{"id":28,"name":"Codeforces Beta Round 28 (Codeforces format)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1284735600,"relativeTimeSeconds":474979603},{"id":27,"name":"Codeforces Beta Round 27 (Codeforces format, Div. 2)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1284130800,"relativeTimeSeconds":475584403},{"id":26,"name":"Codeforces Beta Round 26 (Codeforces format)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1281970800,"relativeTimeSeconds":477744403},{"id":25,"name":"Codeforces Beta Round 25 (Div. 2 Only)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1280761200,"relativeTimeSeconds":478954003},{"id":24,"name":"Codeforces Beta Round 24","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1280149200,"relativeTimeSeconds":479566003},{"id":23,"name":"Codeforces Beta Round 23","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1278687600,"relativeTimeSeconds":481027603},{"id":22,"name":"Codeforces Beta Round 22 (Div. 2 Only)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1277823600,"relativeTimeSeconds":481891601},{"id":21,"name":"Codeforces Alpha Round 21 (Codeforces format)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1277730300,"relativeTimeSeconds":481984903},{"id":19,"name":"Codeforces Beta Round 19","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1277391600,"relativeTimeSeconds":482323601},{"id":20,"name":"Codeforces Alpha Round 20 (Codeforces format)","type":"CF","phase":"FINISHED","frozen":false,"durationSeconds":5400,"startTimeSeconds":1276875000,"relativeTimeSeconds":482840203},{"id":18,"name":"Codeforces Beta Round 18 (Div. 2 Only)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1276700400,"relativeTimeSeconds":483014803},{"id":17,"name":"Codeforces Beta Round 17","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1276182000,"relativeTimeSeconds":483533203},{"id":16,"name":"Codeforces Beta Round 16 (Div. 2 Only)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1275570000,"relativeTimeSeconds":484145203},{"id":15,"name":"Codeforces Beta Round 15","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":8100,"startTimeSeconds":1275145200,"relativeTimeSeconds":484570003},{"id":14,"name":"Codeforces Beta Round 14 (Div. 2)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1274283000,"relativeTimeSeconds":485432203},{"id":13,"name":"Codeforces Beta Round 13","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1273154400,"relativeTimeSeconds":486560803},{"id":12,"name":"Codeforces Beta Round 12 (Div 2 Only)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1272538800,"relativeTimeSeconds":487176403},{"id":11,"name":"Codeforces Beta Round 11","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1272294000,"relativeTimeSeconds":487421203},{"id":10,"name":"Codeforces Beta Round 10","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1271346300,"relativeTimeSeconds":488368903},{"id":9,"name":"Codeforces Beta Round 9 (Div. 2 Only)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1270983600,"relativeTimeSeconds":488731603},{"id":8,"name":"Codeforces Beta Round 8","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1270741500,"relativeTimeSeconds":488973703},{"id":7,"name":"Codeforces Beta Round 7","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1270136700,"relativeTimeSeconds":489578503},{"id":6,"name":"Codeforces Beta Round 6 (Div. 2 Only)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1269673200,"relativeTimeSeconds":490042003},{"id":5,"name":"Codeforces Beta Round 5","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1269100800,"relativeTimeSeconds":490614403},{"id":4,"name":"Codeforces Beta Round 4 (Div. 2 Only)","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1268395200,"relativeTimeSeconds":491320003},{"id":3,"name":"Codeforces Beta Round 3","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1267963200,"relativeTimeSeconds":491752003},{"id":2,"name":"Codeforces Beta Round 2","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1267117200,"relativeTimeSeconds":492598003},{"id":1,"name":"Codeforces Beta Round 1","type":"ICPC","phase":"FINISHED","frozen":false,"durationSeconds":7200,"startTimeSeconds":1266580800,"relativeTimeSeconds":493134403}]}
+ + diff --git a/tests/fixtures/cses_contests.html b/tests/fixtures/cses_contests.html new file mode 100644 index 0000000..1106f5a --- /dev/null +++ b/tests/fixtures/cses_contests.html @@ -0,0 +1,43 @@ + + + + + + + + + + + + + +
+
+ + + + +
+ + + Dark mode +
+
+
+
+ +
+
+CSES - CSES Problem Set - Tasks

General

Introductory Problems

Sorting and Searching

Dynamic Programming

Graph Algorithms

Range Queries

Tree Algorithms

Mathematics

String Algorithms

Geometry

Advanced Techniques

Sliding Window Problems

Interactive Problems

Bitwise Operations

Construction Problems

Advanced Graph Problems

Counting Problems

Additional Problems I

Additional Problems II

+
+
+ + diff --git a/tests/fixtures/cses_task_1068.html b/tests/fixtures/cses_task_1068.html new file mode 100644 index 0000000..8bd0358 --- /dev/null +++ b/tests/fixtures/cses_task_1068.html @@ -0,0 +1,156 @@ + + + + + + + + + + + + + +
+
+ + + + +
+ + + Dark mode +
+
+
+
+ + +
+
+ CSES - Weird Algorithm + + + + +
    +
  • Time limit: 1.00 s
  • +
  • Memory limit: 512 MB
  • +
+
+

+ Consider an algorithm that takes as input a positive integer + n. If + n is even, the algorithm + divides it by two, and if + n is odd, the algorithm + multiplies it by three and adds one. The algorithm repeats this, + until n is one. For example, + the sequence for n=3 is as + follows: + + 3 \rightarrow 10 \rightarrow 5 \rightarrow 16 \rightarrow 8 + \rightarrow 4 \rightarrow 2 \rightarrow 1 + Your task is to simulate the execution of the algorithm for a + given value of n. +

+

Input

+

+ The only input line contains an integer + n. +

+

Output

+

+ Print a line that contains all values of + n during the algorithm. +

+

Constraints

+
    +
  • 1 \le n \le 10^6
  • +
+

Example

+

Input:

+
+3
+
+

Output:

+
+3 10 5 16 8 4 2 1
+
+
+
+ +
+
+ + diff --git a/tests/fixtures/cses_task_1621.html b/tests/fixtures/cses_task_1621.html new file mode 100644 index 0000000..291a12c --- /dev/null +++ b/tests/fixtures/cses_task_1621.html @@ -0,0 +1,150 @@ + + + + + + + + + + + + + +
+
+ + + + +
+ + + Dark mode +
+
+
+
+ + +
+
+ CSES - Distinct Numbers + + + + +
    +
  • Time limit: 1.00 s
  • +
  • Memory limit: 512 MB
  • +
+
+

+ You are given a list of + n integers, and your task is + to calculate the number of distinct values in the list. +

+

Input

+

+ The first input line has an integer + n: the number of values. +

+

+ The second line has + n integers + x_1,x_2,\dots,x_n. +

+

Output

+

Print one integers: the number of distinct values.

+

Constraints

+
    +
  • + 1 \le n \le 2 \cdot 10^5 +
  • +
  • 1 \le x_i \le 10^9
  • +
+

Example

+

Input:

+
+5
+2 3 2 2 3
+
+

Output:

+
+2
+
+
+
+ +
+
+ + diff --git a/tests/scrapers/test_filler.py b/tests/scrapers/test_filler.py deleted file mode 100644 index b0f1978..0000000 --- a/tests/scrapers/test_filler.py +++ /dev/null @@ -1,2 +0,0 @@ -def test(): - assert 5 == 5 diff --git a/tests/test_scrapers.py b/tests/test_scrapers.py new file mode 100644 index 0000000..83847ca --- /dev/null +++ b/tests/test_scrapers.py @@ -0,0 +1,69 @@ +import pytest + +from scrapers.models import ( + ContestListResult, + MetadataResult, + TestsResult, +) + +MODEL_FOR_MODE = { + "metadata": MetadataResult, + "contests": ContestListResult, +} + +MATRIX = { + "cses": { + "metadata": ("introductory_problems",), + "tests": ("introductory_problems",), + "contests": tuple(), + }, + "atcoder": { + "metadata": ("abc100",), + "tests": ("abc100",), + "contests": tuple(), + }, + "codeforces": { + "metadata": ("1550",), + "tests": ("1550",), + "contests": tuple(), + }, +} + + +@pytest.mark.parametrize("scraper", MATRIX.keys()) +@pytest.mark.parametrize("mode", ["metadata", "tests", "contests"]) +def test_scraper_offline_fixture_matrix(run_scraper_offline, scraper, mode): + args = MATRIX[scraper][mode] + rc, objs = run_scraper_offline(scraper, mode, *args) + assert rc in (0, 1), f"Bad exit code {rc}" + assert objs, f"No JSON output for {scraper}:{mode}" + + if mode in ("metadata", "contests"): + Model = MODEL_FOR_MODE[mode] + model = Model.model_validate(objs[-1]) + assert model is not None + if mode == "metadata": + assert model.success in (True, False) + if model.success: + assert len(model.problems) >= 1 + assert all(isinstance(p.id, str) and p.id for p in model.problems) + else: + assert model.success in (True, False) + if model.success: + assert len(model.contests) >= 1 + else: + validated_any = False + for obj in objs: + if "success" in obj and "tests" in obj and "problem_id" in obj: + tr = TestsResult.model_validate(obj) + assert tr.problem_id != "" + assert isinstance(tr.tests, list) + validated_any = True + else: + assert "problem_id" in obj + assert "tests" in obj and isinstance(obj["tests"], list) + assert ( + "timeout_ms" in obj and "memory_mb" in obj and "interactive" in obj + ) + validated_any = True + assert validated_any, "No valid tests payloads validated" diff --git a/uv.lock b/uv.lock index 58a9d1b..bc46366 100644 --- a/uv.lock +++ b/uv.lock @@ -92,6 +92,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, ] +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + [[package]] name = "anyio" version = "4.11.0" @@ -1299,6 +1308,86 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, ] +[[package]] +name = "pydantic" +version = "2.11.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/54/ecab642b3bed45f7d5f59b38443dcb36ef50f85af192e6ece103dbfe9587/pydantic-2.11.10.tar.gz", hash = "sha256:dc280f0982fbda6c38fada4e476dc0a4f3aeaf9c6ad4c28df68a666ec3c61423", size = 788494, upload-time = "2025-10-04T10:40:41.338Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/1f/73c53fcbfb0b5a78f91176df41945ca466e71e9d9d836e5c522abda39ee7/pydantic-2.11.10-py3-none-any.whl", hash = "sha256:802a655709d49bd004c31e865ef37da30b540786a46bfce02333e0e24b5fe29a", size = 444823, upload-time = "2025-10-04T10:40:39.055Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.33.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/8d/71db63483d518cbbf290261a1fc2839d17ff89fce7089e08cad07ccfce67/pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7", size = 2028584, upload-time = "2025-04-23T18:31:03.106Z" }, + { url = "https://files.pythonhosted.org/packages/24/2f/3cfa7244ae292dd850989f328722d2aef313f74ffc471184dc509e1e4e5a/pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246", size = 1855071, upload-time = "2025-04-23T18:31:04.621Z" }, + { url = "https://files.pythonhosted.org/packages/b3/d3/4ae42d33f5e3f50dd467761304be2fa0a9417fbf09735bc2cce003480f2a/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f", size = 1897823, upload-time = "2025-04-23T18:31:06.377Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f3/aa5976e8352b7695ff808599794b1fba2a9ae2ee954a3426855935799488/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc", size = 1983792, upload-time = "2025-04-23T18:31:07.93Z" }, + { url = "https://files.pythonhosted.org/packages/d5/7a/cda9b5a23c552037717f2b2a5257e9b2bfe45e687386df9591eff7b46d28/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de", size = 2136338, upload-time = "2025-04-23T18:31:09.283Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9f/b8f9ec8dd1417eb9da784e91e1667d58a2a4a7b7b34cf4af765ef663a7e5/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a", size = 2730998, upload-time = "2025-04-23T18:31:11.7Z" }, + { url = "https://files.pythonhosted.org/packages/47/bc/cd720e078576bdb8255d5032c5d63ee5c0bf4b7173dd955185a1d658c456/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef", size = 2003200, upload-time = "2025-04-23T18:31:13.536Z" }, + { url = "https://files.pythonhosted.org/packages/ca/22/3602b895ee2cd29d11a2b349372446ae9727c32e78a94b3d588a40fdf187/pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e", size = 2113890, upload-time = "2025-04-23T18:31:15.011Z" }, + { url = "https://files.pythonhosted.org/packages/ff/e6/e3c5908c03cf00d629eb38393a98fccc38ee0ce8ecce32f69fc7d7b558a7/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d", size = 2073359, upload-time = "2025-04-23T18:31:16.393Z" }, + { url = "https://files.pythonhosted.org/packages/12/e7/6a36a07c59ebefc8777d1ffdaf5ae71b06b21952582e4b07eba88a421c79/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30", size = 2245883, upload-time = "2025-04-23T18:31:17.892Z" }, + { url = "https://files.pythonhosted.org/packages/16/3f/59b3187aaa6cc0c1e6616e8045b284de2b6a87b027cce2ffcea073adf1d2/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf", size = 2241074, upload-time = "2025-04-23T18:31:19.205Z" }, + { url = "https://files.pythonhosted.org/packages/e0/ed/55532bb88f674d5d8f67ab121a2a13c385df382de2a1677f30ad385f7438/pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51", size = 1910538, upload-time = "2025-04-23T18:31:20.541Z" }, + { url = "https://files.pythonhosted.org/packages/fe/1b/25b7cccd4519c0b23c2dd636ad39d381abf113085ce4f7bec2b0dc755eb1/pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab", size = 1952909, upload-time = "2025-04-23T18:31:22.371Z" }, + { url = "https://files.pythonhosted.org/packages/49/a9/d809358e49126438055884c4366a1f6227f0f84f635a9014e2deb9b9de54/pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65", size = 1897786, upload-time = "2025-04-23T18:31:24.161Z" }, + { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" }, + { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" }, + { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" }, + { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" }, + { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" }, + { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" }, + { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" }, + { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" }, + { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" }, + { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" }, + { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" }, + { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" }, + { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" }, + { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" }, + { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" }, + { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" }, + { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" }, + { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" }, + { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" }, + { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" }, + { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" }, + { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" }, + { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" }, + { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" }, + { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" }, + { url = "https://files.pythonhosted.org/packages/7b/27/d4ae6487d73948d6f20dddcd94be4ea43e74349b56eba82e9bdee2d7494c/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8", size = 2025200, upload-time = "2025-04-23T18:33:14.199Z" }, + { url = "https://files.pythonhosted.org/packages/f1/b8/b3cb95375f05d33801024079b9392a5ab45267a63400bf1866e7ce0f0de4/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593", size = 1859123, upload-time = "2025-04-23T18:33:16.555Z" }, + { url = "https://files.pythonhosted.org/packages/05/bc/0d0b5adeda59a261cd30a1235a445bf55c7e46ae44aea28f7bd6ed46e091/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612", size = 1892852, upload-time = "2025-04-23T18:33:18.513Z" }, + { url = "https://files.pythonhosted.org/packages/3e/11/d37bdebbda2e449cb3f519f6ce950927b56d62f0b84fd9cb9e372a26a3d5/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7", size = 2067484, upload-time = "2025-04-23T18:33:20.475Z" }, + { url = "https://files.pythonhosted.org/packages/8c/55/1f95f0a05ce72ecb02a8a8a1c3be0579bbc29b1d5ab68f1378b7bebc5057/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e", size = 2108896, upload-time = "2025-04-23T18:33:22.501Z" }, + { url = "https://files.pythonhosted.org/packages/53/89/2b2de6c81fa131f423246a9109d7b2a375e83968ad0800d6e57d0574629b/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8", size = 2069475, upload-time = "2025-04-23T18:33:24.528Z" }, + { url = "https://files.pythonhosted.org/packages/b8/e9/1f7efbe20d0b2b10f6718944b5d8ece9152390904f29a78e68d4e7961159/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf", size = 2239013, upload-time = "2025-04-23T18:33:26.621Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b2/5309c905a93811524a49b4e031e9851a6b00ff0fb668794472ea7746b448/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb", size = 2238715, upload-time = "2025-04-23T18:33:28.656Z" }, + { url = "https://files.pythonhosted.org/packages/32/56/8a7ca5d2cd2cda1d245d34b1c9a942920a718082ae8e54e5f3e5a58b7add/pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1", size = 2066757, upload-time = "2025-04-23T18:33:30.645Z" }, +] + [[package]] name = "pyee" version = "13.0.0" @@ -1460,6 +1549,7 @@ dependencies = [ { name = "curl-cffi" }, { name = "httpx" }, { name = "ndjson" }, + { name = "pydantic" }, { name = "requests" }, { name = "scrapling", extra = ["fetchers"] }, ] @@ -1482,6 +1572,7 @@ requires-dist = [ { name = "curl-cffi", specifier = ">=0.13.0" }, { name = "httpx", specifier = ">=0.28.1" }, { name = "ndjson", specifier = ">=0.3.1" }, + { name = "pydantic", specifier = ">=2.11.10" }, { name = "requests", specifier = ">=2.32.5" }, { name = "scrapling", extras = ["fetchers"], specifier = ">=0.3.5" }, ] @@ -1623,6 +1714,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b5/00/d631e67a838026495268c2f6884f3711a15a9a2a96cd244fdaea53b823fb/typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76", size = 43906, upload-time = "2025-07-04T13:28:32.743Z" }, ] +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] + [[package]] name = "ua-parser" version = "1.0.1" From 2426e1cbd41170c76a7f430b03f5f73509a34500 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 5 Oct 2025 22:10:26 -0400 Subject: [PATCH 004/187] fix: scrapers --- .prettierrc | 2 +- scrapers/models.py | 26 +++++++++----------------- tests/conftest.py | 41 +++++++++++++---------------------------- 3 files changed, 23 insertions(+), 46 deletions(-) diff --git a/.prettierrc b/.prettierrc index ed9f7c5..039a474 100644 --- a/.prettierrc +++ b/.prettierrc @@ -8,7 +8,7 @@ "singleQuote": true, "overrides": [ { - "files": ["*.md", "docs/**/*.md"], + "files": ["**/*.md"], "options": { "parser": "markdown" } diff --git a/scrapers/models.py b/scrapers/models.py index 69ba52b..d2cf19a 100644 --- a/scrapers/models.py +++ b/scrapers/models.py @@ -1,20 +1,18 @@ -from pydantic import BaseModel, Field +from pydantic import BaseModel, ConfigDict, Field class TestCase(BaseModel): input: str expected: str - class Config: - extra = "forbid" + model_config = ConfigDict(extra="forbid") class ProblemSummary(BaseModel): id: str name: str - class Config: - extra = "forbid" + model_config = ConfigDict(extra="forbid") class ContestSummary(BaseModel): @@ -22,31 +20,27 @@ class ContestSummary(BaseModel): name: str display_name: str | None = None - class Config: - extra = "forbid" + model_config = ConfigDict(extra="forbid") class ScrapingResult(BaseModel): success: bool error: str - class Config: - extra = "forbid" + model_config = ConfigDict(extra="forbid") class MetadataResult(ScrapingResult): contest_id: str = "" problems: list[ProblemSummary] = Field(default_factory=list) - class Config: - extra = "forbid" + model_config = ConfigDict(extra="forbid") class ContestListResult(ScrapingResult): contests: list[ContestSummary] = Field(default_factory=list) - class Config: - extra = "forbid" + model_config = ConfigDict(extra="forbid") class TestsResult(ScrapingResult): @@ -57,8 +51,7 @@ class TestsResult(ScrapingResult): memory_mb: float interactive: bool = False - class Config: - extra = "forbid" + model_config = ConfigDict(extra="forbid") class ScraperConfig(BaseModel): @@ -67,5 +60,4 @@ class ScraperConfig(BaseModel): backoff_base: float = 2.0 rate_limit_delay: float = 1.0 - class Config: - extra = "forbid" + model_config = ConfigDict(extra="forbid") diff --git a/tests/conftest.py b/tests/conftest.py index 1053031..b4ca219 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,8 +1,9 @@ +import importlib.util import io import json import sys from pathlib import Path -from typing import Callable +from types import ModuleType import pytest @@ -19,32 +20,16 @@ def fixture_text(): return _load -def _compile_and_exec_module( - module_path: Path, offline_fetch_impls: dict[str, Callable] -): - src = module_path.read_text(encoding="utf-8") - - replacements: list[tuple[str, str]] = [ - ("def _fetch(", "def _orig_fetch("), - ("def fetch_text(", "def _orig_fetch_text("), - ("async def _get_async(", "async def _orig_get_async("), - ] - for old, new in replacements: - src = src.replace(old, new) - - stub_lines = [] - if " _orig_fetch(" in src or "def _orig_fetch(" in src: - stub_lines.append("_fetch = __offline_fetch_sync") - if " _orig_fetch_text(" in src or "def _orig_fetch_text(" in src: - stub_lines.append("fetch_text = __offline_fetch_text") - if " _orig_get_async(" in src or "async def _orig_get_async(" in src: - stub_lines.append("_get_async = __offline_fetch_async") - src += "\n" + "\n".join(stub_lines) + "\n" - - ns = {} - ns.update(offline_fetch_impls) - exec(compile(src, str(module_path), "exec"), ns) - return ns +def _load_scraper_module(module_path: Path, module_name: str) -> ModuleType: + spec = importlib.util.spec_from_file_location( + f"scrapers.{module_name}", module_path + ) + if spec is None or spec.loader is None: + raise ImportError(f"Could not load spec for {module_name} from {module_path}") + module = importlib.util.module_from_spec(spec) + sys.modules[f"scrapers.{module_name}"] = module + spec.loader.exec_module(module) + return module def _capture_stdout(coro): @@ -146,7 +131,7 @@ def run_scraper_offline(fixture_text): def _run(scraper_name: str, mode: str, *args: str): mod_path = ROOT / "scrapers" / f"{scraper_name}.py" - ns = _compile_and_exec_module(mod_path, _make_offline_fetches(scraper_name)) + ns = _load_scraper_module(mod_path, scraper_name) main_async = ns.get("main_async") assert callable(main_async), f"main_async not found in {scraper_name}" From c143600c5bced816a9f15698f849e6c711853613 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 5 Oct 2025 22:13:48 -0400 Subject: [PATCH 005/187] fix(tests): cleaunop --- tests/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index b4ca219..0843a4d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -132,7 +132,7 @@ def run_scraper_offline(fixture_text): def _run(scraper_name: str, mode: str, *args: str): mod_path = ROOT / "scrapers" / f"{scraper_name}.py" ns = _load_scraper_module(mod_path, scraper_name) - main_async = ns.get("main_async") + main_async = getattr(ns, "main_async", None) assert callable(main_async), f"main_async not found in {scraper_name}" argv = [str(mod_path), mode, *args] From 4fac6c8019a23037f52d640fcdd4aca0f9f77088 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 5 Oct 2025 23:06:38 -0400 Subject: [PATCH 006/187] feat(tests): fixtures --- scrapers/cses.py | 2 +- tests/conftest.py | 164 +- tests/fixtures/atcoder_task_abc100_a.html | 1483 +++++++----------- tests/fixtures/atcoder_task_abc100_b.html | 1483 +++++++----------- tests/fixtures/atcoder_task_abc100_c.html | 618 ++++++++ tests/fixtures/atcoder_task_abc100_d.html | 728 +++++++++ tests/fixtures/codeforces_1550_problems.html | 1095 +++++++++++++ 7 files changed, 3750 insertions(+), 1823 deletions(-) create mode 100644 tests/fixtures/atcoder_task_abc100_c.html create mode 100644 tests/fixtures/atcoder_task_abc100_d.html create mode 100644 tests/fixtures/codeforces_1550_problems.html diff --git a/scrapers/cses.py b/scrapers/cses.py index 5302caa..2f76cc5 100644 --- a/scrapers/cses.py +++ b/scrapers/cses.py @@ -19,7 +19,7 @@ from .models import ( ) BASE_URL = "https://cses.fi" -INDEX_PATH = "/problemset/list" +INDEX_PATH = "/problemset" TASK_PATH = "/problemset/task/{id}" HEADERS = { "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" diff --git a/tests/conftest.py b/tests/conftest.py index 0843a4d..a2efcc0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,11 +1,16 @@ +import asyncio import importlib.util import io import json import sys from pathlib import Path -from types import ModuleType +from types import SimpleNamespace +from typing import Any +import httpx import pytest +import requests +from scrapling import fetchers ROOT = Path(__file__).resolve().parent.parent FIX = Path(__file__).resolve().parent / "fixtures" @@ -20,12 +25,12 @@ def fixture_text(): return _load -def _load_scraper_module(module_path: Path, module_name: str) -> ModuleType: +def _load_scraper_module(module_path: Path, module_name: str): spec = importlib.util.spec_from_file_location( f"scrapers.{module_name}", module_path ) if spec is None or spec.loader is None: - raise ImportError(f"Could not load spec for {module_name} from {module_path}") + raise ImportError(f"Cannot load module {module_name}") module = importlib.util.module_from_spec(spec) sys.modules[f"scrapers.{module_name}"] = module spec.loader.exec_module(module) @@ -33,8 +38,6 @@ def _load_scraper_module(module_path: Path, module_name: str) -> ModuleType: def _capture_stdout(coro): - import asyncio - buf = io.StringIO() old = sys.stdout sys.stdout = buf @@ -49,12 +52,26 @@ def _capture_stdout(coro): @pytest.fixture def run_scraper_offline(fixture_text): def _router_cses(*, path: str | None = None, url: str | None = None) -> str: - if path == "/problemset/list": + if not path and not url: + raise AssertionError("CSES expects path or url") + + target = path or url + if target is None: + raise AssertionError(f"No target for CSES (path={path!r}, url={url!r})") + + if target.startswith("https://cses.fi"): + target = target.removeprefix("https://cses.fi") + + if target.strip("/") == "problemset": return fixture_text("cses_contests.html") - if path and path.startswith("/problemset/task/"): - pid = path.rsplit("/", 1)[-1] + + if target.startswith("/problemset/task/") or target.startswith( + "problemset/task/" + ): + pid = target.rstrip("/").split("/")[-1] return fixture_text(f"cses_task_{pid}.html") - raise AssertionError(f"No fixture for CSES path={path!r}") + + raise AssertionError(f"No fixture for CSES path={path!r} url={url!r}") def _router_atcoder(*, path: str | None = None, url: str | None = None) -> str: if not url: @@ -71,6 +88,9 @@ def run_scraper_offline(fixture_text): def _router_codeforces(*, path: str | None = None, url: str | None = None) -> str: if not url: raise AssertionError("Codeforces expects url routing") + if "/contest/" in url and url.endswith("/problems"): + contest_id = url.rstrip("/").split("/")[-2] + return fixture_text(f"codeforces_{contest_id}_problems.html") if "/contests" in url and "/problem/" not in url: return fixture_text("codeforces_contests.html") if "/problem/" in url: @@ -81,58 +101,99 @@ def run_scraper_offline(fixture_text): parts = url.rstrip("/").split("/") contest_id, index = parts[-2], parts[-1] return fixture_text(f"codeforces_{contest_id}_{index}.html") + raise AssertionError(f"No fixture for Codeforces url={url!r}") def _make_offline_fetches(scraper_name: str): - if scraper_name == "cses": + match scraper_name: + case "cses": - def __offline_fetch_text(client, path: str) -> str: - return _router_cses(path=path) + async def __offline_fetch_text(client, path: str, **kwargs): + html = _router_cses(path=path) + return SimpleNamespace( + text=html, + status_code=200, + raise_for_status=lambda: None, + ) - return { - "__offline_fetch_text": __offline_fetch_text, - "__offline_fetch_sync": lambda url: (_ for _ in ()).throw( - AssertionError("CSES doesn't use _fetch") - ), - "__offline_fetch_async": lambda client, url: (_ for _ in ()).throw( - AssertionError("CSES doesn't use _get_async") - ), - } - if scraper_name == "atcoder": + return { + "__offline_fetch_text": __offline_fetch_text, + } - async def __offline_fetch_async(client, url: str) -> str: - return _router_atcoder(url=url) + case "atcoder": - def __offline_fetch_sync(url: str) -> str: - return _router_atcoder(url=url) + def __offline_fetch(url: str, *args, **kwargs): + html = _router_atcoder(url=url) + return html - return { - "__offline_fetch_text": lambda client, path: (_ for _ in ()).throw( - AssertionError("AtCoder doesn't use fetch_text") - ), - "__offline_fetch_sync": __offline_fetch_sync, - "__offline_fetch_async": __offline_fetch_async, - } - if scraper_name == "codeforces": + async def __offline_get_async(client, url: str, **kwargs): + return _router_atcoder(url=url) - def __offline_fetch_sync(url: str) -> str: - return _router_codeforces(url=url) + return { + "_fetch": __offline_fetch, + "_get_async": __offline_get_async, + } - return { - "__offline_fetch_text": lambda client, path: (_ for _ in ()).throw( - AssertionError("Codeforces doesn't use fetch_text") - ), - "__offline_fetch_sync": __offline_fetch_sync, - "__offline_fetch_async": lambda client, url: (_ for _ in ()).throw( - AssertionError("Codeforces doesn't use _get_async") - ), - } - raise AssertionError(f"Unknown scraper: {scraper_name}") + case "codeforces": + + class MockPage: + def __init__(self, html: str): + self.html_content = html + + def _mock_stealthy_fetch(url: str, **kwargs): + return MockPage(_router_codeforces(url=url)) + + def _mock_requests_get(url: str, **kwargs): + if "api/contest.list" in url: + data = { + "status": "OK", + "result": [ + { + "id": 1550, + "name": "Educational Codeforces Round 155 (Rated for Div. 2)", + "phase": "FINISHED", + }, + { + "id": 1000, + "name": "Codeforces Round #1000", + "phase": "FINISHED", + }, + ], + } + + class R: + def json(self_inner): + return data + + def raise_for_status(self_inner): + return None + + return R() + raise AssertionError(f"Unexpected requests.get call: {url}") + + return { + "StealthyFetcher.fetch": _mock_stealthy_fetch, + "requests.get": _mock_requests_get, + } + + case _: + raise AssertionError(f"Unknown scraper: {scraper_name}") def _run(scraper_name: str, mode: str, *args: str): mod_path = ROOT / "scrapers" / f"{scraper_name}.py" ns = _load_scraper_module(mod_path, scraper_name) - main_async = getattr(ns, "main_async", None) + offline_fetches = _make_offline_fetches(scraper_name) + + if scraper_name == "codeforces": + fetchers.stealthyfetcher.fetch = offline_fetches["stealthyfetcher.fetch"] # type: ignore + requests.get = offline_fetches["requests.get"] + elif scraper_name == "atcoder": + ns._fetch = offline_fetches["_fetch"] + ns._get_async = offline_fetches["_get_async"] + elif scraper_name == "cses": + httpx.asyncclient.get = offline_fetches["__offline_fetch_text"] # type: ignore + + main_async = getattr(ns, "main_async") assert callable(main_async), f"main_async not found in {scraper_name}" argv = [str(mod_path), mode, *args] @@ -143,14 +204,9 @@ def run_scraper_offline(fixture_text): finally: sys.argv = old_argv - json_lines = [] + json_lines: list[Any] = [] for line in (l for l in out.splitlines() if l.strip()): - try: - json_lines.append(json.loads(line)) - except json.JSONDecodeError as e: - raise AssertionError( - f"Invalid JSON from {scraper_name} {mode}: {line}" - ) from e + json_lines.append(json.loads(line)) return rc, json_lines return _run diff --git a/tests/fixtures/atcoder_task_abc100_a.html b/tests/fixtures/atcoder_task_abc100_a.html index c96cd9a..2e0e623 100644 --- a/tests/fixtures/atcoder_task_abc100_a.html +++ b/tests/fixtures/atcoder_task_abc100_a.html @@ -1,885 +1,602 @@ - + + + + + + + + + - - A - Happy Birthday! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - -
- -
-
-
-
-
- - Contest Duration: - - - - - (local time) (100 minutes) - - Back to Home -
- -
-
- - A - Happy Birthday! - Editorial - - - / - - -
-

Time Limit: 2 sec / Memory Limit: 976 MiB

- -
- - -

配点: 100

- -
-
-

問題文

-

- もうすぐ E869120 君と square1001 君の - 16 才の誕生日が来る.
- そこで, AtCoder 王国の高橋君は, 円形のケーキ - 1 個に放射状に切れ目を入れ - 16 等分したものを, 彼らにプレゼントした. -

-

- E869120 君はそのうち A 切れ、square1001 君は - B 切れを食べようとした.
- しかし, ケーキと一緒についていた紙を見ると, - 「同じ人が隣り合う - 2 - 切れのケーキを両方取ってはならない」と書かれていた. -

-

- さて、彼らは紙に書かれたことを守って、2 - 人とも食べたい数のケーキを取ることができるだろうか? -

-
-
- -
-
-

制約

-
    -
  • - A, B1 以上 - 16 以下の整数 -
  • -
  • A+B16 以下である.
  • -
-
-
- -
- -
-
-
-

入力

-

入力は以下の形式で標準入力から与えられる.

-
A B
-
-
-
- -
-
-

出力

-

- 紙に書かれたことを守って, E869120 君と square1001 - 君両方が, 食べたい数のケーキを取ることができるならば - Yay!, そうでなければ - :( と出力しなさい. -

-
-
-
- -
- -
-
-

入力例 1

-
-5 4
-
-
-
- -
-
-

出力例 1

-
-Yay!
-
- -

- 下の図のようにケーキを取れば、2 - 人とも目標を達成することができる.
-  -

-
-
- -
- -
-
-

入力例 2

-
-8 8
-
-
-
- -
-
-

出力例 2

-
-Yay!
-
- -

- 下の図のようにケーキを取れば、2 - 人とも目標を達成することができる.
-  -

-
-
- -
- -
-
-

入力例 3

-
-11 4
-
-
-
- -
-
-

出力例 3

-
-:(
-
- -

- この場合, 残念ながら目標を達成する方法は - 1 つもない. -

-
-
-
- -

Score: 100 points

- -
-
-

Problem Statement

-

- E869120's and square1001's 16-th birthday is - coming soon.
- Takahashi from AtCoder Kingdom gave them a round cake - cut into 16 equal fan-shaped pieces. -

-

- E869120 and square1001 were just about to eat - A and B of those pieces, - respectively,
- when they found a note attached to the cake saying that - "the same person should not take two adjacent pieces of - cake". -

-

- Can both of them obey the instruction in the note and - take desired numbers of pieces of cake? -

-
-
- -
-
-

Constraints

-
    -
  • - A and B are integers between - 1 and 16 (inclusive). -
  • -
  • A+B is at most 16.
  • -
-
-
- -
- -
-
-
-

Input

-

- Input is given from Standard Input in the following - format: -

-
A B
-
-
-
- -
-
-

Output

-

- If both E869120 and square1001 can obey the - instruction in the note and take desired numbers of - pieces of cake, print Yay!; otherwise, - print :(. -

-
-
-
- -
- -
-
-

Sample Input 1

-
-5 4
-
-
-
- -
-
-

Sample Output 1

-
-Yay!
-
- -

- Both of them can take desired number of pieces as - follows: -  -

-
-
- -
- -
-
-

Sample Input 2

-
-8 8
-
-
-
- -
-
-

Sample Output 2

-
-Yay!
-
- -

- Both of them can take desired number of pieces as - follows: -  -

-
-
- -
- -
-
-

Sample Input 3

-
-11 4
-
-
-
- -
-
-

Sample Output 3

-
-:(
-
- -

- In this case, there is no way for them to take desired - number of pieces, unfortunately. -

-
-
-
-
-
-
-
- -
- -
- - - - - - -
- - -
-
-
- -
- -
-

- - + + A - Happy Birthday! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ +
+
+ + + +
+
+
+ + + Contest Duration: + - (local time) + (100 minutes) + + + Back to Home +
+ +
+
+ + A - Happy Birthday! + Editorial + + / + +
+

+ Time Limit: 2 sec / Memory Limit: 976 MiB + + +

+ +
+ + + + + + + + +

配点: 100

+ +
+
+

問題文

+

もうすぐ E869120 君と square1001 君の 16 才の誕生日が来る.
+そこで, AtCoder 王国の高橋君は, 円形のケーキ 1 個に放射状に切れ目を入れ 16 等分したものを, 彼らにプレゼントした.

+

E869120 君はそのうち A 切れ、square1001 君は B 切れを食べようとした.
+しかし, ケーキと一緒についていた紙を見ると, 「同じ人が隣り合う 2 切れのケーキを両方取ってはならない」と書かれていた.

+

さて、彼らは紙に書かれたことを守って、2 人とも食べたい数のケーキを取ることができるだろうか?

+
+
+ +
+
+

制約

+
    +
  • A, B1 以上 16 以下の整数
  • +
  • A+B16 以下である.
  • +
+
+
+ +
+ +
+
+
+

入力

+

入力は以下の形式で標準入力から与えられる.

+
A B
+
+ +
+
+ +
+
+

出力

+

紙に書かれたことを守って, E869120 君と square1001 君両方が, 食べたい数のケーキを取ることができるならば Yay!, そうでなければ :( と出力しなさい.

+
+
+
+ +
+ +
+
+

入力例 1

5 4
+
+ +
+
+ +
+
+

出力例 1

Yay!
+
+ +

下の図のようにケーキを取れば、2 人とも目標を達成することができる.
+

+
+
+ +
+ +
+
+

入力例 2

8 8
+
+ +
+
+ +
+
+

出力例 2

Yay!
+
+ +

下の図のようにケーキを取れば、2 人とも目標を達成することができる.
+

+
+
+ +
+ +
+
+

入力例 3

11 4
+
+ +
+
+ +
+
+

出力例 3

:(
+
+ +

この場合, 残念ながら目標を達成する方法は 1 つもない.

+
+
+ +

Score: 100 points

+ +
+
+

Problem Statement

+

E869120's and square1001's 16-th birthday is coming soon.
+Takahashi from AtCoder Kingdom gave them a round cake cut into 16 equal fan-shaped pieces.

+

E869120 and square1001 were just about to eat A and B of those pieces, respectively,
+when they found a note attached to the cake saying that "the same person should not take two adjacent pieces of cake".

+

Can both of them obey the instruction in the note and take desired numbers of pieces of cake?

+
+
+ +
+
+

Constraints

+
    +
  • A and B are integers between 1 and 16 (inclusive).
  • +
  • A+B is at most 16.
  • +
+
+
+ +
+ +
+
+
+

Input

+

Input is given from Standard Input in the following format:

+
A B
+
+ +
+
+ +
+
+

Output

+

If both E869120 and square1001 can obey the instruction in the note and take desired numbers of pieces of cake, print Yay!; otherwise, print :(.

+
+
+
+ +
+ +
+
+

Sample Input 1

5 4
+
+ +
+
+ +
+
+

Sample Output 1

Yay!
+
+ +

Both of them can take desired number of pieces as follows: +

+
+
+ +
+ +
+
+

Sample Input 2

8 8
+
+ +
+
+ +
+
+

Sample Output 2

Yay!
+
+ +

Both of them can take desired number of pieces as follows: +

+
+
+ +
+ +
+
+

Sample Input 3

11 4
+
+ +
+
+ +
+
+

Sample Output 3

:(
+
+ +

In this case, there is no way for them to take desired number of pieces, unfortunately.

+
+
+
+ +
+ + + + +
+
+ + + + + +
+ + + +
+ + + + + + +
+ + + + +
+
+
+ +
+ +
+

+ + + + + diff --git a/tests/fixtures/atcoder_task_abc100_b.html b/tests/fixtures/atcoder_task_abc100_b.html index c2ab95e..c7a28d3 100644 --- a/tests/fixtures/atcoder_task_abc100_b.html +++ b/tests/fixtures/atcoder_task_abc100_b.html @@ -1,887 +1,600 @@ - + + + + + + + + + - - B - Ringo's Favorite Numbers - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - -
- -
-
-
-
-
- - Contest Duration: - - - - - (local time) (100 minutes) - - Back to Home -
- -
-
- - B - Ringo's Favorite Numbers - Editorial - - - / - - -
-

Time Limit: 2 sec / Memory Limit: 976 MiB

- -
- - -

配点: 200

- -
-
-

問題文

-

- 今日は, 記念すべき AtCoder Beginner Contest 100 - が開催される. そのため, 高橋君はりんごさんに, - ある整数をプレゼントしようと思った.
- 今日のコンテストは「AtCoder Beginner Contest - 100」なので, りんごさんは 100 で - ちょうど - D - 回割りきれる正の整数をプレゼントされると喜ぶ. -

-

- さて, りんごさんがプレゼントされると喜ぶような整数のうち - N 番目に小さいものを求めなさい. -

-
-
- -
-
-

制約

-
    -
  • - D0, 1, 2 のいずれかである -
  • -
  • - N1 以上 - 100 以下の整数 -
  • -
-
-
- -
- -
-
-
-

入力

-

入力は以下の形式で標準入力から与えられる.

-
D N
-
-
-
- -
-
-

出力

-

- 100 でちょうど - D 回割りきれる正の整数の中で - N 番目に小さいものを出力しなさい. -

-
-
-
- -
- -
-
-

入力例 1

-
-0 5
-
-
-
- -
-
-

出力例 1

-
-5
-
- -

- 100 でちょうど - 0 回割り切れる(すなわち, - 100 で割り切れない)整数は, 1, - 2, 3, 4, 5, - 6, 7, ... と続く.
- よって, 5 番目に小さいりんごさんが喜ぶ整数は - 5 である. -

-
-
- -
- -
-
-

入力例 2

-
-1 11
-
-
-
- -
-
-

出力例 2

-
-1100
-
- -

- 100 でちょうど - 1 回割り切れる整数は, 100, - 200, 300, 400, - 500, 600, 700, - 800, 900, 1 \ 000, - 1 \ 100, ... と続く.
- よって, 求めたい整数は 1 \ 100 である. -

-
-
- -
- -
-
-

入力例 3

-
-2 85
-
-
-
- -
-
-

出力例 3

-
-850000
-
- -

- 100 でちょうど - 2 回割り切れる整数は, 10 \ 000, - 20 \ 000, 30 \ 000, ... と続く.
- よって, 求めたい整数は 850 \ 000 である. -

-
-
-
- -

Score: 200 points

- -
-
-

Problem Statement

-

- Today, the memorable AtCoder Beginner Contest 100 takes - place. On this occasion, Takahashi would like to give an - integer to Ringo.
- As the name of the contest is AtCoder Beginner Contest - 100, Ringo would be happy if he is given a positive - integer that can be divided by 100 - exactly D times. -

-

- Find the N-th smallest integer that would - make Ringo happy. -

-
-
- -
-
-

Constraints

-
    -
  • - D is 0, 1 or - 2. -
  • -
  • - N is an integer between 1 and - 100 (inclusive). -
  • -
-
-
- -
- -
-
-
-

Input

-

- Input is given from Standard Input in the following - format: -

-
D N
-
-
-
- -
-
-

Output

-

- Print the N-th smallest integer that can be - divided by 100 exactly D times. -

-
-
-
- -
- -
-
-

Sample Input 1

-
-0 5
-
-
-
- -
-
-

Sample Output 1

-
-5
-
- -

- The integers that can be divided by - 100 exactly 0 times (that is, not - divisible by 100) are as follows: - 1, 2, 3, 4, - 5, 6, 7, ...
- Thus, the 5-th smallest integer that would - make Ringo happy is 5. -

-
-
- -
- -
-
-

Sample Input 2

-
-1 11
-
-
-
- -
-
-

Sample Output 2

-
-1100
-
- -

- The integers that can be divided by - 100 exactly once are as follows: - 100, 200, 300, - 400, 500, 600, - 700, 800, 900, - 1 \ 000, 1 \ 100, ...
- Thus, the integer we are seeking is 1 \ 100. -

-
-
- -
- -
-
-

Sample Input 3

-
-2 85
-
-
-
- -
-
-

Sample Output 3

-
-850000
-
- -

- The integers that can be divided by - 100 exactly twice are as follows: - 10 \ 000, 20 \ 000, - 30 \ 000, ...
- Thus, the integer we are seeking is - 850 \ 000. -

-
-
-
-
-
-
-
- -
- -
- - - - - - -
- - -
-
-
- -
- -
-

- - + + B - Ringo's Favorite Numbers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ +
+
+ + + +
+
+
+ + + Contest Duration: + - (local time) + (100 minutes) + + + Back to Home +
+ +
+
+ + B - Ringo's Favorite Numbers + Editorial + + / + +
+

+ Time Limit: 2 sec / Memory Limit: 976 MiB + + +

+ +
+ + + + + + + + +

配点: 200

+ +
+
+

問題文

+

今日は, 記念すべき AtCoder Beginner Contest 100 が開催される. そのため, 高橋君はりんごさんに, ある整数をプレゼントしようと思った.
+今日のコンテストは「AtCoder Beginner Contest 100」なので, りんごさんは 100ちょうど D 回割りきれる正の整数をプレゼントされると喜ぶ.

+

さて, りんごさんがプレゼントされると喜ぶような整数のうち N 番目に小さいものを求めなさい.

+
+
+ +
+
+

制約

+
    +
  • D0, 1, 2 のいずれかである
  • +
  • N1 以上 100 以下の整数
  • +
+
+
+ +
+ +
+
+
+

入力

+

入力は以下の形式で標準入力から与えられる.

+
D N
+
+ +
+
+ +
+
+

出力

+

100 でちょうど D 回割りきれる正の整数の中で N 番目に小さいものを出力しなさい.

+
+
+
+ +
+ +
+
+

入力例 1

0 5
+
+ +
+
+ +
+
+

出力例 1

5
+
+ +

100 でちょうど 0 回割り切れる(すなわち, 100 で割り切れない)整数は, 1, 2, 3, 4, 5, 6, 7, ... と続く.
+よって, 5 番目に小さいりんごさんが喜ぶ整数は 5 である.

+
+
+ +
+ +
+
+

入力例 2

1 11
+
+ +
+
+ +
+
+

出力例 2

1100
+
+ +

100 でちょうど 1 回割り切れる整数は, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1 \ 000, 1 \ 100, ... と続く.
+よって, 求めたい整数は 1 \ 100 である.

+
+
+ +
+ +
+
+

入力例 3

2 85
+
+ +
+
+ +
+
+

出力例 3

850000
+
+ +

100 でちょうど 2 回割り切れる整数は, 10 \ 000, 20 \ 000, 30 \ 000, ... と続く.
+よって, 求めたい整数は 850 \ 000 である.

+
+
+ +

Score: 200 points

+ +
+
+

Problem Statement

+

Today, the memorable AtCoder Beginner Contest 100 takes place. On this occasion, Takahashi would like to give an integer to Ringo.
+As the name of the contest is AtCoder Beginner Contest 100, Ringo would be happy if he is given a positive integer that can be divided by 100 exactly D times.

+

Find the N-th smallest integer that would make Ringo happy.

+
+
+ +
+
+

Constraints

+
    +
  • D is 0, 1 or 2.
  • +
  • N is an integer between 1 and 100 (inclusive).
  • +
+
+
+ +
+ +
+
+
+

Input

+

Input is given from Standard Input in the following format:

+
D N
+
+ +
+
+ +
+
+

Output

+

Print the N-th smallest integer that can be divided by 100 exactly D times.

+
+
+
+ +
+ +
+
+

Sample Input 1

0 5
+
+ +
+
+ +
+
+

Sample Output 1

5
+
+ +

The integers that can be divided by 100 exactly 0 times (that is, not divisible by 100) are as follows: 1, 2, 3, 4, 5, 6, 7, ...
+Thus, the 5-th smallest integer that would make Ringo happy is 5.

+
+
+ +
+ +
+
+

Sample Input 2

1 11
+
+ +
+
+ +
+
+

Sample Output 2

1100
+
+ +

The integers that can be divided by 100 exactly once are as follows: 100, 200, 300, 400, 500, 600, 700, 800, 900, 1 \ 000, 1 \ 100, ...
+Thus, the integer we are seeking is 1 \ 100.

+
+
+ +
+ +
+
+

Sample Input 3

2 85
+
+ +
+
+ +
+
+

Sample Output 3

850000
+
+ +

The integers that can be divided by 100 exactly twice are as follows: 10 \ 000, 20 \ 000, 30 \ 000, ...
+Thus, the integer we are seeking is 850 \ 000.

+
+
+
+ +
+ + + + +
+
+ + + + + +
+ + + +
+ + + + + + +
+ + + + +
+
+
+ +
+ +
+

+ + + + + diff --git a/tests/fixtures/atcoder_task_abc100_c.html b/tests/fixtures/atcoder_task_abc100_c.html new file mode 100644 index 0000000..6b298ba --- /dev/null +++ b/tests/fixtures/atcoder_task_abc100_c.html @@ -0,0 +1,618 @@ + + + + + + + + + + + + C - *3 or /2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ +
+
+ + + +
+
+
+ + + Contest Duration: + - (local time) + (100 minutes) + + + Back to Home +
+ +
+
+ + C - *3 or /2 + Editorial + + / + +
+

+ Time Limit: 2 sec / Memory Limit: 976 MiB + + +

+ +
+ + + + + + + + +

配点: 300

+ +
+
+

問題文

+

AtCoder Beginner Contest 100 の開催にともなって, AtCoder 社では長さ N の数列 a = {a_1, a_2, a_3, ..., a_N} が飾られることになった.
+社員のすぬけ君は, この数列で遊んでみようと思った.

+

具体的には, 以下の操作をできるだけ多くの回数繰り返そうと思った.

+
1 \leq i \leq N を満たす全ての i に対して, それぞれ「a_i の値を 2 で割る」「a_i の値を 3 倍する」のどちらかを行う.  
+ただし, 全ての i に対して 3 倍することはできず, 操作後の a_i の値は整数でなければならない.  
+
+ +

最大で何回の操作が可能か, 求めなさい.

+
+
+ +
+
+

制約

+
    +
  • N1 以上 10 \ 000 以下の整数
  • +
  • a_i1 以上 1 \ 000 \ 000 \ 000 以下の整数
  • +
+
+
+ +
+ +
+
+
+

入力

+

入力は以下の形式で標準入力から与えられる.

+
N
+a_1 a_2 a_3 ... a_N
+
+ +
+
+ +
+
+

出力

+

すぬけ君が行える最大の操作回数を出力しなさい.

+
+
+
+ +
+ +
+
+

入力例 1

3
+5 2 4
+
+ +
+
+ +
+
+

出力例 1

3
+
+ +

最初, 数列は {5, 2, 4} であるが, 以下のように操作すれば 3 回の操作を行うことができる.

+
    +
  • 最初に, a_13 倍し, a_23 倍し, a_32 で割る. すると数列は {15, 6, 2} となる.
  • +
  • 次に, a_13 倍し, a_22 で割り, a_33 倍する. すると数列は {45, 3, 6} となる.
  • +
  • 最後に, a_13 倍し, a_23 倍し, a_32 で割る. すると数列は {135, 9, 3} となる.
  • +
+
+
+ +
+ +
+
+

入力例 2

4
+631 577 243 199
+
+ +
+
+ +
+
+

出力例 2

0
+
+ +

全ての要素が奇数なので, 操作はできない. よって答えは 0 である.

+
+
+ +
+ +
+
+

入力例 3

10
+2184 2126 1721 1800 1024 2528 3360 1945 1280 1776
+
+ +
+
+ +
+
+

出力例 3

39
+
+
+
+ +

Score: 300 points

+ +
+
+

Problem Statement

+

As AtCoder Beginner Contest 100 is taking place, the office of AtCoder, Inc. is decorated with a sequence of length N, a = {a_1, a_2, a_3, ..., a_N}.
+Snuke, an employee, would like to play with this sequence.

+

Specifically, he would like to repeat the following operation as many times as possible:

+
For every i satisfying 1 \leq i \leq N, perform one of the following: "divide a_i by 2" and "multiply a_i by 3".  
+Here, choosing "multiply a_i by 3" for every i is not allowed, and the value of a_i after the operation must be an integer.
+
+ +

At most how many operations can be performed?

+
+
+ +
+
+

Constraints

+
    +
  • N is an integer between 1 and 10 \ 000 (inclusive).
  • +
  • a_i is an integer between 1 and 1 \ 000 \ 000 \ 000 (inclusive).
  • +
+
+
+ +
+ +
+
+
+

Input

+

Input is given from Standard Input in the following format:

+
N
+a_1 a_2 a_3 ... a_N
+
+ +
+
+ +
+
+

Output

+

Print the maximum number of operations that Snuke can perform.

+
+
+
+ +
+ +
+
+

Sample Input 1

3
+5 2 4
+
+ +
+
+ +
+
+

Sample Output 1

3
+
+ +

The sequence is initially {5, 2, 4}. Three operations can be performed as follows:

+
    +
  • First, multiply a_1 by 3, multiply a_2 by 3 and divide a_3 by 2. The sequence is now {15, 6, 2}.
  • +
  • Next, multiply a_1 by 3, divide a_2 by 2 and multiply a_3 by 3. The sequence is now {45, 3, 6}.
  • +
  • Finally, multiply a_1 by 3, multiply a_2 by 3 and divide a_3 by 2. The sequence is now {135, 9, 3}.
  • +
+
+
+ +
+ +
+
+

Sample Input 2

4
+631 577 243 199
+
+ +
+
+ +
+
+

Sample Output 2

0
+
+ +

No operation can be performed since all the elements are odd. Thus, the answer is 0.

+
+
+ +
+ +
+
+

Sample Input 3

10
+2184 2126 1721 1800 1024 2528 3360 1945 1280 1776
+
+ +
+
+ +
+
+

Sample Output 3

39
+
+
+
+
+ +
+ + + + +
+
+ + + + + +
+ + + +
+ + + + + + +
+ + + + +
+
+
+ +
+ +
+

+ + + + + + diff --git a/tests/fixtures/atcoder_task_abc100_d.html b/tests/fixtures/atcoder_task_abc100_d.html new file mode 100644 index 0000000..552b276 --- /dev/null +++ b/tests/fixtures/atcoder_task_abc100_d.html @@ -0,0 +1,728 @@ + + + + + + + + + + + + D - Patisserie ABC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ +
+
+ + + +
+
+
+ + + Contest Duration: + - (local time) + (100 minutes) + + + Back to Home +
+ +
+
+ + D - Patisserie ABC + Editorial + + / + +
+

+ Time Limit: 2 sec / Memory Limit: 976 MiB + + +

+ +
+ + + + + + + + +

配点: 400

+ +
+
+

問題文

+

高橋君はプロのパティシエになり, AtCoder Beginner Contest 100 を記念して, 「ABC洋菓子店」というお店を開いた.

+

ABC洋菓子店では, N 種類のケーキを売っている.
+各種類のケーキには「綺麗さ」「おいしさ」「人気度」の 3 つの値を持ち, i 種類目のケーキの綺麗さは x_i, おいしさは y_i, 人気度は z_i である.
+これらの値は 0 以下である可能性もある.

+

りんごさんは, ABC洋菓子店で M 個のケーキを食べることにした. 彼は次のように, 食べるケーキの組み合わせを選ぶことにした.

+
    +
  • 同じ種類のケーキを 2 個以上食べない.
  • +
  • 上の条件を満たしつつ, (綺麗さの合計の絶対値) + (おいしさの合計の絶対値) + (人気度の合計の絶対値) が最大になるように選ぶ.
  • +
+

このとき, りんごさんが選ぶケーキの (綺麗さの合計の絶対値) + (おいしさの合計の絶対値) + (人気度の合計の絶対値) の最大値を求めなさい.

+
+
+ +
+
+

制約

+
    +
  • N1 以上 1 \ 000 以下の整数
  • +
  • M0 以上 N 以下の整数
  • +
  • x_i, y_i, z_i \ (1 \leq i \leq N) は, それぞれ -10 \ 000 \ 000 \ 000 以上 10 \ 000 \ 000 \ 000 以下の整数.
  • +
+
+
+ +
+ +
+
+
+

入力

+

入力は以下の形式で標準入力から与えられる.

+
N M
+x_1 y_1 z_1
+x_2 y_2 z_2
+ :  :
+x_N y_N z_N
+
+ +
+
+ +
+
+

出力

+

りんごさんが選ぶケーキの (綺麗さの合計の絶対値) + (おいしさの合計の絶対値) + (人気度の合計の絶対値) の最大値を出力しなさい.

+
+
+
+ +
+ +
+
+

入力例 1

5 3
+3 1 4
+1 5 9
+2 6 5
+3 5 8
+9 7 9
+
+ +
+
+ +
+
+

出力例 1

56
+
+ +

2, 4, 5 種類目のケーキを食べることを考える. そのとき, 「綺麗さ」「おいしさ」「人気度」の合計はそれぞれ次のようになる.

+
    +
  • 綺麗さ:1 + 3 + 9 = 13
  • +
  • おいしさ:5 + 5 + 7 = 17
  • +
  • 人気度:9 + 8 + 9 = 26
  • +
+

このときの (綺麗さの合計の絶対値) + (おいしさの合計の絶対値) + (人気度の合計の絶対値) は 13 + 17 + 26 = 56 となり, これが最大になる.

+
+
+ +
+ +
+
+

入力例 2

5 3
+1 -2 3
+-4 5 -6
+7 -8 -9
+-10 11 -12
+13 -14 15
+
+ +
+
+ +
+
+

出力例 2

54
+
+ +

1, 3, 5 種類目のケーキを食べることを考える. そのとき, 「綺麗さ」「おいしさ」「人気度」の合計はそれぞれ次のようになる.

+
    +
  • 綺麗さ:1 + 7 + 13 = 21
  • +
  • おいしさ:(-2) + (-8) + (-14) = -24
  • +
  • 人気度:3 + (-9) + 15 = 9
  • +
+

このときの (綺麗さの合計の絶対値) + (おいしさの合計の絶対値) + (人気度の合計の絶対値) は 21 + 24 + 9 = 54 となり, これが最大になる.

+
+
+ +
+ +
+
+

入力例 3

10 5
+10 -80 21
+23 8 38
+-94 28 11
+-26 -2 18
+-69 72 79
+-26 -86 -54
+-72 -50 59
+21 65 -32
+40 -94 87
+-62 18 82
+
+ +
+
+ +
+
+

出力例 3

638
+
+ +

3, 4, 5, 7, 10 種類目のケーキを食べると, 綺麗さの合計は -323, おいしさの合計は 66, 人気度の合計は 249 となる.
+このときの (綺麗さの合計の絶対値) + (おいしさの合計の絶対値) + (人気度の合計の絶対値) は 323 + 66 + 249 = 638 となり, これが最大になる.

+
+
+ +
+ +
+
+

入力例 4

3 2
+2000000000 -9000000000 4000000000
+7000000000 -5000000000 3000000000
+6000000000 -1000000000 8000000000
+
+ +
+
+ +
+
+

出力例 4

30000000000
+
+ +

ケーキの綺麗さ, おいしさ, 人気度や出力すべき値が, 32bit 整数に収まらない場合もある.

+
+
+ +

Score: 400 points

+ +
+
+

Problem Statement

+

Takahashi became a pastry chef and opened a shop La Confiserie d'ABC to celebrate AtCoder Beginner Contest 100.

+

The shop sells N kinds of cakes.
+Each kind of cake has three parameters "beauty", "tastiness" and "popularity". The i-th kind of cake has the beauty of x_i, the tastiness of y_i and the popularity of z_i.
+These values may be zero or negative.

+

Ringo has decided to have M pieces of cakes here. He will choose the set of cakes as follows:

+
    +
  • Do not have two or more pieces of the same kind of cake.
  • +
  • Under the condition above, choose the set of cakes to maximize (the absolute value of the total beauty) + (the absolute value of the total tastiness) + (the absolute value of the total popularity).
  • +
+

Find the maximum possible value of (the absolute value of the total beauty) + (the absolute value of the total tastiness) + (the absolute value of the total popularity) for the set of cakes that Ringo chooses.

+
+
+ +
+
+

Constraints

+
    +
  • N is an integer between 1 and 1 \ 000 (inclusive).
  • +
  • M is an integer between 0 and N (inclusive).
  • +
  • x_i, y_i, z_i \ (1 \leq i \leq N) are integers between -10 \ 000 \ 000 \ 000 and 10 \ 000 \ 000 \ 000 (inclusive).
  • +
+
+
+ +
+ +
+
+
+

Input

+

Input is given from Standard Input in the following format:

+
N M
+x_1 y_1 z_1
+x_2 y_2 z_2
+ :  :
+x_N y_N z_N
+
+ +
+
+ +
+
+

Output

+

Print the maximum possible value of (the absolute value of the total beauty) + (the absolute value of the total tastiness) + (the absolute value of the total popularity) for the set of cakes that Ringo chooses.

+
+
+
+ +
+ +
+
+

Sample Input 1

5 3
+3 1 4
+1 5 9
+2 6 5
+3 5 8
+9 7 9
+
+ +
+
+ +
+
+

Sample Output 1

56
+
+ +

Consider having the 2-nd, 4-th and 5-th kinds of cakes. The total beauty, tastiness and popularity will be as follows:

+
    +
  • Beauty: 1 + 3 + 9 = 13
  • +
  • Tastiness: 5 + 5 + 7 = 17
  • +
  • Popularity: 9 + 8 + 9 = 26
  • +
+

The value (the absolute value of the total beauty) + (the absolute value of the total tastiness) + (the absolute value of the total popularity) here is 13 + 17 + 26 = 56. This is the maximum value.

+
+
+ +
+ +
+
+

Sample Input 2

5 3
+1 -2 3
+-4 5 -6
+7 -8 -9
+-10 11 -12
+13 -14 15
+
+ +
+
+ +
+
+

Sample Output 2

54
+
+ +

Consider having the 1-st, 3-rd and 5-th kinds of cakes. The total beauty, tastiness and popularity will be as follows:

+
    +
  • Beauty: 1 + 7 + 13 = 21
  • +
  • Tastiness: (-2) + (-8) + (-14) = -24
  • +
  • Popularity: 3 + (-9) + 15 = 9
  • +
+

The value (the absolute value of the total beauty) + (the absolute value of the total tastiness) + (the absolute value of the total popularity) here is 21 + 24 + 9 = 54. This is the maximum value.

+
+
+ +
+ +
+
+

Sample Input 3

10 5
+10 -80 21
+23 8 38
+-94 28 11
+-26 -2 18
+-69 72 79
+-26 -86 -54
+-72 -50 59
+21 65 -32
+40 -94 87
+-62 18 82
+
+ +
+
+ +
+
+

Sample Output 3

638
+
+ +

If we have the 3-rd, 4-th, 5-th, 7-th and 10-th kinds of cakes, the total beauty, tastiness and popularity will be -323, 66 and 249, respectively.
+The value (the absolute value of the total beauty) + (the absolute value of the total tastiness) + (the absolute value of the total popularity) here is 323 + 66 + 249 = 638. This is the maximum value.

+
+
+ +
+ +
+
+

Sample Input 4

3 2
+2000000000 -9000000000 4000000000
+7000000000 -5000000000 3000000000
+6000000000 -1000000000 8000000000
+
+ +
+
+ +
+
+

Sample Output 4

30000000000
+
+ +

The values of the beauty, tastiness and popularity of the cakes and the value to be printed may not fit into 32-bit integers.

+
+
+
+ +
+ + + + +
+
+ + + + + +
+ + + +
+ + + + + + +
+ + + + +
+
+
+ +
+ +
+

+ + + + + + diff --git a/tests/fixtures/codeforces_1550_problems.html b/tests/fixtures/codeforces_1550_problems.html new file mode 100644 index 0000000..fa19bbb --- /dev/null +++ b/tests/fixtures/codeforces_1550_problems.html @@ -0,0 +1,1095 @@ +Problems - Codeforces
Loading [MathJax]/jax/output/HTML-CSS/fonts/TeX/fontdata.js
+
+ + +
Educational Codeforces Round 111 (Rated for Div. 2)
+
+ +
+
+ +
+
+ +
+ +
A. Find The Array
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Let's call an array a consisting of n positive (greater than 0) integers beautiful if the following condition is held for every i from 1 to n: either ai=1, or at least one of the numbers ai1 and ai2 exists in the array as well.

For example:

  • the array [5,3,1] is beautiful: for a1, the number a12=3 exists in the array; for a2, the number a22=1 exists in the array; for a3, the condition a3=1 holds;
  • the array [1,2,2,2,2] is beautiful: for a1, the condition a1=1 holds; for every other number ai, the number ai1=1 exists in the array;
  • the array [1,4] is not beautiful: for a2, neither a22=2 nor a21=3 exists in the array, and a21;
  • the array [2] is not beautiful: for a1, neither a11=1 nor a12=0 exists in the array, and a11;
  • the array [2,1,3] is beautiful: for a1, the number a11=1 exists in the array; for a2, the condition a2=1 holds; for a3, the number a32=1 exists in the array.

You are given a positive integer s. Find the minimum possible size of a beautiful array with the sum of elements equal to s.

Input

The first line contains one integer t (1t5000) — the number of test cases.

Then t lines follow, the i-th line contains one integer s (1s5000) for the i-th test case.

Output

Print t integers, the i-th integer should be the answer for the i-th testcase: the minimum possible size of a beautiful array with the sum of elements equal to s.

Example
Input
Copy
4
+1
+8
+7
+42
+
Output
Copy
1
+3
+3
+7
+
Note

Consider the example test:

  1. in the first test case, the array [1] meets all conditions;
  2. in the second test case, the array [3,4,1] meets all conditions;
  3. in the third test case, the array [1,2,4] meets all conditions;
  4. in the fourth test case, the array [1,4,6,8,10,2,11] meets all conditions.

+
+ +
+
+ + +
+ +
B. Maximum Cost Deletion
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You are given a string s of length n consisting only of the characters 0 and 1.

You perform the following operation until the string becomes empty: choose some consecutive substring of equal characters, erase it from the string and glue the remaining two parts together (any of them can be empty) in the same order. For example, if you erase the substring 111 from the string 111110, you will get the string 110. When you delete a substring of length l, you get al+b points.

Your task is to calculate the maximum number of points that you can score in total, if you have to make the given string empty.

Input

The first line contains a single integer t (1t2000) — the number of testcases.

The first line of each testcase contains three integers n, a and b (1n100;100a,b100) — the length of the string s and the parameters a and b.

The second line contains the string s. The string s consists only of the characters 0 and 1.

Output

For each testcase, print a single integer — the maximum number of points that you can score.

Example
Input
Copy
3
+3 2 0
+000
+5 -2 5
+11001
+6 1 -4
+100111
+
Output
Copy
6
+15
+-2
+
Note

In the first example, it is enough to delete the entire string, then we will get 23+0=6 points.

In the second example, if we delete characters one by one, then for each deleted character we will get (2)1+5=3 points, i. e. 15 points in total.

In the third example, we can delete the substring 00 from the string 100111, we get 12+(4)=2 points, and the string will be equal to 1111, removing it entirely we get 14+(4)=0 points. In total, we got 2 points for 2 operations.

+
+ +
+
+ + +
+ +
C. Manhattan Subarrays
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Suppose you have two points p=(xp,yp) and q=(xq,yq). Let's denote the Manhattan distance between them as d(p,q)=|xpxq|+|ypyq|.

Let's say that three points p, q, r form a bad triple if d(p,r)=d(p,q)+d(q,r).

Let's say that an array b1,b2,,bm is good if it is impossible to choose three distinct indices i, j, k such that the points (bi,i), (bj,j) and (bk,k) form a bad triple.

You are given an array a1,a2,,an. Calculate the number of good subarrays of a. A subarray of the array a is the array al,al+1,,ar for some 1lrn.

Note that, according to the definition, subarrays of length 1 and 2 are good.

Input

The first line contains one integer t (1t5000) — the number of test cases.

The first line of each test case contains one integer n (1n2105) — the length of array a.

The second line of each test case contains n integers a1,a2,,an (1ai109).

It's guaranteed that the sum of n doesn't exceed 2105.

Output

For each test case, print the number of good subarrays of array a.

Example
Input
Copy
3
+4
+2 4 1 3
+5
+6 9 1 9 6
+2
+13 37
+
Output
Copy
10
+12
+3
+
Note

In the first test case, it can be proven that any subarray of a is good. For example, subarray [a2,a3,a4] is good since it contains only three elements and:

  • d((a2,2),(a4,4))=|43|+|24|=3<d((a2,2),(a3,3))+d((a3,3),(a4,4))=3+1+2+1=7;
  • d((a2,2),(a3,3))<d((a2,2),(a4,4))+d((a4,4),(a3,3));
  • d((a3,3),(a4,4))<d((a3,3),(a2,2))+d((a2,2),(a4,4));

In the second test case, for example, subarray [a1,a2,a3,a4] is not good, since it contains a bad triple (a1,1), (a2,2), (a4,4):

  • d((a1,1),(a4,4))=|69|+|14|=6;
  • d((a1,1),(a2,2))=|69|+|12|=4;
  • d((a2,2),(a4,4))=|99|+|24|=2;

So, d((a1,1),(a4,4))=d((a1,1),(a2,2))+d((a2,2),(a4,4)).

+
+ +
+
+ + +
+ +
D. Excellent Arrays
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Let's call an integer array a1,a2,,angood if aii for each i.

Let F(a) be the number of pairs (i,j) (1i<jn) such that ai+aj=i+j.

Let's say that an array a1,a2,,an is excellent if:

  • a is good;
  • lair for each i;
  • F(a) is the maximum possible among all good arrays of size n.

Given n, l and r, calculate the number of excellent arrays modulo 109+7.

Input

The first line contains a single integer t (1t1000) — the number of test cases.

The first and only line of each test case contains three integers n, l, and r (2n2105; 109l1; nr109).

It's guaranteed that the sum of n doesn't exceed 2105.

Output

For each test case, print the number of excellent arrays modulo 109+7.

Example
Input
Copy
4
+3 0 3
+4 -3 5
+42 -33 55
+69 -42 146
+
Output
Copy
4
+10
+143922563
+698570404
+
Note

In the first test case, it can be proven that the maximum F(a) among all good arrays a is equal to 2. The excellent arrays are:

  1. [2,1,2];
  2. [0,3,2];
  3. [2,3,2];
  4. [3,0,1].

+
+ +
+
+ + +
+ +
E. Stringforces
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You are given a string s of length n. Each character is either one of the first k lowercase Latin letters or a question mark.

You are asked to replace every question mark with one of the first k lowercase Latin letters in such a way that the following value is maximized.

Let fi be the maximum length substring of string s, which consists entirely of the i-th Latin letter. A substring of a string is a contiguous subsequence of that string. If the i-th letter doesn't appear in a string, then fi is equal to 0.

The value of a string s is the minimum value among fi for all i from 1 to k.

What is the maximum value the string can have?

Input

The first line contains two integers n and k (1n2105; 1k17) — the length of the string and the number of first Latin letters used.

The second line contains a string s, consisting of n characters. Each character is either one of the first k lowercase Latin letters or a question mark.

Output

Print a single integer — the maximum value of the string after every question mark is replaced with one of the first k lowercase Latin letters.

Examples
Input
Copy
10 2
+a??ab????b
+
Output
Copy
4
+
Input
Copy
9 4
+?????????
+
Output
Copy
2
+
Input
Copy
2 3
+??
+
Output
Copy
0
+
Input
Copy
15 3
+??b?babbc??b?aa
+
Output
Copy
3
+
Input
Copy
4 4
+cabd
+
Output
Copy
1
+
Note

In the first example the question marks can be replaced in the following way: "aaaababbbb". f1=4, f2=4, thus the answer is 4. Replacing it like this is also possible: "aaaabbbbbb". That way f1=4, f2=6, however, the minimum of them is still 4.

In the second example one of the possible strings is "aabbccdda".

In the third example at least one letter won't appear in the string, thus, the minimum of values fi is always 0.

+
+ +
+
+ + +
+ +
F. Jumping Around
time limit per test
5 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

There is an infinite pond that can be represented with a number line. There are n rocks in the pond, numbered from 1 to n. The i-th rock is located at an integer coordinate ai. The coordinates of the rocks are pairwise distinct. The rocks are numbered in the increasing order of the coordinate, so a1<a2<<an.

A robot frog sits on the rock number s. The frog is programmable. It has a base jumping distance parameter d. There also is a setting for the jumping distance range. If the jumping distance range is set to some integer k, then the frog can jump from some rock to any rock at a distance from dk to d+k inclusive in any direction. The distance between two rocks is an absolute difference between their coordinates.

You are assigned a task to implement a feature for the frog. Given two integers i and k determine if the frog can reach a rock number i from a rock number s performing a sequence of jumps with the jumping distance range set to k. The sequence can be arbitrarily long or empty.

You will be given q testcases for that feature, the j-th testcase consists of two integers i and k. Print "Yes" if the i-th rock is reachable and "No" otherwise.

You can output "YES" and "NO" in any case (for example, strings "yEs", "yes", "Yes" and 'YES"' will be recognized as a positive answer).

Input

The first line contains four integers n, q, s and d (1n,q2105; 1sn; 1d106) — the number of rocks, the number of testcases, the starting rock and the base jumping distance parameter.

The second line contains n integers a1,a2,,an (1ai106) — the coordinates of the rocks. The coordinates of the rocks are pairwise distinct. The rocks are numbered in the increasing order of distance from the land, so a1<a2<<an.

Each of the next q lines contains two integers i and k (1in; 1k106) — the parameters to the testcase.

Output

For each of the testcases print an answer. If there is a sequence of jumps from a rock number s to a rock number i with the jumping distance range set to k, then print "Yes". Otherwise, print "No".

Examples
Input
Copy
7 4 4 5
+1 5 10 13 20 22 28
+4 1
+7 2
+7 3
+3 2
+
Output
Copy
Yes
+No
+Yes
+Yes
+
Input
Copy
10 8 6 11
+1 2 4 7 8 9 11 13 19 20
+2 13
+5 8
+8 1
+6 15
+1 15
+2 7
+7 6
+8 9
+
Output
Copy
Yes
+Yes
+No
+Yes
+Yes
+Yes
+Yes
+Yes
+
Input
Copy
6 9 6 6
+1 2 4 9 18 19
+2 17
+1 18
+5 4
+2 11
+5 17
+6 8
+4 3
+3 3
+6 6
+
Output
Copy
Yes
+Yes
+Yes
+Yes
+Yes
+Yes
+No
+No
+Yes
+
Input
Copy
4 1 1 10
+1 8 10 19
+2 1
+
Output
Copy
Yes
+
Note

Explanation of the first example:

In the first testcase the destination rock is the same as the starting rock, thus no jumps are required to reach it.

In the second testcase the frog can jump any distance in the range [52;5+2]. Thus, it can reach rock number 5 (by jumping 7 to the right) and rock number 3 (by jumping 3 to the left). From rock number 3 it can reach rock number 2 (by jumping 5 to the left). From rock number 2 it can reach rock number 1 (by jumping 4 to the left). However, there is no way to reach rock number 7.

In the third testcase the frog can jump any distance in the range [53;5+3]. Thus, it can reach rock number 7 by jumping to rock 5 first and to 7 afterwards.

The fourth testcase is shown in the explanation for the second testcase.

+
+ +
+
+ + + +
+
\ No newline at end of file From b30c036478678068357a910c4bf6497f7fa5b0bf Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 5 Oct 2025 23:08:54 -0400 Subject: [PATCH 007/187] fix(ci): typing --- scrapers/base.py | 4 ++-- tests/conftest.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scrapers/base.py b/scrapers/base.py index dbf76e6..5c602a3 100644 --- a/scrapers/base.py +++ b/scrapers/base.py @@ -1,10 +1,10 @@ from abc import ABC, abstractmethod from typing import Any, Awaitable, Callable, ParamSpec, cast -P = ParamSpec("P") - from .models import ContestListResult, MetadataResult, TestsResult +P = ParamSpec("P") + class BaseScraper(ABC): @property diff --git a/tests/conftest.py b/tests/conftest.py index a2efcc0..b6940ab 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -205,7 +205,7 @@ def run_scraper_offline(fixture_text): sys.argv = old_argv json_lines: list[Any] = [] - for line in (l for l in out.splitlines() if l.strip()): + for line in (_line for _line in out.splitlines() if _line.strip()): json_lines.append(json.loads(line)) return rc, json_lines From c9ebdcdda578ab50148d326df0f12d0d01b4c3c9 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 5 Oct 2025 23:12:38 -0400 Subject: [PATCH 008/187] fix: pre-commit --- .pre-commit-config.yaml | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 60acfc6..74499e8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,21 +1,25 @@ minimum_pre_commit_version: "3.5.0" + repos: - repo: https://github.com/JohnnyMorganz/StyLua rev: v2.1.0 hooks: - id: stylua-github name: stylua (Lua formatter) - args: ["."] - additional_dependencies: [] + files: \.lua$ + pass_filenames: true + - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.6.9 hooks: - id: ruff-format name: ruff (format) - files: ^(scrapers/|tests/scrapers/|.*\.py$) + files: \.py$ - id: ruff - name: ruff (lint) - args: ["--fix", "--select=I", "."] + name: ruff (lint imports) + args: ["--fix", "--select=I"] + files: \.py$ + - repo: local hooks: - id: mypy @@ -24,9 +28,11 @@ repos: language: system args: ["."] pass_filenames: false + - repo: https://github.com/pre-commit/mirrors-prettier rev: v3.1.0 hooks: - id: prettier name: prettier (format markdown) - files: \.(md)$ + files: \.md$ + From 617c1741cc3b9c6581d6ae01d6ecf09c2532400b Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 5 Oct 2025 23:18:09 -0400 Subject: [PATCH 009/187] fix(ci): typing --- tests/conftest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index b6940ab..dfd8e7c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -185,13 +185,13 @@ def run_scraper_offline(fixture_text): offline_fetches = _make_offline_fetches(scraper_name) if scraper_name == "codeforces": - fetchers.stealthyfetcher.fetch = offline_fetches["stealthyfetcher.fetch"] # type: ignore + fetchers.StealthyFetcher.fetch = offline_fetches["StealthyFetcher.fetch"] # type: ignore[assignment] requests.get = offline_fetches["requests.get"] elif scraper_name == "atcoder": ns._fetch = offline_fetches["_fetch"] ns._get_async = offline_fetches["_get_async"] elif scraper_name == "cses": - httpx.asyncclient.get = offline_fetches["__offline_fetch_text"] # type: ignore + httpx.AsyncClient.get = offline_fetches["__offline_fetch_text"] # type: ignore[assignment] main_async = getattr(ns, "main_async") assert callable(main_async), f"main_async not found in {scraper_name}" From 6ae94887619f7722abbf4d2304eb21760f2339f1 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 5 Oct 2025 23:55:23 -0400 Subject: [PATCH 010/187] fix: typing --- lua/cp/scraper.lua | 8 +- lua/cp/setup.lua | 211 ++++++++++++++++++++++++++++++++++----------- lua/cp/state.lua | 40 ++++++++- 3 files changed, 205 insertions(+), 54 deletions(-) diff --git a/lua/cp/scraper.lua b/lua/cp/scraper.lua index 0c3494a..f8cb817 100644 --- a/lua/cp/scraper.lua +++ b/lua/cp/scraper.lua @@ -1,6 +1,6 @@ local M = {} -local constants = require('cp.log') +local constants = require('cp.constants') local logger = require('cp.log') local utils = require('cp.utils') @@ -168,7 +168,11 @@ function M.scrape_all_tests(platform, contest_id, callback) end if ev.error and ev.problem_id then logger.log( - ("Failed to load tests for problem '%s': %s"):format(contest_id, ev.problem_id, ev.error), + ("Failed to load tests for problem '%s' in contest '%s': %s"):format( + ev.problem_id, + contest_id, + ev.error + ), vim.log.levels.WARN ) return diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index 486aad9..e05c81b 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -2,12 +2,11 @@ local M = {} local cache = require('cp.cache') local config_module = require('cp.config') +local constants = require('cp.constants') local logger = require('cp.log') local scraper = require('cp.scraper') local state = require('cp.state') -local constants = require('cp.constants') - ---@class TestCaseLite ---@field input string ---@field expected string @@ -23,6 +22,46 @@ local constants = require('cp.constants') ---@field succeeded integer|nil ---@field failed integer|nil +---@param cd table|nil +---@return boolean +local function is_metadata_ready(cd) + return cd + and type(cd.problems) == 'table' + and #cd.problems > 0 + and type(cd.index_map) == 'table' + and next(cd.index_map) ~= nil +end + +---@param platform string +---@param contest_id string +---@param problems table +local function start_tests(platform, contest_id, problems) + local cached_len = #vim.tbl_filter(function(p) + return not vim.tbl_isempty(cache.get_test_cases(platform, contest_id, p.id)) + end, problems) + if cached_len ~= #problems then + logger.log(('Fetching test cases... (%d/%d)'):format(cached_len, #problems)) + scraper.scrape_all_tests(platform, contest_id, function(ev) + local cached_tests = {} + if not ev.interactive and vim.tbl_isempty(ev.tests) then + logger.log(("No tests found for problem '%s'."):format(ev.problem_id), vim.log.levels.WARN) + end + for i, t in ipairs(ev.tests) do + cached_tests[i] = { index = i, input = t.input, expected = t.expected } + end + cache.set_test_cases( + platform, + contest_id, + ev.problem_id, + cached_tests, + ev.timeout_ms or 0, + ev.memory_mb or 0, + ev.interactive + ) + end) + end +end + ---@param platform string ---@param contest_id string ---@param problem_id? string @@ -34,49 +73,86 @@ function M.setup_contest(platform, contest_id, problem_id, language) local function proceed(contest_data) local problems = contest_data.problems - local pid = problems[(problem_id and contest_data.index_map[problem_id] or 1)].id + local pid = problem_id and problem_id or problems[1].id M.setup_problem(pid, language) - - local cached_len = #vim.tbl_filter(function(p) - return not vim.tbl_isempty(cache.get_test_cases(platform, contest_id, p.id)) - end, problems) - - if cached_len ~= #problems then - logger.log(('Fetching test cases...'):format(cached_len, #problems)) - scraper.scrape_all_tests(platform, contest_id, function(ev) - local cached_tests = {} - if not ev.interactive and vim.tbl_isempty(ev.tests) then - logger.log( - ("No tests found for problem '%s'."):format(ev.problem_id), - vim.log.levels.WARN - ) - end - for i, t in ipairs(ev.tests) do - cached_tests[i] = { index = i, input = t.input, expected = t.expected } - end - cache.set_test_cases( - platform, - contest_id, - ev.problem_id, - cached_tests, - ev.timeout_ms or 0, - ev.memory_mb or 0, - ev.interactive - ) - logger.log('Test cases loaded.') - end) - end + start_tests(platform, contest_id, problems) end local contest_data = cache.get_contest_data(platform, contest_id) - if not contest_data or not contest_data.problems then + if not is_metadata_ready(contest_data) then + local cfg = config_module.get_config() + local lang = language or (cfg.platforms[platform] and cfg.platforms[platform].default_language) + + vim.cmd.only({ mods = { silent = true } }) + local bufnr = vim.api.nvim_create_buf(true, false) + vim.api.nvim_win_set_buf(0, bufnr) + if lang then + vim.bo[bufnr].filetype = lang + end + vim.bo[bufnr].buftype = '' + + local ext = cfg.runtime + and cfg.runtime.effective[platform] + and cfg.runtime.effective[platform][lang] + and cfg.runtime.effective[platform][lang].extension + local provisional_name = nil + if ext then + provisional_name = (config_module.default_filename(contest_id) .. '.' .. ext) + vim.api.nvim_buf_set_name(bufnr, provisional_name) + end + + if cfg.hooks and cfg.hooks.setup_code and not vim.b[bufnr].cp_setup_done then + local ok = pcall(cfg.hooks.setup_code, state) + if ok then + vim.b[bufnr].cp_setup_done = true + end + end + + if provisional_name then + cache.set_file_state( + vim.fn.fnamemodify(provisional_name, ':p'), + platform, + contest_id, + '', + lang + ) + end + + state.set_provisional({ + bufnr = bufnr, + platform = platform, + contest_id = contest_id, + language = lang, + requested_problem_id = problem_id, + token = vim.loop.hrtime(), + }) + logger.log('Fetching contests problems...', vim.log.levels.INFO, true) - scraper.scrape_contest_metadata(platform, contest_id, function(result) - local problems = result.problems or {} - cache.set_contest_data(platform, contest_id, problems) - logger.log(('Found %d problems for %s contest %s.'):format(#problems, platform, contest_id)) - proceed(cache.get_contest_data(platform, contest_id)) - end) + scraper.scrape_contest_metadata( + platform, + contest_id, + vim.schedule_wrap(function(result) + local problems = result.problems or {} + cache.set_contest_data(platform, contest_id, problems) + local prov = state.get_provisional() + if not prov or prov.platform ~= platform or prov.contest_id ~= contest_id then + return + end + local cd = cache.get_contest_data(platform, contest_id) + if not is_metadata_ready(cd) then + return + end + local pid = prov.requested_problem_id + if not pid or not cd.index_map or not cd.index_map[pid] then + pid = cd.problems[1] and cd.problems[1].id or nil + end + if not pid then + return + end + M.setup_problem(pid, prov.language) + start_tests(platform, contest_id, cd.problems) + end) + ) return end @@ -88,25 +164,58 @@ end function M.setup_problem(problem_id, language) local platform = state.get_platform() if not platform then - logger.log('No platform set.', vim.log.levels.ERROR) return end state.set_problem_id(problem_id) - local config = config_module.get_config() + local lang = language + or (config.platforms[platform] and config.platforms[platform].default_language) + local source_file = state.get_source_file(lang) + if not source_file then + return + end + + local prov = state.get_provisional() + if prov and prov.platform == platform and prov.contest_id == (state.get_contest_id() or '') then + if vim.api.nvim_buf_is_valid(prov.bufnr) then + local old = vim.api.nvim_buf_get_name(prov.bufnr) + local new = source_file + if old ~= '' and old ~= new then + local st = vim.loop.fs_stat(old) + if st and st.type == 'file' then + pcall(vim.loop.fs_rename, old, new) + end + end + vim.api.nvim_buf_set_name(prov.bufnr, new) + if config.hooks and config.hooks.setup_code and not vim.b[prov.bufnr].cp_setup_done then + local ok = pcall(config.hooks.setup_code, state) + if ok then + vim.b[prov.bufnr].cp_setup_done = true + end + end + cache.set_file_state( + vim.fn.fnamemodify(new, ':p'), + platform, + state.get_contest_id() or '', + state.get_problem_id() or '', + lang + ) + end + state.set_provisional(nil) + return + end vim.schedule(function() vim.cmd.only({ mods = { silent = true } }) - - local lang = language or config.platforms[platform].default_language - local source_file = state.get_source_file(lang) vim.cmd.e(source_file) - - if config.hooks and config.hooks.setup_code then - config.hooks.setup_code(state) + local bufnr = vim.api.nvim_get_current_buf() + if config.hooks and config.hooks.setup_code and not vim.b[bufnr].cp_setup_done then + local ok = pcall(config.hooks.setup_code, state) + if ok then + vim.b[bufnr].cp_setup_done = true + end end - cache.set_file_state( vim.fn.expand('%:p'), platform, @@ -117,6 +226,7 @@ function M.setup_problem(problem_id, language) end) end +---@param direction integer function M.navigate_problem(direction) if direction == 0 then return @@ -126,7 +236,6 @@ function M.navigate_problem(direction) local platform = state.get_platform() local contest_id = state.get_contest_id() local current_problem_id = state.get_problem_id() - if not platform or not contest_id or not current_problem_id then logger.log('No platform configured.', vim.log.levels.ERROR) return @@ -134,7 +243,7 @@ function M.navigate_problem(direction) cache.load() local contest_data = cache.get_contest_data(platform, contest_id) - if not contest_data or not contest_data.problems then + if not is_metadata_ready(contest_data) then logger.log( ('No data available for %s contest %s.'):format( constants.PLATFORM_DISPLAY_NAMES[platform], diff --git a/lua/cp/state.lua b/lua/cp/state.lua index e228212..9172fe4 100644 --- a/lua/cp/state.lua +++ b/lua/cp/state.lua @@ -1,3 +1,11 @@ +---@class cp.ProvisionalState +---@field bufnr integer +---@field platform string +---@field contest_id string +---@field language string +---@field requested_problem_id string|nil +---@field token integer + ---@class cp.State ---@field get_platform fun(): string? ---@field set_platform fun(platform: string) @@ -6,16 +14,19 @@ ---@field get_problem_id fun(): string? ---@field set_problem_id fun(problem_id: string) ---@field get_active_panel fun(): string? ----@field set_active_panel fun(): string? +---@field set_active_panel fun(panel: string?) ---@field get_base_name fun(): string? ---@field get_source_file fun(language?: string): string? ---@field get_binary_file fun(): string? ---@field get_input_file fun(): string? ---@field get_output_file fun(): string? ---@field get_expected_file fun(): string? +---@field get_provisional fun(): cp.ProvisionalState|nil +---@field set_provisional fun(p: cp.ProvisionalState|nil) local M = {} +---@type table local state = { platform = nil, contest_id = nil, @@ -23,32 +34,40 @@ local state = { test_cases = nil, saved_session = nil, active_panel = nil, + provisional = nil, } +---@return string|nil function M.get_platform() return state.platform end +---@param platform string function M.set_platform(platform) state.platform = platform end +---@return string|nil function M.get_contest_id() return state.contest_id end +---@param contest_id string function M.set_contest_id(contest_id) state.contest_id = contest_id end +---@return string|nil function M.get_problem_id() return state.problem_id end +---@param problem_id string function M.set_problem_id(problem_id) state.problem_id = problem_id end +---@return string|nil function M.get_base_name() local platform, contest_id, problem_id = M.get_platform(), M.get_contest_id(), M.get_problem_id() if not platform or not contest_id or not problem_id then @@ -65,10 +84,13 @@ function M.get_base_name() end end +---@return string|nil function M.get_language() return end +---@param language? string +---@return string|nil function M.get_source_file(language) local base_name = M.get_base_name() if not base_name or not M.get_platform() then @@ -90,34 +112,50 @@ function M.get_source_file(language) return base_name .. '.' .. eff.extension end +---@return string|nil function M.get_binary_file() local base_name = M.get_base_name() return base_name and ('build/%s.run'):format(base_name) or nil end +---@return string|nil function M.get_input_file() local base_name = M.get_base_name() return base_name and ('io/%s.cpin'):format(base_name) or nil end +---@return string|nil function M.get_output_file() local base_name = M.get_base_name() return base_name and ('io/%s.cpout'):format(base_name) or nil end +---@return string|nil function M.get_expected_file() local base_name = M.get_base_name() return base_name and ('io/%s.expected'):format(base_name) or nil end +---@return string|nil function M.get_active_panel() return state.active_panel end +---@param panel string|nil function M.set_active_panel(panel) state.active_panel = panel end +---@return cp.ProvisionalState|nil +function M.get_provisional() + return state.provisional +end + +---@param p cp.ProvisionalState|nil +function M.set_provisional(p) + state.provisional = p +end + M._state = state return M From e36a40a9ac9e8bcf44192f5181fee7a398f25292 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 5 Oct 2025 23:57:01 -0400 Subject: [PATCH 011/187] fix(ci): typing --- lua/cp/setup.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index e05c81b..1744655 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -26,10 +26,11 @@ local state = require('cp.state') ---@return boolean local function is_metadata_ready(cd) return cd - and type(cd.problems) == 'table' - and #cd.problems > 0 - and type(cd.index_map) == 'table' - and next(cd.index_map) ~= nil + and type(cd.problems) == 'table' + and #cd.problems > 0 + and type(cd.index_map) == 'table' + and next(cd.index_map) ~= nil + or false end ---@param platform string From 2bc56195fd8cb9b7a8384168c985303c19cf3b15 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 12 Oct 2025 14:14:56 -0400 Subject: [PATCH 012/187] fix(restore): state from :CP --- lua/cp/restore.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/cp/restore.lua b/lua/cp/restore.lua index 875e733..44cdfd4 100644 --- a/lua/cp/restore.lua +++ b/lua/cp/restore.lua @@ -16,7 +16,7 @@ function M.restore_from_current_file() end local setup = require('cp.setup') - setup.set_platform(file_state.platform) + state.set_platform(file_state.platform) state.set_contest_id(file_state.contest_id) state.set_problem_id(file_state.problem_id) setup.setup_contest( From c0e175d84b3eca3b3de02cc485c49a2dfe94146d Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 12 Oct 2025 16:19:02 -0400 Subject: [PATCH 013/187] feat(config): open url option --- lua/cp/cache.lua | 6 +++++- lua/cp/config.lua | 6 +++--- lua/cp/setup.lua | 10 +++++++--- lua/cp/utils.lua | 2 +- scrapers/atcoder.py | 8 ++++++-- scrapers/base.py | 2 +- scrapers/codeforces.py | 13 ++++++++++--- scrapers/cses.py | 14 +++++++++++--- scrapers/models.py | 2 +- 9 files changed, 45 insertions(+), 18 deletions(-) diff --git a/lua/cp/cache.lua b/lua/cp/cache.lua index 9e96caa..5c56ef8 100644 --- a/lua/cp/cache.lua +++ b/lua/cp/cache.lua @@ -9,6 +9,7 @@ ---@field index_map table ---@field name string ---@field display_name string +---@field url string ---@class ContestSummary ---@field display_name string @@ -94,11 +95,13 @@ end ---@param platform string ---@param contest_id string ---@param problems Problem[] -function M.set_contest_data(platform, contest_id, problems) +---@param url string +function M.set_contest_data(platform, contest_id, problems, url) vim.validate({ platform = { platform, 'string' }, contest_id = { contest_id, 'string' }, problems = { problems, 'table' }, + url = { url, 'string' }, }) cache_data[platform] = cache_data[platform] or {} @@ -109,6 +112,7 @@ function M.set_contest_data(platform, contest_id, problems) display_name = prev.display_name, problems = problems, index_map = {}, + url = url, } for i, p in ipairs(out.problems) do out.index_map[p.id] = i diff --git a/lua/cp/config.lua b/lua/cp/config.lua index 31540cf..ae66586 100644 --- a/lua/cp/config.lua +++ b/lua/cp/config.lua @@ -43,6 +43,7 @@ ---@field platforms table ---@field hooks Hooks ---@field debug boolean +---@field open_url boolean ---@field scrapers string[] ---@field filename? fun(contest: string, contest_id: string, problem_id?: string, config: cp.Config, language?: string): string ---@field ui CpUI @@ -58,6 +59,7 @@ local utils = require('cp.utils') -- defaults per the new single schema ---@type cp.Config M.defaults = { + open_url = false, languages = { cpp = { extension = 'cc', @@ -223,9 +225,7 @@ function M.setup(user_config) vim.validate({ hooks = { cfg.hooks, { 'table' } }, ui = { cfg.ui, { 'table' } }, - }) - - vim.validate({ + open_url = { cfg.open_url, { 'boolean', 'nil' }, true }, before_run = { cfg.hooks.before_run, { 'function', 'nil' }, true }, before_debug = { cfg.hooks.before_debug, { 'function', 'nil' }, true }, setup_code = { cfg.hooks.setup_code, { 'function', 'nil' }, true }, diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index 1744655..4c5fcae 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -77,6 +77,11 @@ function M.setup_contest(platform, contest_id, problem_id, language) local pid = problem_id and problem_id or problems[1].id M.setup_problem(pid, language) start_tests(platform, contest_id, problems) + + if contest_data.url and config_module.get_config().open_url then + vim.print('opening') + vim.ui.open(contest_data.url) + end end local contest_data = cache.get_contest_data(platform, contest_id) @@ -134,7 +139,7 @@ function M.setup_contest(platform, contest_id, problem_id, language) contest_id, vim.schedule_wrap(function(result) local problems = result.problems or {} - cache.set_contest_data(platform, contest_id, problems) + cache.set_contest_data(platform, contest_id, problems, result.url) local prov = state.get_provisional() if not prov or prov.platform ~= platform or prov.contest_id ~= contest_id then return @@ -150,8 +155,7 @@ function M.setup_contest(platform, contest_id, problem_id, language) if not pid then return end - M.setup_problem(pid, prov.language) - start_tests(platform, contest_id, cd.problems) + proceed(cd) end) ) return diff --git a/lua/cp/utils.lua b/lua/cp/utils.lua index e78b056..6ce2311 100644 --- a/lua/cp/utils.lua +++ b/lua/cp/utils.lua @@ -12,7 +12,7 @@ local _timeout_path = nil local _timeout_reason = nil local function is_windows() - return uname and uname.sysname == 'Windows_NT' + return uname.sysname == 'Windows_NT' end local function check_time_is_gnu_time(bin) diff --git a/scrapers/atcoder.py b/scrapers/atcoder.py index 7571a26..f565104 100644 --- a/scrapers/atcoder.py +++ b/scrapers/atcoder.py @@ -286,6 +286,7 @@ class AtcoderScraper(BaseScraper): error="", contest_id=cid, problems=problems, + url=f"https://atcoder.jp/contests/{contest_id}/tasks", ) return await self._safe_execute("metadata", impl, contest_id) @@ -335,6 +336,7 @@ async def main_async() -> int: result = MetadataResult( success=False, error="Usage: atcoder.py metadata OR atcoder.py tests OR atcoder.py contests", + url="", ) print(result.model_dump_json()) return 1 @@ -345,7 +347,9 @@ async def main_async() -> int: if mode == "metadata": if len(sys.argv) != 3: result = MetadataResult( - success=False, error="Usage: atcoder.py metadata " + success=False, + error="Usage: atcoder.py metadata ", + url="", ) print(result.model_dump_json()) return 1 @@ -360,7 +364,6 @@ async def main_async() -> int: success=False, error="Usage: atcoder.py tests ", problem_id="", - url="", tests=[], timeout_ms=0, memory_mb=0, @@ -385,6 +388,7 @@ async def main_async() -> int: result = MetadataResult( success=False, error="Unknown mode. Use 'metadata ', 'tests ', or 'contests'", + url="", ) print(result.model_dump_json()) return 1 diff --git a/scrapers/base.py b/scrapers/base.py index 5c602a3..315519c 100644 --- a/scrapers/base.py +++ b/scrapers/base.py @@ -28,6 +28,7 @@ class BaseScraper(ABC): error=f"{self.platform_name}: {error_msg}", contest_id=contest_id, problems=[], + url="", ) def _create_tests_error( @@ -37,7 +38,6 @@ class BaseScraper(ABC): success=False, error=f"{self.platform_name}: {error_msg}", problem_id=problem_id, - url=url, tests=[], timeout_ms=0, memory_mb=0, diff --git a/scrapers/codeforces.py b/scrapers/codeforces.py index b0eecc3..10287ae 100644 --- a/scrapers/codeforces.py +++ b/scrapers/codeforces.py @@ -198,7 +198,11 @@ class CodeforcesScraper(BaseScraper): f"No problems found for contest {cid}", cid ) return MetadataResult( - success=True, error="", contest_id=cid, problems=problems + success=True, + error="", + contest_id=cid, + problems=problems, + url=f"https://codeforces.com/contest/{contest_id}", ) return await self._safe_execute("metadata", impl, contest_id) @@ -259,6 +263,7 @@ async def main_async() -> int: result = MetadataResult( success=False, error="Usage: codeforces.py metadata OR codeforces.py tests OR codeforces.py contests", + url="", ) print(result.model_dump_json()) return 1 @@ -269,7 +274,9 @@ async def main_async() -> int: if mode == "metadata": if len(sys.argv) != 3: result = MetadataResult( - success=False, error="Usage: codeforces.py metadata " + success=False, + error="Usage: codeforces.py metadata ", + url="", ) print(result.model_dump_json()) return 1 @@ -284,7 +291,6 @@ async def main_async() -> int: success=False, error="Usage: codeforces.py tests ", problem_id="", - url="", tests=[], timeout_ms=0, memory_mb=0, @@ -309,6 +315,7 @@ async def main_async() -> int: result = MetadataResult( success=False, error="Unknown mode. Use 'metadata ', 'tests ', or 'contests'", + url="", ) print(result.model_dump_json()) return 1 diff --git a/scrapers/cses.py b/scrapers/cses.py index 2f76cc5..434e8a4 100644 --- a/scrapers/cses.py +++ b/scrapers/cses.py @@ -193,9 +193,14 @@ class CSESScraper(BaseScraper): return MetadataResult( success=False, error=f"{self.platform_name}: No problems found for category: {contest_id}", + url="", ) return MetadataResult( - success=True, error="", contest_id=contest_id, problems=problems + success=True, + error="", + contest_id=contest_id, + problems=problems, + url="https://cses.fi/problemset", ) async def scrape_contest_list(self) -> ContestListResult: @@ -249,6 +254,7 @@ async def main_async() -> int: result = MetadataResult( success=False, error="Usage: cses.py metadata OR cses.py tests OR cses.py contests", + url="", ) print(result.model_dump_json()) return 1 @@ -259,7 +265,9 @@ async def main_async() -> int: if mode == "metadata": if len(sys.argv) != 3: result = MetadataResult( - success=False, error="Usage: cses.py metadata " + success=False, + error="Usage: cses.py metadata ", + url="", ) print(result.model_dump_json()) return 1 @@ -274,7 +282,6 @@ async def main_async() -> int: success=False, error="Usage: cses.py tests ", problem_id="", - url="", tests=[], timeout_ms=0, memory_mb=0, @@ -299,6 +306,7 @@ async def main_async() -> int: result = MetadataResult( success=False, error=f"Unknown mode: {mode}. Use 'metadata ', 'tests ', or 'contests'", + url="", ) print(result.model_dump_json()) return 1 diff --git a/scrapers/models.py b/scrapers/models.py index d2cf19a..2a954ef 100644 --- a/scrapers/models.py +++ b/scrapers/models.py @@ -33,6 +33,7 @@ class ScrapingResult(BaseModel): class MetadataResult(ScrapingResult): contest_id: str = "" problems: list[ProblemSummary] = Field(default_factory=list) + url: str model_config = ConfigDict(extra="forbid") @@ -45,7 +46,6 @@ class ContestListResult(ScrapingResult): class TestsResult(ScrapingResult): problem_id: str - url: str tests: list[TestCase] = Field(default_factory=list) timeout_ms: int memory_mb: float From 600a578a17fcab3a8f8c519d359a6d041a87183a Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 12 Oct 2025 16:20:14 -0400 Subject: [PATCH 014/187] docs: update with `open_url` option --- doc/cp.nvim.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/cp.nvim.txt b/doc/cp.nvim.txt index 695a2cb..2557fb8 100644 --- a/doc/cp.nvim.txt +++ b/doc/cp.nvim.txt @@ -142,6 +142,7 @@ Here's an example configuration with lazy.nvim: default_language = 'cpp', }, }, + open_url = true, debug = false, ui = { run_panel = { @@ -210,6 +211,7 @@ run CSES problems with Rust using the single schema: Should return full filename with extension. (default: concatenates contest_id and problem_id, lowercased) {ui} (|CpUI|) UI settings: run panel, diff backend, picker. + {open_url} (boolean) Open the contest url in the browser. *CpPlatform* Fields: ~ From 32a46b4e98a42a9e6f8d2e264113b2fa1c2188ab Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 12 Oct 2025 16:23:06 -0400 Subject: [PATCH 015/187] feat: tests upgrade --- tests/test_scrapers.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/test_scrapers.py b/tests/test_scrapers.py index 83847ca..415f0dd 100644 --- a/tests/test_scrapers.py +++ b/tests/test_scrapers.py @@ -42,15 +42,13 @@ def test_scraper_offline_fixture_matrix(run_scraper_offline, scraper, mode): Model = MODEL_FOR_MODE[mode] model = Model.model_validate(objs[-1]) assert model is not None + assert model.success is True if mode == "metadata": - assert model.success in (True, False) - if model.success: - assert len(model.problems) >= 1 - assert all(isinstance(p.id, str) and p.id for p in model.problems) + assert model.url + assert len(model.problems) >= 1 + assert all(isinstance(p.id, str) and p.id for p in model.problems) else: - assert model.success in (True, False) - if model.success: - assert len(model.contests) >= 1 + assert len(model.contests) >= 1 else: validated_any = False for obj in objs: From 14b8bded1d5af0f20817a8e19fa726418e710df5 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 12 Oct 2025 16:39:06 -0400 Subject: [PATCH 016/187] fix: buffer name --- lua/cp/setup.lua | 42 ++++++++---------------------------------- lua/cp/state.lua | 7 ++----- 2 files changed, 10 insertions(+), 39 deletions(-) diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index 4c5fcae..3d5715e 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -79,7 +79,6 @@ function M.setup_contest(platform, contest_id, problem_id, language) start_tests(platform, contest_id, problems) if contest_data.url and config_module.get_config().open_url then - vim.print('opening') vim.ui.open(contest_data.url) end end @@ -92,20 +91,9 @@ function M.setup_contest(platform, contest_id, problem_id, language) vim.cmd.only({ mods = { silent = true } }) local bufnr = vim.api.nvim_create_buf(true, false) vim.api.nvim_win_set_buf(0, bufnr) - if lang then - vim.bo[bufnr].filetype = lang - end + vim.bo[bufnr].filetype = lang or '' vim.bo[bufnr].buftype = '' - - local ext = cfg.runtime - and cfg.runtime.effective[platform] - and cfg.runtime.effective[platform][lang] - and cfg.runtime.effective[platform][lang].extension - local provisional_name = nil - if ext then - provisional_name = (config_module.default_filename(contest_id) .. '.' .. ext) - vim.api.nvim_buf_set_name(bufnr, provisional_name) - end + vim.bo[bufnr].swapfile = false if cfg.hooks and cfg.hooks.setup_code and not vim.b[bufnr].cp_setup_done then local ok = pcall(cfg.hooks.setup_code, state) @@ -114,16 +102,6 @@ function M.setup_contest(platform, contest_id, problem_id, language) end end - if provisional_name then - cache.set_file_state( - vim.fn.fnamemodify(provisional_name, ':p'), - platform, - contest_id, - '', - lang - ) - end - state.set_provisional({ bufnr = bufnr, platform = platform, @@ -181,18 +159,14 @@ function M.setup_problem(problem_id, language) return end + vim.fn.mkdir(vim.fn.fnamemodify(source_file, ':h'), 'p') + local prov = state.get_provisional() if prov and prov.platform == platform and prov.contest_id == (state.get_contest_id() or '') then if vim.api.nvim_buf_is_valid(prov.bufnr) then - local old = vim.api.nvim_buf_get_name(prov.bufnr) - local new = source_file - if old ~= '' and old ~= new then - local st = vim.loop.fs_stat(old) - if st and st.type == 'file' then - pcall(vim.loop.fs_rename, old, new) - end - end - vim.api.nvim_buf_set_name(prov.bufnr, new) + vim.api.nvim_buf_set_name(prov.bufnr, source_file) + vim.bo[prov.bufnr].swapfile = true + vim.cmd(string.format('silent keepalt noautocmd write! %s', vim.fn.fnameescape(source_file))) if config.hooks and config.hooks.setup_code and not vim.b[prov.bufnr].cp_setup_done then local ok = pcall(config.hooks.setup_code, state) if ok then @@ -200,7 +174,7 @@ function M.setup_problem(problem_id, language) end end cache.set_file_state( - vim.fn.fnamemodify(new, ':p'), + vim.fn.fnamemodify(source_file, ':p'), platform, state.get_contest_id() or '', state.get_problem_id() or '', diff --git a/lua/cp/state.lua b/lua/cp/state.lua index 9172fe4..63613a3 100644 --- a/lua/cp/state.lua +++ b/lua/cp/state.lua @@ -84,11 +84,6 @@ function M.get_base_name() end end ----@return string|nil -function M.get_language() - return -end - ---@param language? string ---@return string|nil function M.get_source_file(language) @@ -103,12 +98,14 @@ function M.get_source_file(language) if not platform_cfg then return nil end + local target_language = language or platform_cfg.default_language local eff = config.runtime.effective[plat] and config.runtime.effective[plat][target_language] or nil if not eff or not eff.extension then return nil end + return base_name .. '.' .. eff.extension end From 7f9f60af5be1ccb790736afa3feb1b0ff8d479b9 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 12 Oct 2025 20:31:11 -0400 Subject: [PATCH 017/187] fix: don't always open new window --- lua/cp/restore.lua | 2 -- lua/cp/setup.lua | 7 ++++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lua/cp/restore.lua b/lua/cp/restore.lua index 44cdfd4..fde3fd5 100644 --- a/lua/cp/restore.lua +++ b/lua/cp/restore.lua @@ -16,8 +16,6 @@ function M.restore_from_current_file() end local setup = require('cp.setup') - state.set_platform(file_state.platform) - state.set_contest_id(file_state.contest_id) state.set_problem_id(file_state.problem_id) setup.setup_contest( file_state.platform, diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index 3d5715e..f0001a8 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -68,8 +68,13 @@ end ---@param problem_id? string ---@param language? string function M.setup_contest(platform, contest_id, problem_id, language) + local old_platform, old_contest_id = state.get_platform(), state.get_contest_id() + state.set_platform(platform) state.set_contest_id(contest_id) + + local is_new_contest = old_platform ~= platform and old_contest_id ~= contest_id + cache.load() local function proceed(contest_data) @@ -78,7 +83,7 @@ function M.setup_contest(platform, contest_id, problem_id, language) M.setup_problem(pid, language) start_tests(platform, contest_id, problems) - if contest_data.url and config_module.get_config().open_url then + if config_module.get_config().open_url and is_new_contest and contest_data.url then vim.ui.open(contest_data.url) end end From 352f98f26fb20bb9d745cfbddff94f2ec458ed19 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Wed, 15 Oct 2025 11:00:31 -0400 Subject: [PATCH 018/187] fix: open problem-specific url --- .gitignore | 1 + doc/cp.nvim.txt | 3 ++- lua/cp/setup.lua | 2 +- scrapers/atcoder.py | 2 +- scrapers/codeforces.py | 2 +- scrapers/cses.py | 2 +- 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 780dcd2..ddee7e1 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ io debug venv/ CLAUDE.md +__pycache__ diff --git a/doc/cp.nvim.txt b/doc/cp.nvim.txt index 2557fb8..ac993b7 100644 --- a/doc/cp.nvim.txt +++ b/doc/cp.nvim.txt @@ -211,7 +211,8 @@ run CSES problems with Rust using the single schema: Should return full filename with extension. (default: concatenates contest_id and problem_id, lowercased) {ui} (|CpUI|) UI settings: run panel, diff backend, picker. - {open_url} (boolean) Open the contest url in the browser. + {open_url} (boolean) Open the contest & problem url in the browser + when the contest is first opened. *CpPlatform* Fields: ~ diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index f0001a8..6dd579f 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -84,7 +84,7 @@ function M.setup_contest(platform, contest_id, problem_id, language) start_tests(platform, contest_id, problems) if config_module.get_config().open_url and is_new_contest and contest_data.url then - vim.ui.open(contest_data.url) + vim.ui.open(contest_data.url:format(pid)) end end diff --git a/scrapers/atcoder.py b/scrapers/atcoder.py index f565104..41f50ad 100644 --- a/scrapers/atcoder.py +++ b/scrapers/atcoder.py @@ -286,7 +286,7 @@ class AtcoderScraper(BaseScraper): error="", contest_id=cid, problems=problems, - url=f"https://atcoder.jp/contests/{contest_id}/tasks", + url=f"https://atcoder.jp/contests/{contest_id}/tasks/{contest_id}_%s", ) return await self._safe_execute("metadata", impl, contest_id) diff --git a/scrapers/codeforces.py b/scrapers/codeforces.py index 10287ae..c540ba1 100644 --- a/scrapers/codeforces.py +++ b/scrapers/codeforces.py @@ -202,7 +202,7 @@ class CodeforcesScraper(BaseScraper): error="", contest_id=cid, problems=problems, - url=f"https://codeforces.com/contest/{contest_id}", + url=f"https://codeforces.com/contest/{contest_id}/%s", ) return await self._safe_execute("metadata", impl, contest_id) diff --git a/scrapers/cses.py b/scrapers/cses.py index 434e8a4..b8a6145 100644 --- a/scrapers/cses.py +++ b/scrapers/cses.py @@ -200,7 +200,7 @@ class CSESScraper(BaseScraper): error="", contest_id=contest_id, problems=problems, - url="https://cses.fi/problemset", + url="https://cses.fi/problemset/task/%s", ) async def scrape_contest_list(self) -> ContestListResult: From 018d801121a88b45b27fde74ac72d0c566073cef Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 23 Oct 2025 09:54:55 -0400 Subject: [PATCH 019/187] fix: rename run panel to panel --- doc/cp.nvim.txt | 16 ++++++++-------- lua/cp/commands/init.lua | 4 ++-- lua/cp/config.lua | 12 ++++++------ lua/cp/init.lua | 1 - lua/cp/runner/run.lua | 36 ++++++++++++++++++------------------ lua/cp/runner/run_render.lua | 2 +- lua/cp/ui/layouts.lua | 4 ++-- lua/cp/ui/panel.lua | 30 +++++++++++++++--------------- spec/execute_spec.lua | 2 +- 9 files changed, 53 insertions(+), 54 deletions(-) diff --git a/doc/cp.nvim.txt b/doc/cp.nvim.txt index ac993b7..5dd17b1 100644 --- a/doc/cp.nvim.txt +++ b/doc/cp.nvim.txt @@ -145,7 +145,7 @@ Here's an example configuration with lazy.nvim: open_url = true, debug = false, ui = { - run_panel = { + panel = { ansi = true, diff_mode = 'vim', max_output_lines = 50, @@ -210,7 +210,7 @@ run CSES problems with Rust using the single schema: function(contest, contest_id, problem_id, config, language): string Should return full filename with extension. (default: concatenates contest_id and problem_id, lowercased) - {ui} (|CpUI|) UI settings: run panel, diff backend, picker. + {ui} (|CpUI|) UI settings: panel, diff backend, picker. {open_url} (boolean) Open the contest & problem url in the browser when the contest is first opened. @@ -238,11 +238,11 @@ run CSES problems with Rust using the single schema: *CpUI* Fields: ~ - {run_panel} (|RunPanelConfig|) Test panel behavior configuration. + {panel} (|PanelConfig|) Test panel behavior configuration. {diff} (|DiffConfig|) Diff backend configuration. {picker} (string|nil) 'telescope', 'fzf-lua', or nil. - *cp.RunPanelConfig* + *cp.PanelConfig* Fields: ~ {ansi} (boolean, default: true) Enable ANSI color parsing and highlighting. @@ -367,15 +367,15 @@ PICKER KEYMAPS *cp-picker-keys* Useful when contest lists are outdated or incomplete ============================================================================== -RUN PANEL *cp-run* +PANEL *cp-run* -The run panel provides individual test case debugging. Problem time/memory +The panel provides individual test case debugging. Problem time/memory limit constraints are in columns Time/Mem respectively. Used time/memory are in columns Runtime/RSS respectively. Interface ~ -The run panel uses the following table layout: > +The panel uses the following table layout: > ┌─────┬────────┬──────────────┬───────────┬──────────┬──────────┬─────────────┐ │ # │ Status │ Runtime (ms) │ Time (ms) │ RSS (MB) │ Mem (MB) │ Exit Code │ @@ -502,7 +502,7 @@ Customize highlight groups after your colorscheme loads: }) ============================================================================== -RUN PANEL KEYMAPS *cp-test-keys* +PANEL KEYMAPS *cp-test-keys* Navigate to next test case Navigate to previous test case diff --git a/lua/cp/commands/init.lua b/lua/cp/commands/init.lua index 9583204..a7bd626 100644 --- a/lua/cp/commands/init.lua +++ b/lua/cp/commands/init.lua @@ -109,9 +109,9 @@ function M.handle_command(opts) if cmd.action == 'interact' then ui.toggle_interactive(cmd.interactor_cmd) elseif cmd.action == 'run' then - ui.toggle_run_panel() + ui.toggle_panel() elseif cmd.action == 'debug' then - ui.toggle_run_panel({ debug = true }) + ui.toggle_panel({ debug = true }) elseif cmd.action == 'next' then setup.navigate_problem(1) elseif cmd.action == 'prev' then diff --git a/lua/cp/config.lua b/lua/cp/config.lua index ae66586..4e787b4 100644 --- a/lua/cp/config.lua +++ b/lua/cp/config.lua @@ -17,7 +17,7 @@ ---@field default_language string ---@field overrides? table ----@class RunPanelConfig +---@class PanelConfig ---@field ansi boolean ---@field diff_mode "none"|"vim"|"git" ---@field max_output_lines integer @@ -34,7 +34,7 @@ ---@field setup_code? fun(state: cp.State) ---@class CpUI ----@field run_panel RunPanelConfig +---@field panel PanelConfig ---@field diff DiffConfig ---@field picker string|nil @@ -106,7 +106,7 @@ M.defaults = { scrapers = constants.PLATFORMS, filename = nil, ui = { - run_panel = { ansi = true, diff_mode = 'none', max_output_lines = 50 }, + panel = { ansi = true, diff_mode = 'none', max_output_lines = 50 }, diff = { git = { args = { 'diff', '--no-index', '--word-diff=plain', '--word-diff-regex=.', '--no-prefix' }, @@ -232,16 +232,16 @@ function M.setup(user_config) }) vim.validate({ - ansi = { cfg.ui.run_panel.ansi, 'boolean' }, + ansi = { cfg.ui.panel.ansi, 'boolean' }, diff_mode = { - cfg.ui.run_panel.diff_mode, + cfg.ui.panel.diff_mode, function(v) return vim.tbl_contains({ 'none', 'vim', 'git' }, v) end, "diff_mode must be 'none', 'vim', or 'git'", }, max_output_lines = { - cfg.ui.run_panel.max_output_lines, + cfg.ui.panel.max_output_lines, function(v) return type(v) == 'number' and v > 0 and v == math.floor(v) end, diff --git a/lua/cp/init.lua b/lua/cp/init.lua index 4e2be8a..366517c 100644 --- a/lua/cp/init.lua +++ b/lua/cp/init.lua @@ -12,7 +12,6 @@ local user_config = {} local config = nil local initialized = false ---- Root handler for all `:CP ...` commands ---@return nil function M.handle_command(opts) local commands = require('cp.commands') diff --git a/lua/cp/runner/run.lua b/lua/cp/runner/run.lua index 16ae696..367d9ec 100644 --- a/lua/cp/runner/run.lua +++ b/lua/cp/runner/run.lua @@ -20,7 +20,7 @@ ---@field timeout_ms number ---@field memory_mb number ----@class RunPanelState +---@class PanelState ---@field test_cases RanTestCase[] ---@field current_index number ---@field buffer number? @@ -37,8 +37,8 @@ local execute = require('cp.runner.execute') local logger = require('cp.log') local state = require('cp.state') ----@type RunPanelState -local run_panel_state = { +---@type PanelState +local panel_state = { test_cases = {}, current_index = 1, buffer = nil, @@ -113,8 +113,8 @@ local function run_single_test_case(test_case) local run_template = eff and eff.commands and eff.commands.run or {} local cmd = build_command(run_template, substitutions) local stdin_content = (test_case.input or '') .. '\n' - local timeout_ms = (run_panel_state.constraints and run_panel_state.constraints.timeout_ms) or 0 - local memory_mb = run_panel_state.constraints and run_panel_state.constraints.memory_mb or 0 + local timeout_ms = (panel_state.constraints and panel_state.constraints.timeout_ms) or 0 + local memory_mb = panel_state.constraints and panel_state.constraints.memory_mb or 0 local r = execute.run(cmd, stdin_content, timeout_ms, memory_mb) @@ -122,7 +122,7 @@ local function run_single_test_case(test_case) local out = r.stdout or '' local highlights = {} if out ~= '' then - if config.ui.run_panel.ansi then + if config.ui.panel.ansi then local parsed = ansi.parse_ansi_text(out) out = table.concat(parsed.lines, '\n') highlights = parsed.highlights @@ -131,7 +131,7 @@ local function run_single_test_case(test_case) end end - local max_lines = config.ui.run_panel.max_output_lines + local max_lines = config.ui.panel.max_output_lines local lines = vim.split(out, '\n') if #lines > max_lines then local trimmed = {} @@ -185,9 +185,9 @@ function M.load_test_cases() state.get_problem_id() ) - run_panel_state.test_cases = create_sentinal_panel_data(tcs) - run_panel_state.current_index = 1 - run_panel_state.constraints = load_constraints_from_cache( + panel_state.test_cases = create_sentinal_panel_data(tcs) + panel_state.current_index = 1 + panel_state.constraints = load_constraints_from_cache( state.get_platform() or '', state.get_contest_id() or '', state.get_problem_id() @@ -200,7 +200,7 @@ end ---@param index number ---@return boolean function M.run_test_case(index) - local tc = run_panel_state.test_cases[index] + local tc = panel_state.test_cases[index] if not tc then return false end @@ -227,16 +227,16 @@ end ---@return RanTestCase[] function M.run_all_test_cases() local results = {} - for i = 1, #run_panel_state.test_cases do + for i = 1, #panel_state.test_cases do M.run_test_case(i) - results[i] = run_panel_state.test_cases[i] + results[i] = panel_state.test_cases[i] end return results end ----@return RunPanelState -function M.get_run_panel_state() - return run_panel_state +---@return PanelState +function M.get_panel_state() + return panel_state end ---@param output string|nil @@ -247,7 +247,7 @@ function M.handle_compilation_failure(output) local txt local hl = {} - if config.ui.run_panel.ansi then + if config.ui.panel.ansi then local p = ansi.parse_ansi_text(output or '') txt = table.concat(p.lines, '\n') hl = p.highlights @@ -255,7 +255,7 @@ function M.handle_compilation_failure(output) txt = (output or ''):gsub('\027%[[%d;]*[a-zA-Z]', '') end - for _, tc in ipairs(run_panel_state.test_cases) do + for _, tc in ipairs(panel_state.test_cases) do tc.status = 'fail' tc.actual = txt tc.actual_highlights = hl diff --git a/lua/cp/runner/run_render.lua b/lua/cp/runner/run_render.lua index 027aae3..0847793 100644 --- a/lua/cp/runner/run_render.lua +++ b/lua/cp/runner/run_render.lua @@ -275,7 +275,7 @@ local function data_row(c, idx, tc, is_current, test_state) return line, hi end ----@param test_state RunPanelState +---@param test_state PanelState ---@return string[], Highlight[] lines and highlight positions function M.render_test_list(test_state) local lines, highlights = {}, {} diff --git a/lua/cp/ui/layouts.lua b/lua/cp/ui/layouts.lua index ea73cd7..d5470d1 100644 --- a/lua/cp/ui/layouts.lua +++ b/lua/cp/ui/layouts.lua @@ -164,7 +164,7 @@ function M.update_diff_panes( config, setup_keybindings_for_buffer ) - local test_state = run.get_run_panel_state() + local test_state = run.get_panel_state() local current_test = test_state.test_cases[test_state.current_index] if not current_test then @@ -185,7 +185,7 @@ function M.update_diff_panes( actual_content = actual_content end - local desired_mode = is_compilation_failure and 'single' or config.ui.run_panel.diff_mode + local desired_mode = is_compilation_failure and 'single' or config.ui.panel.diff_mode local highlight = require('cp.ui.highlight') local diff_namespace = highlight.create_namespace() local ansi_namespace = vim.api.nvim_create_namespace('cp_ansi_highlights') diff --git a/lua/cp/ui/panel.lua b/lua/cp/ui/panel.lua index 32bef7c..9b1ab05 100644 --- a/lua/cp/ui/panel.lua +++ b/lua/cp/ui/panel.lua @@ -1,6 +1,6 @@ local M = {} ----@class RunOpts +---@class PanelOpts ---@field debug? boolean local config_module = require('cp.config') @@ -21,7 +21,7 @@ function M.disable() end if active_panel == 'run' then - M.toggle_run_panel() + M.toggle_panel() elseif active_panel == 'interactive' then M.toggle_interactive() else @@ -204,8 +204,8 @@ function M.toggle_interactive(interactor_cmd) state.set_active_panel('interactive') end ----@param run_opts? RunOpts -function M.toggle_run_panel(run_opts) +---@param panel_opts? PanelOpts +function M.toggle_panel(panel_opts) if state.get_active_panel() == 'run' then if current_diff_layout then current_diff_layout.cleanup() @@ -294,13 +294,13 @@ function M.toggle_run_panel(run_opts) ) end - local function refresh_run_panel() + local function refresh_panel() if not test_buffers.tab_buf or not vim.api.nvim_buf_is_valid(test_buffers.tab_buf) then return end local run_render = require('cp.runner.run_render') run_render.setup_highlights() - local test_state = run.get_run_panel_state() + local test_state = run.get_panel_state() local tab_lines, tab_highlights = run_render.render_test_list(test_state) utils.update_buffer_content( test_buffers.tab_buf, @@ -312,29 +312,29 @@ function M.toggle_run_panel(run_opts) end local function navigate_test_case(delta) - local test_state = run.get_run_panel_state() + local test_state = run.get_panel_state() if vim.tbl_isempty(test_state.test_cases) then return end test_state.current_index = (test_state.current_index + delta - 1) % #test_state.test_cases + 1 - refresh_run_panel() + refresh_panel() end setup_keybindings_for_buffer = function(buf) vim.keymap.set('n', 'q', function() - M.toggle_run_panel() + M.toggle_panel() end, { buffer = buf, silent = true }) vim.keymap.set('n', 't', function() local modes = { 'none', 'git', 'vim' } local current_idx = 1 for i, mode in ipairs(modes) do - if config.ui.run_panel.diff_mode == mode then + if config.ui.panel.diff_mode == mode then current_idx = i break end end - config.ui.run_panel.diff_mode = modes[(current_idx % #modes) + 1] - refresh_run_panel() + config.ui.panel.diff_mode = modes[(current_idx % #modes) + 1] + refresh_panel() end, { buffer = buf, silent = true }) vim.keymap.set('n', '', function() navigate_test_case(1) @@ -351,7 +351,7 @@ function M.toggle_run_panel(run_opts) config.hooks.before_run(state) end) end - if run_opts and run_opts.debug and config.hooks and config.hooks.before_debug then + if panel_opts and panel_opts.debug and config.hooks and config.hooks.before_debug then vim.schedule_wrap(function() config.hooks.before_debug(state) end) @@ -365,10 +365,10 @@ function M.toggle_run_panel(run_opts) run.handle_compilation_failure(compile_result.output) end - refresh_run_panel() + refresh_panel() vim.schedule(function() - if config.ui.run_panel.ansi then + if config.ui.panel.ansi then local ansi = require('cp.ui.ansi') ansi.setup_highlight_groups() end diff --git a/spec/execute_spec.lua b/spec/execute_spec.lua index f401605..12d85d2 100644 --- a/spec/execute_spec.lua +++ b/spec/execute_spec.lua @@ -3,7 +3,7 @@ describe('run module', function() describe('basic functionality', function() it('can get panel state', function() - local state = run.get_run_panel_state() + local state = run.get_panel_state() assert.is_table(state) assert.is_table(state.test_cases) end) From 347be7277410e4c434162732100db539d2773c5f Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 23 Oct 2025 10:07:22 -0400 Subject: [PATCH 020/187] feat: add solution to window state --- lua/cp/setup.lua | 2 ++ lua/cp/state.lua | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index 6dd579f..12fde62 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -172,6 +172,7 @@ function M.setup_problem(problem_id, language) vim.api.nvim_buf_set_name(prov.bufnr, source_file) vim.bo[prov.bufnr].swapfile = true vim.cmd(string.format('silent keepalt noautocmd write! %s', vim.fn.fnameescape(source_file))) + state.set_solution_win(vim.api.nvim_get_current_win()) if config.hooks and config.hooks.setup_code and not vim.b[prov.bufnr].cp_setup_done then local ok = pcall(config.hooks.setup_code, state) if ok then @@ -194,6 +195,7 @@ function M.setup_problem(problem_id, language) vim.cmd.only({ mods = { silent = true } }) vim.cmd.e(source_file) local bufnr = vim.api.nvim_get_current_buf() + state.set_solution_win(vim.api.nvim_get_current_win()) if config.hooks and config.hooks.setup_code and not vim.b[bufnr].cp_setup_done then local ok = pcall(config.hooks.setup_code, state) if ok then diff --git a/lua/cp/state.lua b/lua/cp/state.lua index 63613a3..c234387 100644 --- a/lua/cp/state.lua +++ b/lua/cp/state.lua @@ -35,6 +35,7 @@ local state = { saved_session = nil, active_panel = nil, provisional = nil, + solution_win = nil, } ---@return string|nil @@ -153,6 +154,19 @@ function M.set_provisional(p) state.provisional = p end +---@return integer? +function M.get_solution_win() + if state.solution_win and vim.api.nvim_win_is_valid(state.solution_win) then + return state.solution_win + end + return vim.api.nvim_get_current_win() +end + +---@param win integer? +function M.set_solution_win(win) + state.solution_win = win +end + M._state = state return M From ad17855532120a6d21d43b3cd4a8204d7259a3af Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 23 Oct 2025 10:27:40 -0400 Subject: [PATCH 021/187] feat(ui): io view --- lua/cp/state.lua | 75 +++++++++++++++++++----- lua/cp/ui/panel.lua | 139 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 192 insertions(+), 22 deletions(-) diff --git a/lua/cp/state.lua b/lua/cp/state.lua index c234387..4a3ff79 100644 --- a/lua/cp/state.lua +++ b/lua/cp/state.lua @@ -3,9 +3,15 @@ ---@field platform string ---@field contest_id string ---@field language string ----@field requested_problem_id string|nil +---@field requested_problem_id string? ---@field token integer +---@class cp.IoViewState +---@field output_buf integer +---@field input_buf integer +---@field output_win integer +---@field input_win integer + ---@class cp.State ---@field get_platform fun(): string? ---@field set_platform fun(platform: string) @@ -21,8 +27,12 @@ ---@field get_input_file fun(): string? ---@field get_output_file fun(): string? ---@field get_expected_file fun(): string? ----@field get_provisional fun(): cp.ProvisionalState|nil ----@field set_provisional fun(p: cp.ProvisionalState|nil) +---@field get_provisional fun(): cp.ProvisionalState? +---@field set_provisional fun(p: cp.ProvisionalState?) +---@field get_saved_session fun(): string? +---@field set_saved_session fun(path: string?) +---@field get_io_view_state fun(): cp.IoViewState? +---@field set_io_view_state fun(s: cp.IoViewState?) local M = {} @@ -36,9 +46,10 @@ local state = { active_panel = nil, provisional = nil, solution_win = nil, + io_view_state = nil, } ----@return string|nil +---@return string? function M.get_platform() return state.platform end @@ -48,7 +59,7 @@ function M.set_platform(platform) state.platform = platform end ----@return string|nil +---@return string? function M.get_contest_id() return state.contest_id end @@ -58,7 +69,7 @@ function M.set_contest_id(contest_id) state.contest_id = contest_id end ----@return string|nil +---@return string? function M.get_problem_id() return state.problem_id end @@ -68,7 +79,7 @@ function M.set_problem_id(problem_id) state.problem_id = problem_id end ----@return string|nil +---@return string? function M.get_base_name() local platform, contest_id, problem_id = M.get_platform(), M.get_contest_id(), M.get_problem_id() if not platform or not contest_id or not problem_id then @@ -86,7 +97,7 @@ function M.get_base_name() end ---@param language? string ----@return string|nil +---@return string? function M.get_source_file(language) local base_name = M.get_base_name() if not base_name or not M.get_platform() then @@ -110,46 +121,46 @@ function M.get_source_file(language) return base_name .. '.' .. eff.extension end ----@return string|nil +---@return string? function M.get_binary_file() local base_name = M.get_base_name() return base_name and ('build/%s.run'):format(base_name) or nil end ----@return string|nil +---@return string? function M.get_input_file() local base_name = M.get_base_name() return base_name and ('io/%s.cpin'):format(base_name) or nil end ----@return string|nil +---@return string? function M.get_output_file() local base_name = M.get_base_name() return base_name and ('io/%s.cpout'):format(base_name) or nil end ----@return string|nil +---@return string? function M.get_expected_file() local base_name = M.get_base_name() return base_name and ('io/%s.expected'):format(base_name) or nil end ----@return string|nil +---@return string? function M.get_active_panel() return state.active_panel end ----@param panel string|nil +---@param panel string? function M.set_active_panel(panel) state.active_panel = panel end ----@return cp.ProvisionalState|nil +---@return cp.ProvisionalState? function M.get_provisional() return state.provisional end ----@param p cp.ProvisionalState|nil +---@param p cp.ProvisionalState? function M.set_provisional(p) state.provisional = p end @@ -167,6 +178,38 @@ function M.set_solution_win(win) state.solution_win = win end +---@return cp.IoViewState? +function M.get_io_view_state() + if not state.io_view_state then + return nil + end + local s = state.io_view_state + if + vim.api.nvim_buf_is_valid(s.output_buf) + and vim.api.nvim_buf_is_valid(s.input_buf) + and vim.api.nvim_win_is_valid(s.output_win) + and vim.api.nvim_win_is_valid(s.input_win) + then + return s + end + return nil +end + +---@param s cp.IoViewState? +function M.set_io_view_state(s) + state.io_view_state = s +end + +---@return string? +function M.get_saved_session() + return state.saved_session +end + +---@param path string? +function M.set_saved_session(path) + state.saved_session = path +end + M._state = state return M diff --git a/lua/cp/ui/panel.lua b/lua/cp/ui/panel.lua index 9b1ab05..19bbfc4 100644 --- a/lua/cp/ui/panel.lua +++ b/lua/cp/ui/panel.lua @@ -204,6 +204,131 @@ function M.toggle_interactive(interactor_cmd) state.set_active_panel('interactive') end +function M.toggle_io_view() + local io_state = state.get_io_view_state() + if io_state then + if vim.api.nvim_buf_is_valid(io_state.output_buf) then + vim.api.nvim_buf_delete(io_state.output_buf, { force = true }) + end + if vim.api.nvim_buf_is_valid(io_state.input_buf) then + vim.api.nvim_buf_delete(io_state.input_buf, { force = true }) + end + state.set_io_view_state(nil) + return + end + + local platform, contest_id = state.get_platform(), state.get_contest_id() + if not platform then + logger.log( + 'No platform configured. Use :CP [...] first.', + vim.log.levels.ERROR + ) + return + end + + if not contest_id then + logger.log( + ("No contest '%s' configured for platform '%s'."):format( + contest_id, + constants.PLATFORM_DISPLAY_NAMES[platform] + ), + vim.log.levels.ERROR + ) + return + end + + local problem_id = state.get_problem_id() + if not problem_id then + logger.log('No problem is active.', vim.log.levels.ERROR) + return + end + + local cache = require('cp.cache') + cache.load() + local contest_data = cache.get_contest_data(platform, contest_id) + if + contest_data + and contest_data.index_map + and contest_data.problems[contest_data.index_map[problem_id]] + and contest_data.problems[contest_data.index_map[problem_id]].interactive + then + logger.log('This is an interactive problem. Use :CP interact instead.', vim.log.levels.WARN) + return + end + + local run = require('cp.runner.run') + if not run.load_test_cases() then + logger.log('no test cases found', vim.log.levels.WARN) + return + end + + local execute = require('cp.runner.execute') + local compile_result = execute.compile_problem() + if compile_result.success then + run.run_all_test_cases() + else + run.handle_compilation_failure(compile_result.output) + end + + local solution_win = state.get_solution_win() + vim.api.nvim_set_current_win(solution_win) + + vim.cmd.vsplit() + local output_win = vim.api.nvim_get_current_win() + local output_buf = utils.create_buffer_with_options() + vim.api.nvim_win_set_buf(output_win, output_buf) + + vim.cmd.split() + local input_win = vim.api.nvim_get_current_win() + local input_buf = utils.create_buffer_with_options() + vim.api.nvim_win_set_buf(input_win, input_buf) + + local test_state = run.get_panel_state() + local run_render = require('cp.runner.run_render') + run_render.setup_highlights() + + local verdict_lines = {} + local verdict_highlights = {} + for i, tc in ipairs(test_state.test_cases) do + local status = run_render.get_status_info(tc) + local time = tc.time_ms and string.format('%.2f', tc.time_ms) or '—' + local mem = tc.rss_mb and string.format('%.0f', tc.rss_mb) or '—' + local line = string.format('Test %d: %s (%sms, %sMB)', i, status.text, time, mem) + table.insert(verdict_lines, line) + local status_pos = line:find(status.text, 1, true) + if status_pos then + table.insert(verdict_highlights, { + line = i - 1, + col_start = status_pos - 1, + col_end = status_pos - 1 + #status.text, + highlight_group = status.highlight_group, + }) + end + end + + local verdict_ns = vim.api.nvim_create_namespace('cp_io_view_verdict') + utils.update_buffer_content(output_buf, verdict_lines, verdict_highlights, verdict_ns) + + local hint_lines = { 'Multiple tests running...', 'Use :CP run to view specific test' } + utils.update_buffer_content(input_buf, hint_lines, nil, nil) + + vim.keymap.set('n', 'q', function() + M.toggle_io_view() + end, { buffer = output_buf, silent = true }) + vim.keymap.set('n', 'q', function() + M.toggle_io_view() + end, { buffer = input_buf, silent = true }) + + state.set_io_view_state({ + output_buf = output_buf, + input_buf = input_buf, + output_win = output_win, + input_win = input_win, + }) + + vim.api.nvim_set_current_win(output_win) +end + ---@param panel_opts? PanelOpts function M.toggle_panel(panel_opts) if state.get_active_panel() == 'run' then @@ -212,10 +337,11 @@ function M.toggle_panel(panel_opts) current_diff_layout = nil current_mode = nil end - if state.saved_session then - vim.cmd(('source %s'):format(state.saved_session)) - vim.fn.delete(state.saved_session) - state.saved_session = nil + local saved = state.get_saved_session() + if saved then + vim.cmd(('source %s'):format(saved)) + vim.fn.delete(saved) + state.set_saved_session(nil) end state.set_active_panel(nil) return @@ -268,8 +394,9 @@ function M.toggle_panel(panel_opts) return end - state.saved_session = vim.fn.tempname() - vim.cmd(('mksession! %s'):format(state.saved_session)) + local session_file = vim.fn.tempname() + state.set_saved_session(session_file) + vim.cmd(('mksession! %s'):format(session_file)) vim.cmd('silent only') local tab_buf = utils.create_buffer_with_options() From 92b6ce31f9ee2ab4bdaf1715070e9e8efa8db1fa Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 23 Oct 2025 10:52:13 -0400 Subject: [PATCH 022/187] fix(ui): open panel on problem setup --- lua/cp/setup.lua | 8 ++- lua/cp/ui/panel.lua | 115 ++++++++++++++++++++++++++++---------------- 2 files changed, 80 insertions(+), 43 deletions(-) diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index 12fde62..eaa92f2 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -186,6 +186,7 @@ function M.setup_problem(problem_id, language) state.get_problem_id() or '', lang ) + require('cp.ui.panel').ensure_io_view() end state.set_provisional(nil) return @@ -209,6 +210,7 @@ function M.setup_problem(problem_id, language) state.get_problem_id() or '', lang ) + require('cp.ui.panel').ensure_io_view() end) end @@ -247,7 +249,11 @@ function M.navigate_problem(direction) return end - require('cp.ui.panel').disable() + local active_panel = state.get_active_panel() + if active_panel == 'run' then + require('cp.ui.panel').disable() + end + M.setup_contest(platform, contest_id, problems[new_index].id) end diff --git a/lua/cp/ui/panel.lua b/lua/cp/ui/panel.lua index 19bbfc4..63db981 100644 --- a/lua/cp/ui/panel.lua +++ b/lua/cp/ui/panel.lua @@ -204,19 +204,75 @@ function M.toggle_interactive(interactor_cmd) state.set_active_panel('interactive') end -function M.toggle_io_view() - local io_state = state.get_io_view_state() - if io_state then - if vim.api.nvim_buf_is_valid(io_state.output_buf) then - vim.api.nvim_buf_delete(io_state.output_buf, { force = true }) - end - if vim.api.nvim_buf_is_valid(io_state.input_buf) then - vim.api.nvim_buf_delete(io_state.input_buf, { force = true }) - end - state.set_io_view_state(nil) +function M.ensure_io_view() + local platform, contest_id = state.get_platform(), state.get_contest_id() + if not platform or not contest_id then return end + local problem_id = state.get_problem_id() + if not problem_id then + return + end + + local cache = require('cp.cache') + cache.load() + local contest_data = cache.get_contest_data(platform, contest_id) + if + contest_data + and contest_data.index_map + and contest_data.problems[contest_data.index_map[problem_id]] + and contest_data.problems[contest_data.index_map[problem_id]].interactive + then + return + end + + local io_state = state.get_io_view_state() + local output_buf, input_buf, output_win, input_win + + if io_state then + output_buf = io_state.output_buf + input_buf = io_state.input_buf + output_win = io_state.output_win + input_win = io_state.input_win + else + local solution_win = state.get_solution_win() + vim.api.nvim_set_current_win(solution_win) + + vim.cmd.vsplit() + output_win = vim.api.nvim_get_current_win() + output_buf = utils.create_buffer_with_options() + vim.api.nvim_win_set_buf(output_win, output_buf) + + vim.cmd.split() + input_win = vim.api.nvim_get_current_win() + input_buf = utils.create_buffer_with_options() + vim.api.nvim_win_set_buf(input_win, input_buf) + + state.set_io_view_state({ + output_buf = output_buf, + input_buf = input_buf, + output_win = output_win, + input_win = input_win, + }) + end + + local test_cases = cache.get_test_cases(platform, contest_id, problem_id) + local input_lines = {} + for i, tc in ipairs(test_cases) do + table.insert(input_lines, string.format('--- Test %d ---', i)) + for _, line in ipairs(vim.split(tc.input, '\n', { plain = true, trimempty = false })) do + table.insert(input_lines, line) + end + end + + utils.update_buffer_content(input_buf, input_lines, nil, nil) + utils.update_buffer_content(output_buf, {}, nil, nil) + + vim.api.nvim_set_current_win(output_win) +end + +function M.run_io_view() local platform, contest_id = state.get_platform(), state.get_contest_id() if not platform then logger.log( @@ -256,6 +312,8 @@ function M.toggle_io_view() return end + M.ensure_io_view() + local run = require('cp.runner.run') if not run.load_test_cases() then logger.log('no test cases found', vim.log.levels.WARN) @@ -270,18 +328,10 @@ function M.toggle_io_view() run.handle_compilation_failure(compile_result.output) end - local solution_win = state.get_solution_win() - vim.api.nvim_set_current_win(solution_win) - - vim.cmd.vsplit() - local output_win = vim.api.nvim_get_current_win() - local output_buf = utils.create_buffer_with_options() - vim.api.nvim_win_set_buf(output_win, output_buf) - - vim.cmd.split() - local input_win = vim.api.nvim_get_current_win() - local input_buf = utils.create_buffer_with_options() - vim.api.nvim_win_set_buf(input_win, input_buf) + local io_state = state.get_io_view_state() + if not io_state then + return + end local test_state = run.get_panel_state() local run_render = require('cp.runner.run_render') @@ -307,26 +357,7 @@ function M.toggle_io_view() end local verdict_ns = vim.api.nvim_create_namespace('cp_io_view_verdict') - utils.update_buffer_content(output_buf, verdict_lines, verdict_highlights, verdict_ns) - - local hint_lines = { 'Multiple tests running...', 'Use :CP run to view specific test' } - utils.update_buffer_content(input_buf, hint_lines, nil, nil) - - vim.keymap.set('n', 'q', function() - M.toggle_io_view() - end, { buffer = output_buf, silent = true }) - vim.keymap.set('n', 'q', function() - M.toggle_io_view() - end, { buffer = input_buf, silent = true }) - - state.set_io_view_state({ - output_buf = output_buf, - input_buf = input_buf, - output_win = output_win, - input_win = input_win, - }) - - vim.api.nvim_set_current_win(output_win) + utils.update_buffer_content(io_state.output_buf, verdict_lines, verdict_highlights, verdict_ns) end ---@param panel_opts? PanelOpts From c9d7d517328c54bb64c2d5dcd011cd3616c9a0cd Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 23 Oct 2025 10:53:23 -0400 Subject: [PATCH 023/187] fix: dont inline requires --- lua/cp/ui/panel.lua | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/lua/cp/ui/panel.lua b/lua/cp/ui/panel.lua index 63db981..b680588 100644 --- a/lua/cp/ui/panel.lua +++ b/lua/cp/ui/panel.lua @@ -3,6 +3,7 @@ local M = {} ---@class PanelOpts ---@field debug? boolean +local cache = require('cp.cache') local config_module = require('cp.config') local constants = require('cp.constants') local layouts = require('cp.ui.layouts') @@ -74,7 +75,6 @@ function M.toggle_interactive(interactor_cmd) return end - local cache = require('cp.cache') cache.load() local contest_data = cache.get_contest_data(platform, contest_id) if @@ -92,9 +92,10 @@ function M.toggle_interactive(interactor_cmd) vim.cmd('silent only') local execute = require('cp.runner.execute') + local run = require('cp.runner.run') local compile_result = execute.compile_problem() if not compile_result.success then - require('cp.runner.run').handle_compilation_failure(compile_result.output) + run.handle_compilation_failure(compile_result.output) return end @@ -215,7 +216,6 @@ function M.ensure_io_view() return end - local cache = require('cp.cache') cache.load() local contest_data = cache.get_contest_data(platform, contest_id) if @@ -299,7 +299,6 @@ function M.run_io_view() return end - local cache = require('cp.cache') cache.load() local contest_data = cache.get_contest_data(platform, contest_id) if @@ -315,6 +314,7 @@ function M.run_io_view() M.ensure_io_view() local run = require('cp.runner.run') + local run_render = require('cp.runner.run_render') if not run.load_test_cases() then logger.log('no test cases found', vim.log.levels.WARN) return @@ -334,7 +334,6 @@ function M.run_io_view() end local test_state = run.get_panel_state() - local run_render = require('cp.runner.run_render') run_render.setup_highlights() local verdict_lines = {} @@ -404,7 +403,6 @@ function M.toggle_panel(panel_opts) return end - local cache = require('cp.cache') cache.load() local contest_data = cache.get_contest_data(platform, contest_id) if @@ -417,6 +415,7 @@ function M.toggle_panel(panel_opts) local config = config_module.get_config() local run = require('cp.runner.run') + local run_render = require('cp.runner.run_render') local input_file = state.get_input_file() logger.log(('run panel: checking test cases for %s'):format(input_file or 'none')) @@ -456,7 +455,6 @@ function M.toggle_panel(panel_opts) if not test_buffers.tab_buf or not vim.api.nvim_buf_is_valid(test_buffers.tab_buf) then return end - local run_render = require('cp.runner.run_render') run_render.setup_highlights() local test_state = run.get_panel_state() local tab_lines, tab_highlights = run_render.render_test_list(test_state) @@ -527,8 +525,7 @@ function M.toggle_panel(panel_opts) vim.schedule(function() if config.ui.panel.ansi then - local ansi = require('cp.ui.ansi') - ansi.setup_highlight_groups() + require('cp.ui.ansi').setup_highlight_groups() end if current_diff_layout then update_diff_panes() From 114187164e840fa0e026669f992dcd2ad670b931 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 23 Oct 2025 11:16:13 -0400 Subject: [PATCH 024/187] improve some refactors --- lua/cp/commands/init.lua | 2 ++ lua/cp/config.lua | 2 ++ lua/cp/constants.lua | 2 +- lua/cp/ui/panel.lua | 14 ++++++++++++-- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/lua/cp/commands/init.lua b/lua/cp/commands/init.lua index a7bd626..c8ebc23 100644 --- a/lua/cp/commands/init.lua +++ b/lua/cp/commands/init.lua @@ -109,6 +109,8 @@ function M.handle_command(opts) if cmd.action == 'interact' then ui.toggle_interactive(cmd.interactor_cmd) elseif cmd.action == 'run' then + ui.run_io_view() + elseif cmd.action == 'panel' then ui.toggle_panel() elseif cmd.action == 'debug' then ui.toggle_panel({ debug = true }) diff --git a/lua/cp/config.lua b/lua/cp/config.lua index 4e787b4..bb02eca 100644 --- a/lua/cp/config.lua +++ b/lua/cp/config.lua @@ -32,6 +32,8 @@ ---@field before_run? fun(state: cp.State) ---@field before_debug? fun(state: cp.State) ---@field setup_code? fun(state: cp.State) +---@field setup_io_input? fun(bufnr: integer, state: cp.State) +---@field setup_io_output? fun(bufnr: integer, state: cp.State) ---@class CpUI ---@field panel PanelConfig diff --git a/lua/cp/constants.lua b/lua/cp/constants.lua index dce8751..310363f 100644 --- a/lua/cp/constants.lua +++ b/lua/cp/constants.lua @@ -1,7 +1,7 @@ local M = {} M.PLATFORMS = { 'atcoder', 'codeforces', 'cses' } -M.ACTIONS = { 'run', 'next', 'prev', 'pick', 'cache', 'interact' } +M.ACTIONS = { 'run', 'panel', 'debug', 'next', 'prev', 'pick', 'cache', 'interact' } M.PLATFORM_DISPLAY_NAMES = { atcoder = 'AtCoder', diff --git a/lua/cp/ui/panel.lua b/lua/cp/ui/panel.lua index b680588..0e2690a 100644 --- a/lua/cp/ui/panel.lua +++ b/lua/cp/ui/panel.lua @@ -227,6 +227,7 @@ function M.ensure_io_view() return end + local solution_win = state.get_solution_win() local io_state = state.get_io_view_state() local output_buf, input_buf, output_win, input_win @@ -236,11 +237,12 @@ function M.ensure_io_view() output_win = io_state.output_win input_win = io_state.input_win else - local solution_win = state.get_solution_win() vim.api.nvim_set_current_win(solution_win) vim.cmd.vsplit() output_win = vim.api.nvim_get_current_win() + local width = math.floor(vim.o.columns * 0.3) + vim.api.nvim_win_set_width(output_win, width) output_buf = utils.create_buffer_with_options() vim.api.nvim_win_set_buf(output_win, output_buf) @@ -255,6 +257,14 @@ function M.ensure_io_view() output_win = output_win, input_win = input_win, }) + + local config = config_module.get_config() + if config.hooks and config.hooks.setup_io_output then + pcall(config.hooks.setup_io_output, output_buf, state) + end + if config.hooks and config.hooks.setup_io_input then + pcall(config.hooks.setup_io_input, input_buf, state) + end end local test_cases = cache.get_test_cases(platform, contest_id, problem_id) @@ -269,7 +279,7 @@ function M.ensure_io_view() utils.update_buffer_content(input_buf, input_lines, nil, nil) utils.update_buffer_content(output_buf, {}, nil, nil) - vim.api.nvim_set_current_win(output_win) + vim.api.nvim_set_current_win(solution_win) end function M.run_io_view() From 13933fc7fdb673952f5c486bc1f407e26dfbe045 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 23 Oct 2025 12:10:14 -0400 Subject: [PATCH 025/187] feat: clearcol --- lua/cp/config.lua | 11 ++++++++++- lua/cp/helpers.lua | 11 +++++++++++ lua/cp/init.lua | 3 +++ lua/cp/setup.lua | 7 +++++++ lua/cp/ui/layouts.lua | 6 ++++++ lua/cp/ui/panel.lua | 3 +++ 6 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 lua/cp/helpers.lua diff --git a/lua/cp/config.lua b/lua/cp/config.lua index bb02eca..5d27ca7 100644 --- a/lua/cp/config.lua +++ b/lua/cp/config.lua @@ -56,6 +56,7 @@ local M = {} local constants = require('cp.constants') +local helpers = require('cp.helpers') local utils = require('cp.utils') -- defaults per the new single schema @@ -103,7 +104,13 @@ M.defaults = { default_language = 'cpp', }, }, - hooks = { before_run = nil, before_debug = nil, setup_code = nil }, + hooks = { + before_run = nil, + before_debug = nil, + setup_code = nil, + setup_io_input = helpers.clearcol, + setup_io_output = helpers.clearcol, + }, debug = false, scrapers = constants.PLATFORMS, filename = nil, @@ -231,6 +238,8 @@ function M.setup(user_config) before_run = { cfg.hooks.before_run, { 'function', 'nil' }, true }, before_debug = { cfg.hooks.before_debug, { 'function', 'nil' }, true }, setup_code = { cfg.hooks.setup_code, { 'function', 'nil' }, true }, + setup_io_input = { cfg.hooks.setup_io_input, { 'function', 'nil' }, true }, + setup_io_output = { cfg.hooks.setup_io_output, { 'function', 'nil' }, true }, }) vim.validate({ diff --git a/lua/cp/helpers.lua b/lua/cp/helpers.lua new file mode 100644 index 0000000..418d16c --- /dev/null +++ b/lua/cp/helpers.lua @@ -0,0 +1,11 @@ +local M = {} + +---@param bufnr integer +function M.clearcol(bufnr) + vim.bo[bufnr].signcolumn = 'no' + vim.bo[bufnr].statuscolumn = '' + vim.bo[bufnr].number = false + vim.bo[bufnr].relativenumber = false +end + +return M diff --git a/lua/cp/init.lua b/lua/cp/init.lua index 366517c..64a997d 100644 --- a/lua/cp/init.lua +++ b/lua/cp/init.lua @@ -1,8 +1,11 @@ local M = {} local config_module = require('cp.config') +local helpers = require('cp.helpers') local logger = require('cp.log') +M.helpers = helpers + if vim.fn.has('nvim-0.10.0') == 0 then logger.log('Requires nvim-0.10.0+', vim.log.levels.ERROR) return {} diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index eaa92f2..6592a3d 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -3,6 +3,7 @@ local M = {} local cache = require('cp.cache') local config_module = require('cp.config') local constants = require('cp.constants') +local helpers = require('cp.helpers') local logger = require('cp.log') local scraper = require('cp.scraper') local state = require('cp.state') @@ -178,6 +179,9 @@ function M.setup_problem(problem_id, language) if ok then vim.b[prov.bufnr].cp_setup_done = true end + elseif not vim.b[prov.bufnr].cp_setup_done then + helpers.clearcol(prov.bufnr) + vim.b[prov.bufnr].cp_setup_done = true end cache.set_file_state( vim.fn.fnamemodify(source_file, ':p'), @@ -202,6 +206,9 @@ function M.setup_problem(problem_id, language) if ok then vim.b[bufnr].cp_setup_done = true end + elseif not vim.b[bufnr].cp_setup_done then + helpers.clearcol(bufnr) + vim.b[bufnr].cp_setup_done = true end cache.set_file_state( vim.fn.expand('%:p'), diff --git a/lua/cp/ui/layouts.lua b/lua/cp/ui/layouts.lua index d5470d1..730c17e 100644 --- a/lua/cp/ui/layouts.lua +++ b/lua/cp/ui/layouts.lua @@ -1,10 +1,13 @@ local M = {} +local helpers = require('cp.helpers') local utils = require('cp.utils') local function create_none_diff_layout(parent_win, expected_content, actual_content) local expected_buf = utils.create_buffer_with_options() local actual_buf = utils.create_buffer_with_options() + helpers.clearcol(expected_buf) + helpers.clearcol(actual_buf) vim.api.nvim_set_current_win(parent_win) vim.cmd.split() @@ -42,6 +45,8 @@ end local function create_vim_diff_layout(parent_win, expected_content, actual_content) local expected_buf = utils.create_buffer_with_options() local actual_buf = utils.create_buffer_with_options() + helpers.clearcol(expected_buf) + helpers.clearcol(actual_buf) vim.api.nvim_set_current_win(parent_win) vim.cmd.split() @@ -89,6 +94,7 @@ end local function create_git_diff_layout(parent_win, expected_content, actual_content) local diff_buf = utils.create_buffer_with_options() + helpers.clearcol(diff_buf) vim.api.nvim_set_current_win(parent_win) vim.cmd.split() diff --git a/lua/cp/ui/panel.lua b/lua/cp/ui/panel.lua index 0e2690a..4cbc116 100644 --- a/lua/cp/ui/panel.lua +++ b/lua/cp/ui/panel.lua @@ -6,6 +6,7 @@ local M = {} local cache = require('cp.cache') local config_module = require('cp.config') local constants = require('cp.constants') +local helpers = require('cp.helpers') local layouts = require('cp.ui.layouts') local logger = require('cp.log') local state = require('cp.state') @@ -262,6 +263,7 @@ function M.ensure_io_view() if config.hooks and config.hooks.setup_io_output then pcall(config.hooks.setup_io_output, output_buf, state) end + if config.hooks and config.hooks.setup_io_input then pcall(config.hooks.setup_io_input, input_buf, state) end @@ -440,6 +442,7 @@ function M.toggle_panel(panel_opts) vim.cmd('silent only') local tab_buf = utils.create_buffer_with_options() + helpers.clearcol(tab_buf) local main_win = vim.api.nvim_get_current_win() vim.api.nvim_win_set_buf(main_win, tab_buf) vim.api.nvim_set_option_value('filetype', 'cp', { buf = tab_buf }) From 9ac2d148d20a21045dd26f010f1f7b80d98eae04 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 23 Oct 2025 12:14:17 -0400 Subject: [PATCH 026/187] fix(helpers): window-local options --- lua/cp/helpers.lua | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lua/cp/helpers.lua b/lua/cp/helpers.lua index 418d16c..27c6cba 100644 --- a/lua/cp/helpers.lua +++ b/lua/cp/helpers.lua @@ -2,10 +2,12 @@ local M = {} ---@param bufnr integer function M.clearcol(bufnr) - vim.bo[bufnr].signcolumn = 'no' - vim.bo[bufnr].statuscolumn = '' - vim.bo[bufnr].number = false - vim.bo[bufnr].relativenumber = false + for _, win in ipairs(vim.fn.win_findbuf(bufnr)) do + vim.wo[win].signcolumn = 'no' + vim.wo[win].statuscolumn = '' + vim.wo[win].number = false + vim.wo[win].relativenumber = false + end end return M From c312ccbb4dd23a69682702ca1894c79d036da89a Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 23 Oct 2025 18:16:36 -0400 Subject: [PATCH 027/187] fix: highlighting --- lua/cp/commands/init.lua | 16 +++- lua/cp/config.lua | 7 +- lua/cp/runner/run.lua | 24 ++++-- lua/cp/setup.lua | 12 +++ lua/cp/ui/ansi.lua | 19 +++++ lua/cp/ui/panel.lua | 179 ++++++++++++++++++++++++++++++--------- 6 files changed, 203 insertions(+), 54 deletions(-) diff --git a/lua/cp/commands/init.lua b/lua/cp/commands/init.lua index c8ebc23..641ba26 100644 --- a/lua/cp/commands/init.lua +++ b/lua/cp/commands/init.lua @@ -52,6 +52,20 @@ local function parse_command(args) else return { type = 'action', action = 'interact' } end + elseif first == 'run' then + local test_arg = args[2] + if test_arg then + local test_index = tonumber(test_arg) + if not test_index then + return { type = 'error', message = 'Test index must be a number' } + end + if test_index < 1 or test_index ~= math.floor(test_index) then + return { type = 'error', message = 'Test index must be >= 1' } + end + return { type = 'action', action = 'run', test_index = test_index } + else + return { type = 'action', action = 'run' } + end else return { type = 'action', action = first } end @@ -109,7 +123,7 @@ function M.handle_command(opts) if cmd.action == 'interact' then ui.toggle_interactive(cmd.interactor_cmd) elseif cmd.action == 'run' then - ui.run_io_view() + ui.run_io_view(cmd.test_index) elseif cmd.action == 'panel' then ui.toggle_panel() elseif cmd.action == 'debug' then diff --git a/lua/cp/config.lua b/lua/cp/config.lua index 5d27ca7..54515ae 100644 --- a/lua/cp/config.lua +++ b/lua/cp/config.lua @@ -18,7 +18,6 @@ ---@field overrides? table ---@class PanelConfig ----@field ansi boolean ---@field diff_mode "none"|"vim"|"git" ---@field max_output_lines integer @@ -36,6 +35,7 @@ ---@field setup_io_output? fun(bufnr: integer, state: cp.State) ---@class CpUI +---@field ansi boolean ---@field panel PanelConfig ---@field diff DiffConfig ---@field picker string|nil @@ -115,7 +115,8 @@ M.defaults = { scrapers = constants.PLATFORMS, filename = nil, ui = { - panel = { ansi = true, diff_mode = 'none', max_output_lines = 50 }, + ansi = true, + panel = { diff_mode = 'none', max_output_lines = 50 }, diff = { git = { args = { 'diff', '--no-index', '--word-diff=plain', '--word-diff-regex=.', '--no-prefix' }, @@ -243,7 +244,7 @@ function M.setup(user_config) }) vim.validate({ - ansi = { cfg.ui.panel.ansi, 'boolean' }, + ansi = { cfg.ui.ansi, 'boolean' }, diff_mode = { cfg.ui.panel.diff_mode, function(v) diff --git a/lua/cp/runner/run.lua b/lua/cp/runner/run.lua index 367d9ec..ab3d8af 100644 --- a/lua/cp/runner/run.lua +++ b/lua/cp/runner/run.lua @@ -122,7 +122,7 @@ local function run_single_test_case(test_case) local out = r.stdout or '' local highlights = {} if out ~= '' then - if config.ui.panel.ansi then + if config.ui.ansi then local parsed = ansi.parse_ansi_text(out) out = table.concat(parsed.lines, '\n') highlights = parsed.highlights @@ -224,14 +224,22 @@ function M.run_test_case(index) return true end +---@param indices? integer[] ---@return RanTestCase[] -function M.run_all_test_cases() - local results = {} - for i = 1, #panel_state.test_cases do - M.run_test_case(i) - results[i] = panel_state.test_cases[i] +function M.run_all_test_cases(indices) + local to_run = indices + if not to_run then + to_run = {} + for i = 1, #panel_state.test_cases do + to_run[i] = i + end end - return results + + for _, i in ipairs(to_run) do + M.run_test_case(i) + end + + return panel_state.test_cases end ---@return PanelState @@ -247,7 +255,7 @@ function M.handle_compilation_failure(output) local txt local hl = {} - if config.ui.panel.ansi then + if config.ui.ansi then local p = ansi.parse_ansi_text(output or '') txt = table.concat(p.lines, '\n') hl = p.highlights diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index 6592a3d..e473563 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -60,6 +60,18 @@ local function start_tests(platform, contest_id, problems) ev.memory_mb or 0, ev.interactive ) + + local io_state = state.get_io_view_state() + if io_state then + local test_cases = cache.get_test_cases(platform, contest_id, state.get_problem_id()) + local input_lines = {} + for _, tc in ipairs(test_cases) do + for _, line in ipairs(vim.split(tc.input, '\n', { plain = true, trimempty = false })) do + table.insert(input_lines, line) + end + end + require('cp.utils').update_buffer_content(io_state.input_buf, input_lines, nil, nil) + end end) end end diff --git a/lua/cp/ui/ansi.lua b/lua/cp/ui/ansi.lua index a72bcad..7d84d2d 100644 --- a/lua/cp/ui/ansi.lua +++ b/lua/cp/ui/ansi.lua @@ -321,6 +321,25 @@ function M.setup_highlight_groups() vim.api.nvim_set_hl(0, 'CpAnsiBold', { bold = true }) vim.api.nvim_set_hl(0, 'CpAnsiItalic', { italic = true }) vim.api.nvim_set_hl(0, 'CpAnsiBoldItalic', { bold = true, italic = true }) + + for _, combo in ipairs(combinations) do + for color_name, _ in pairs(color_map) do + local parts = { 'CpAnsi' } + if combo.bold then + table.insert(parts, 'Bold') + end + if combo.italic then + table.insert(parts, 'Italic') + end + table.insert(parts, color_name) + local hl_name = table.concat(parts) + dyn_hl_cache[hl_name] = true + end + end + + dyn_hl_cache['CpAnsiBold'] = true + dyn_hl_cache['CpAnsiItalic'] = true + dyn_hl_cache['CpAnsiBoldItalic'] = true end ---@param text string diff --git a/lua/cp/ui/panel.lua b/lua/cp/ui/panel.lua index 4cbc116..4e7962d 100644 --- a/lua/cp/ui/panel.lua +++ b/lua/cp/ui/panel.lua @@ -15,6 +15,22 @@ local utils = require('cp.utils') local current_diff_layout = nil local current_mode = nil +local function populate_input() + local io_state = state.get_io_view_state() + + local test_cases = + cache.get_test_cases(state.get_platform(), state.get_contest_id(), state.get_problem_id()) + + local input_lines = {} + for _, tc in ipairs(test_cases) do + for _, line in ipairs(vim.split(tc.input, '\n', { plain = true, trimempty = false })) do + table.insert(input_lines, line) + end + end + + utils.update_buffer_content(io_state.input_buf, input_lines) +end + function M.disable() local active_panel = state.get_active_panel() if not active_panel then @@ -269,22 +285,15 @@ function M.ensure_io_view() end end - local test_cases = cache.get_test_cases(platform, contest_id, problem_id) - local input_lines = {} - for i, tc in ipairs(test_cases) do - table.insert(input_lines, string.format('--- Test %d ---', i)) - for _, line in ipairs(vim.split(tc.input, '\n', { plain = true, trimempty = false })) do - table.insert(input_lines, line) - end - end - - utils.update_buffer_content(input_buf, input_lines, nil, nil) + utils.update_buffer_content(input_buf, {}, nil, nil) utils.update_buffer_content(output_buf, {}, nil, nil) vim.api.nvim_set_current_win(solution_win) + + populate_input() end -function M.run_io_view() +function M.run_io_view(test_index) local platform, contest_id = state.get_platform(), state.get_contest_id() if not platform then logger.log( @@ -296,8 +305,7 @@ function M.run_io_view() if not contest_id then logger.log( - ("No contest '%s' configured for platform '%s'."):format( - contest_id, + ("No contest configured for platform '%s'."):format( constants.PLATFORM_DISPLAY_NAMES[platform] ), vim.log.levels.ERROR @@ -326,18 +334,31 @@ function M.run_io_view() M.ensure_io_view() local run = require('cp.runner.run') - local run_render = require('cp.runner.run_render') if not run.load_test_cases() then - logger.log('no test cases found', vim.log.levels.WARN) + logger.log('No test cases available', vim.log.levels.ERROR) return end - local execute = require('cp.runner.execute') - local compile_result = execute.compile_problem() - if compile_result.success then - run.run_all_test_cases() + local test_state = run.get_panel_state() + local test_indices = {} + + if test_index then + if test_index < 1 or test_index > #test_state.test_cases then + logger.log( + string.format( + 'Test %d does not exist (only %d tests available)', + test_index, + #test_state.test_cases + ), + vim.log.levels.ERROR + ) + return + end + test_indices = { test_index } else - run.handle_compilation_failure(compile_result.output) + for i = 1, #test_state.test_cases do + test_indices[i] = i + end end local io_state = state.get_io_view_state() @@ -345,30 +366,91 @@ function M.run_io_view() return end - local test_state = run.get_panel_state() - run_render.setup_highlights() + local config = config_module.get_config() - local verdict_lines = {} - local verdict_highlights = {} - for i, tc in ipairs(test_state.test_cases) do - local status = run_render.get_status_info(tc) - local time = tc.time_ms and string.format('%.2f', tc.time_ms) or '—' - local mem = tc.rss_mb and string.format('%.0f', tc.rss_mb) or '—' - local line = string.format('Test %d: %s (%sms, %sMB)', i, status.text, time, mem) - table.insert(verdict_lines, line) - local status_pos = line:find(status.text, 1, true) - if status_pos then - table.insert(verdict_highlights, { - line = i - 1, - col_start = status_pos - 1, - col_end = status_pos - 1 + #status.text, - highlight_group = status.highlight_group, - }) - end + if config.ui.ansi then + require('cp.ui.ansi').setup_highlight_groups() end - local verdict_ns = vim.api.nvim_create_namespace('cp_io_view_verdict') - utils.update_buffer_content(io_state.output_buf, verdict_lines, verdict_highlights, verdict_ns) + local execute = require('cp.runner.execute') + local compile_result = execute.compile_problem() + if not compile_result.success then + local ansi = require('cp.ui.ansi') + local output = compile_result.output or '' + local lines, highlights + + if config.ui.ansi then + local parsed = ansi.parse_ansi_text(output) + lines = parsed.lines + highlights = parsed.highlights + else + lines = vim.split(output:gsub('\027%[[%d;]*[a-zA-Z]', ''), '\n') + highlights = {} + end + + local ns = vim.api.nvim_create_namespace('cp_io_view_compile_error') + utils.update_buffer_content(io_state.output_buf, lines, highlights, ns) + return + end + + run.run_all_test_cases(test_indices) + + local input_lines = {} + for _, idx in ipairs(test_indices) do + local tc = test_state.test_cases[idx] + for _, line in ipairs(vim.split(tc.input, '\n', { plain = true, trimempty = false })) do + table.insert(input_lines, line) + end + end + utils.update_buffer_content(io_state.input_buf, input_lines, nil, nil) + + local run_render = require('cp.runner.run_render') + run_render.setup_highlights() + + if #test_indices == 1 then + local idx = test_indices[1] + local tc = test_state.test_cases[idx] + local status = run_render.get_status_info(tc) + + local output_lines = {} + if tc.actual then + for _, line in ipairs(vim.split(tc.actual, '\n', { plain = true, trimempty = false })) do + table.insert(output_lines, line) + end + end + + table.insert(output_lines, '') + local time = tc.time_ms and string.format('%.2fms', tc.time_ms) or '—' + local code = tc.code and tostring(tc.code) or '—' + table.insert(output_lines, string.format('--- %s: %s | Exit: %s ---', status.text, time, code)) + + local highlights = tc.actual_highlights or {} + local ns = vim.api.nvim_create_namespace('cp_io_view_output') + utils.update_buffer_content(io_state.output_buf, output_lines, highlights, ns) + else + local verdict_lines = {} + local verdict_highlights = {} + for _, idx in ipairs(test_indices) do + local tc = test_state.test_cases[idx] + local status = run_render.get_status_info(tc) + local time = tc.time_ms and string.format('%.2f', tc.time_ms) or '—' + local mem = tc.rss_mb and string.format('%.0f', tc.rss_mb) or '—' + local line = string.format('Test %d: %s (%sms, %sMB)', idx, status.text, time, mem) + table.insert(verdict_lines, line) + local status_pos = line:find(status.text, 1, true) + if status_pos then + table.insert(verdict_highlights, { + line = #verdict_lines - 1, + col_start = status_pos - 1, + col_end = status_pos - 1 + #status.text, + highlight_group = status.highlight_group, + }) + end + end + + local verdict_ns = vim.api.nvim_create_namespace('cp_io_view_verdict') + utils.update_buffer_content(io_state.output_buf, verdict_lines, verdict_highlights, verdict_ns) + end end ---@param panel_opts? PanelOpts @@ -386,6 +468,8 @@ function M.toggle_panel(panel_opts) state.set_saved_session(nil) end state.set_active_panel(nil) + M.ensure_io_view() + populate_input() return end @@ -436,6 +520,17 @@ function M.toggle_panel(panel_opts) return end + local io_state = state.get_io_view_state() + if io_state then + if vim.api.nvim_win_is_valid(io_state.output_win) then + vim.api.nvim_win_close(io_state.output_win, true) + end + if vim.api.nvim_win_is_valid(io_state.input_win) then + vim.api.nvim_win_close(io_state.input_win, true) + end + state.set_io_view_state(nil) + end + local session_file = vim.fn.tempname() state.set_saved_session(session_file) vim.cmd(('mksession! %s'):format(session_file)) @@ -537,7 +632,7 @@ function M.toggle_panel(panel_opts) refresh_panel() vim.schedule(function() - if config.ui.panel.ansi then + if config.ui.ansi then require('cp.ui.ansi').setup_highlight_groups() end if current_diff_layout then From dc6f2fd5b627a31779a84a05bda804b5d691b08d Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 23 Oct 2025 18:29:20 -0400 Subject: [PATCH 028/187] fix: cleanup logs --- lua/cp/setup.lua | 1 + lua/cp/ui/panel.lua | 91 +++++++++++++-------------------------------- lua/cp/utils.lua | 4 ++ 3 files changed, 30 insertions(+), 66 deletions(-) diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index e473563..d2c9f43 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -165,6 +165,7 @@ end function M.setup_problem(problem_id, language) local platform = state.get_platform() if not platform then + logger.log('No platform/contest/problem configured.', vim.log.levels.ERROR) return end diff --git a/lua/cp/ui/panel.lua b/lua/cp/ui/panel.lua index 4e7962d..d3fccc2 100644 --- a/lua/cp/ui/panel.lua +++ b/lua/cp/ui/panel.lua @@ -70,37 +70,24 @@ function M.toggle_interactive(interactor_cmd) return end - local platform, contest_id = state.get_platform(), state.get_contest_id() - if not platform then - logger.log('No platform configured.', vim.log.levels.ERROR) - return - end - if not contest_id then + local platform, contest_id, problem_id = + state.get_platform(), state.get_contest_id(), state.get_problem_id() + if not platform or not contest_id or not problem_id then logger.log( - ("No contest %s configured for platform '%s'."):format( - contest_id, - constants.PLATFORM_DISPLAY_NAMES[platform] - ), + 'No platform/contest/problem configured. Use :CP [...] first.', vim.log.levels.ERROR ) return end - local problem_id = state.get_problem_id() - if not problem_id then - logger.log('No problem is active.', vim.log.levels.ERROR) - return - end - cache.load() local contest_data = cache.get_contest_data(platform, contest_id) if not contest_data or not contest_data.index_map - or not contest_data.problems[contest_data.index_map[problem_id]] or not contest_data.problems[contest_data.index_map[problem_id]].interactive then - logger.log('This problem is not interactive. Use :CP run.', vim.log.levels.ERROR) + logger.log('This problem is not interactive. Use :CP {run,panel}.', vim.log.levels.ERROR) return end @@ -223,13 +210,13 @@ function M.toggle_interactive(interactor_cmd) end function M.ensure_io_view() - local platform, contest_id = state.get_platform(), state.get_contest_id() - if not platform or not contest_id then - return - end - - local problem_id = state.get_problem_id() - if not problem_id then + local platform, contest_id, problem_id = + state.get_platform(), state.get_contest_id(), state.get_problem_id() + if not platform or not contest_id or not problem_id then + logger.log( + 'No platform/contest/problem configured. Use :CP [...] first.', + vim.log.levels.ERROR + ) return end @@ -238,9 +225,9 @@ function M.ensure_io_view() if contest_data and contest_data.index_map - and contest_data.problems[contest_data.index_map[problem_id]] and contest_data.problems[contest_data.index_map[problem_id]].interactive then + logger.log('No platform configured.', vim.log.levels.ERROR) return end @@ -285,8 +272,8 @@ function M.ensure_io_view() end end - utils.update_buffer_content(input_buf, {}, nil, nil) - utils.update_buffer_content(output_buf, {}, nil, nil) + utils.update_buffer_content(input_buf, {}) + utils.update_buffer_content(output_buf, {}) vim.api.nvim_set_current_win(solution_win) @@ -294,40 +281,23 @@ function M.ensure_io_view() end function M.run_io_view(test_index) - local platform, contest_id = state.get_platform(), state.get_contest_id() - if not platform then + local platform, contest_id, problem_id = + state.get_platform(), state.get_contest_id(), state.get_problem_id() + if not platform or not contest_id or not problem_id then logger.log( - 'No platform configured. Use :CP [...] first.', + 'No platform/contest/problem configured. Use :CP [...] first.', vim.log.levels.ERROR ) - return - end - - if not contest_id then - logger.log( - ("No contest configured for platform '%s'."):format( - constants.PLATFORM_DISPLAY_NAMES[platform] - ), - vim.log.levels.ERROR - ) - return - end - - local problem_id = state.get_problem_id() - if not problem_id then - logger.log('No problem is active.', vim.log.levels.ERROR) - return end cache.load() local contest_data = cache.get_contest_data(platform, contest_id) if - contest_data - and contest_data.index_map - and contest_data.problems[contest_data.index_map[problem_id]] - and contest_data.problems[contest_data.index_map[problem_id]].interactive + not contest_data + or not contest_data.index_map + or not contest_data.problems[contest_data.index_map[problem_id]].interactive then - logger.log('This is an interactive problem. Use :CP interact instead.', vim.log.levels.WARN) + logger.log('This problem is not interactive. Use :CP {run,panel}.', vim.log.levels.ERROR) return end @@ -480,20 +450,9 @@ function M.toggle_panel(panel_opts) local platform, contest_id = state.get_platform(), state.get_contest_id() - if not platform then + if not platform or not contest_id then logger.log( - 'No platform configured. Use :CP [...] first.', - vim.log.levels.ERROR - ) - return - end - - if not contest_id then - logger.log( - ("No contest '%s' configured for platform '%s'."):format( - contest_id, - constants.PLATFORM_DISPLAY_NAMES[platform] - ), + 'No platform/contest/problem configured. Use :CP [...] first.', vim.log.levels.ERROR ) return diff --git a/lua/cp/utils.lua b/lua/cp/utils.lua index 6ce2311..e9bba54 100644 --- a/lua/cp/utils.lua +++ b/lua/cp/utils.lua @@ -125,6 +125,10 @@ function M.create_buffer_with_options(filetype) return buf end +---@param bufnr integer +---@param lines string[] +---@param highlights? Highlight[] +---@param namespace? integer function M.update_buffer_content(bufnr, lines, highlights, namespace) local was_readonly = vim.api.nvim_get_option_value('readonly', { buf = bufnr }) From 59f506632732b78257c6442ea0125f266b86920a Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 23 Oct 2025 20:03:17 -0400 Subject: [PATCH 029/187] fix input display --- lua/cp/commands/init.lua | 7 +++++-- lua/cp/setup.lua | 2 +- lua/cp/ui/panel.lua | 28 ++++++++++++++++++---------- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/lua/cp/commands/init.lua b/lua/cp/commands/init.lua index 641ba26..4845cc1 100644 --- a/lua/cp/commands/init.lua +++ b/lua/cp/commands/init.lua @@ -57,10 +57,13 @@ local function parse_command(args) if test_arg then local test_index = tonumber(test_arg) if not test_index then - return { type = 'error', message = 'Test index must be a number' } + return { + type = 'error', + message = ("Test index '%s' is not a number"):format(test_index), + } end if test_index < 1 or test_index ~= math.floor(test_index) then - return { type = 'error', message = 'Test index must be >= 1' } + return { type = 'error', message = ("'%s' is not a valid test index"):format(test_index) } end return { type = 'action', action = 'run', test_index = test_index } else diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index d2c9f43..d6e2f38 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -66,7 +66,7 @@ local function start_tests(platform, contest_id, problems) local test_cases = cache.get_test_cases(platform, contest_id, state.get_problem_id()) local input_lines = {} for _, tc in ipairs(test_cases) do - for _, line in ipairs(vim.split(tc.input, '\n', { plain = true, trimempty = false })) do + for _, line in ipairs(vim.split(tc.input, '\n')) do table.insert(input_lines, line) end end diff --git a/lua/cp/ui/panel.lua b/lua/cp/ui/panel.lua index d3fccc2..59bde40 100644 --- a/lua/cp/ui/panel.lua +++ b/lua/cp/ui/panel.lua @@ -85,9 +85,9 @@ function M.toggle_interactive(interactor_cmd) if not contest_data or not contest_data.index_map - or not contest_data.problems[contest_data.index_map[problem_id]].interactive + or contest_data.problems[contest_data.index_map[problem_id]].interactive then - logger.log('This problem is not interactive. Use :CP {run,panel}.', vim.log.levels.ERROR) + logger.log('This problem is interactive. Use :CP {run,panel}.', vim.log.levels.ERROR) return end @@ -275,9 +275,18 @@ function M.ensure_io_view() utils.update_buffer_content(input_buf, {}) utils.update_buffer_content(output_buf, {}) - vim.api.nvim_set_current_win(solution_win) + local test_cases = cache.get_test_cases(platform, contest_id, problem_id) + if test_cases and #test_cases > 0 then + local input_lines = {} + for _, tc in ipairs(test_cases) do + for _, line in ipairs(vim.split(tc.input, '\n')) do + table.insert(input_lines, line) + end + end + utils.update_buffer_content(input_buf, input_lines, nil, nil) + end - populate_input() + vim.api.nvim_set_current_win(solution_win) end function M.run_io_view(test_index) @@ -295,9 +304,9 @@ function M.run_io_view(test_index) if not contest_data or not contest_data.index_map - or not contest_data.problems[contest_data.index_map[problem_id]].interactive + or contest_data.problems[contest_data.index_map[problem_id]].interactive then - logger.log('This problem is not interactive. Use :CP {run,panel}.', vim.log.levels.ERROR) + logger.log('This problem is interactive. Use :CP {run,panel}.', vim.log.levels.ERROR) return end @@ -320,7 +329,7 @@ function M.run_io_view(test_index) test_index, #test_state.test_cases ), - vim.log.levels.ERROR + vim.log.levels.WARN ) return end @@ -368,7 +377,7 @@ function M.run_io_view(test_index) local input_lines = {} for _, idx in ipairs(test_indices) do local tc = test_state.test_cases[idx] - for _, line in ipairs(vim.split(tc.input, '\n', { plain = true, trimempty = false })) do + for _, line in ipairs(vim.split(tc.input, '\n')) do table.insert(input_lines, line) end end @@ -439,7 +448,6 @@ function M.toggle_panel(panel_opts) end state.set_active_panel(nil) M.ensure_io_view() - populate_input() return end @@ -452,7 +460,7 @@ function M.toggle_panel(panel_opts) if not platform or not contest_id then logger.log( - 'No platform/contest/problem configured. Use :CP [...] first.', + 'No platform/contest configured. Use :CP [...] first.', vim.log.levels.ERROR ) return From 99544905dfe5f8ab21073d00a4902d45ebc1fb22 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 23 Oct 2025 20:04:36 -0400 Subject: [PATCH 030/187] fix current mode --- lua/cp/ui/panel.lua | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/lua/cp/ui/panel.lua b/lua/cp/ui/panel.lua index 59bde40..903f2f3 100644 --- a/lua/cp/ui/panel.lua +++ b/lua/cp/ui/panel.lua @@ -5,7 +5,6 @@ local M = {} local cache = require('cp.cache') local config_module = require('cp.config') -local constants = require('cp.constants') local helpers = require('cp.helpers') local layouts = require('cp.ui.layouts') local logger = require('cp.log') @@ -15,22 +14,6 @@ local utils = require('cp.utils') local current_diff_layout = nil local current_mode = nil -local function populate_input() - local io_state = state.get_io_view_state() - - local test_cases = - cache.get_test_cases(state.get_platform(), state.get_contest_id(), state.get_problem_id()) - - local input_lines = {} - for _, tc in ipairs(test_cases) do - for _, line in ipairs(vim.split(tc.input, '\n', { plain = true, trimempty = false })) do - table.insert(input_lines, line) - end - end - - utils.update_buffer_content(io_state.input_buf, input_lines) -end - function M.disable() local active_panel = state.get_active_panel() if not active_panel then From 60e5aabd99ce23238ebf849b0fc61e30c818a0dd Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 23 Oct 2025 20:15:16 -0400 Subject: [PATCH 031/187] fix types --- lua/cp/commands/init.lua | 1 + lua/cp/ui/panel.lua | 1 + 2 files changed, 2 insertions(+) diff --git a/lua/cp/commands/init.lua b/lua/cp/commands/init.lua index 4845cc1..319f952 100644 --- a/lua/cp/commands/init.lua +++ b/lua/cp/commands/init.lua @@ -16,6 +16,7 @@ local actions = constants.ACTIONS ---@field platform? string ---@field problem_id? string ---@field interactor_cmd? string +---@field test_index? integer --- Turn raw args into normalized structure to later dispatch ---@param args string[] The raw command-line mode args diff --git a/lua/cp/ui/panel.lua b/lua/cp/ui/panel.lua index 903f2f3..ce846ba 100644 --- a/lua/cp/ui/panel.lua +++ b/lua/cp/ui/panel.lua @@ -280,6 +280,7 @@ function M.run_io_view(test_index) 'No platform/contest/problem configured. Use :CP [...] first.', vim.log.levels.ERROR ) + return end cache.load() From f45926c09493d6cc7668432c2e34ae8ee1f29504 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 23 Oct 2025 20:40:59 -0400 Subject: [PATCH 032/187] fix(docs): update for new features --- README.md | 23 ++++-- doc/cp.nvim.txt | 208 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 163 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index 9380c63..7130889 100644 --- a/README.md +++ b/README.md @@ -2,22 +2,28 @@ **The definitive competitive programming environment for Neovim** -Scrape problems, run tests, and debug solutions across multiple platforms with zero configuration. +Scrape problems, run tests, and debug solutions across multiple platforms with +zero configuration. https://github.com/user-attachments/assets/50b19481-8e6d-47b4-bebc-15e16c61a9c9 ## Features -- **Multi-platform support**: AtCoder, Codeforces, CSES with consistent interface +- **Multi-platform support**: AtCoder, Codeforces, CSES with consistent + interface - **Automatic problem setup**: Scrape test cases and metadata in seconds -- **Rich test output**: 256 color ANSI support for compiler errors and program output +- **Dual view modes**: Lightweight I/O view for quick feedback, full panel for + detailed analysis +- **Rich test output**: 256 color ANSI support for compiler errors and program + output - **Language agnostic**: Works with any language - **Diff viewer**: Compare expected vs actual output with 3 diff modes ## Optional Dependencies - [uv](https://docs.astral.sh/uv/) for problem scraping -- GNU [time](https://www.gnu.org/software/time/) and [timeout](https://www.gnu.org/software/coreutils/manual/html_node/timeout-invocation.html) +- GNU [time](https://www.gnu.org/software/time/) and + [timeout](https://www.gnu.org/software/coreutils/manual/html_node/timeout-invocation.html) ## Quick Start @@ -32,10 +38,11 @@ cp.nvim follows a simple principle: **solve locally, submit remotely**. :CP codeforces 1848 ``` -3. **Code and test** with instant feedback and rich diffs +3. **Code and test** with instant feedback ``` - :CP run + :CP run " Quick verdict summary in splits + :CP panel " Detailed analysis with diffs ``` 4. **Navigate between problems** @@ -54,7 +61,9 @@ cp.nvim follows a simple principle: **solve locally, submit remotely**. :help cp.nvim ``` -See [my config](https://github.com/barrett-ruth/dots/blob/main/nvim/lua/plugins/cp.lua) for a relatively advanced setup. +See +[my config](https://github.com/barrett-ruth/dots/blob/main/nvim/lua/plugins/cp.lua) +for a relatively advanced setup. ## Similar Projects diff --git a/doc/cp.nvim.txt b/doc/cp.nvim.txt index 5dd17b1..c429314 100644 --- a/doc/cp.nvim.txt +++ b/doc/cp.nvim.txt @@ -4,7 +4,7 @@ Author: Barrett Ruth License: Same terms as Vim itself (see |license|) ============================================================================== -INTRODUCTION *cp.nvim* +INTRODUCTION *cp.nvim* cp.nvim is a competitive programming plugin that automates problem setup, compilation, and testing workflow for online judges. @@ -12,16 +12,16 @@ compilation, and testing workflow for online judges. Supported platforms (for now!): AtCoder, Codeforces, CSES ============================================================================== -REQUIREMENTS *cp-requirements* +REQUIREMENTS *cp-requirements* - Neovim 0.10.0+ - Unix-like operating system - uv package manager (https://docs.astral.sh/uv/) ============================================================================== -COMMANDS *cp-commands* +COMMANDS *cp-commands* -:CP *:CP* +:CP *:CP* cp.nvim uses a single :CP command with intelligent argument parsing: Setup Commands ~ @@ -38,14 +38,23 @@ COMMANDS *cp-commands* Example: > :CP atcoder abc324 < - Action Commands ~ - :CP run Toggle run panel for individual test cases. - Shows per-test results with redesigned - layout for efficient comparison. - - :CP debug - Same as above but with the debug mode configured - settings. + View Commands ~ + :CP run [n] Run tests in I/O view (see |cp-io-view|). + Lightweight split showing test verdicts. + Without [n]: runs all tests, shows verdict summary + With [n]: runs test n, shows detailed output + Examples: > + :CP run " All tests, verdict list + :CP run 3 " Test 3 detail +< + :CP panel [n] Open full-screen test panel (see |cp-panel|). + Aggregate table with diff modes for detailed analysis. + Optional [n] focuses on specific test. + Example: > + :CP panel " All tests with diffs + :CP panel 2 " Focus on test 2 +< + :CP debug [n] Same as :CP panel but uses debug build configuration. :CP pick Launch configured picker for interactive platform/contest selection. @@ -84,7 +93,7 @@ COMMANDS *cp-commands* Exit with q. Template Variables ~ - *cp-template-vars* + *cp-template-vars* Command templates support variable substitution using {variable} syntax: • {source} Source file path (e.g. "abc324a.cpp") @@ -97,7 +106,7 @@ Template Variables ~ < ============================================================================== -CONFIGURATION *cp-config* +CONFIGURATION *cp-config* Here's an example configuration with lazy.nvim: >lua @@ -145,8 +154,8 @@ Here's an example configuration with lazy.nvim: open_url = true, debug = false, ui = { + ansi = true, panel = { - ansi = true, diff_mode = 'vim', max_output_lines = 50, }, @@ -197,7 +206,7 @@ run CSES problems with Rust using the single schema: }, } < - *cp.Config* + *cp.Config* Fields: ~ {languages} (table) Global language registry. Each language provides an {extension} and {commands}. @@ -214,19 +223,19 @@ run CSES problems with Rust using the single schema: {open_url} (boolean) Open the contest & problem url in the browser when the contest is first opened. - *CpPlatform* + *CpPlatform* Fields: ~ {enabled_languages} (string[]) Language ids enabled on this platform. {default_language} (string) One of {enabled_languages}. {overrides} (table, optional) Per-language overrides of {extension} and/or {commands}. - *CpLanguage* + *CpLanguage* Fields: ~ {extension} (string) File extension without leading dot. {commands} (|CpLangCommands|) Command templates. - *CpLangCommands* + *CpLangCommands* Fields: ~ {build} (string[], optional) For compiled languages. Must include {source} and {binary}. @@ -236,25 +245,25 @@ run CSES problems with Rust using the single schema: {debug} (string[], optional) Debug variant; same token rules as {build} (compiled) or {run} (interpreted). - *CpUI* + *CpUI* Fields: ~ + {ansi} (boolean, default: true) Enable ANSI color parsing + and highlighting in both I/O view and panel. {panel} (|PanelConfig|) Test panel behavior configuration. {diff} (|DiffConfig|) Diff backend configuration. {picker} (string|nil) 'telescope', 'fzf-lua', or nil. - *cp.PanelConfig* + *cp.PanelConfig* Fields: ~ - {ansi} (boolean, default: true) Enable ANSI color parsing - and highlighting. {diff_mode} (string, default: "none") Diff backend: "none", "vim", or "git". {max_output_lines} (number, default: 50) Maximum lines of test output. - *cp.DiffConfig* + *cp.DiffConfig* Fields: ~ {git} (|cp.DiffGitConfig|) Git diff backend configuration. - *cp.DiffGitConfig* + *cp.DiffGitConfig* Fields: ~ {args} (string[]) Command-line arguments for git diff. Default: { 'diff', '--no-index', '--word-diff=plain', @@ -264,40 +273,56 @@ run CSES problems with Rust using the single schema: • --word-diff-regex=.: Split on every character • --no-prefix: Remove a/ b/ prefixes from output - *cp.Hooks* + *cp.Hooks* Fields: ~ - {before_run} (function, optional) Called before test panel opens. - function(state: cp.State) - {before_debug} (function, optional) Called before debug build/run. - function(state: cp.State) - {setup_code} (function, optional) Called after source file is opened. - function(state: cp.State) + {before_run} (function, optional) Called before test panel opens. + function(state: cp.State) + {before_debug} (function, optional) Called before debug build/run. + function(state: cp.State) + {setup_code} (function, optional) Called after source file is opened. + function(state: cp.State) + {setup_io_input} (function, optional) Called when I/O input buffer created. + function(bufnr: integer, state: cp.State) + Default: helpers.clearcol (removes line numbers/columns) + {setup_io_output} (function, optional) Called when I/O output buffer created. + function(bufnr: integer, state: cp.State) + Default: helpers.clearcol (removes line numbers/columns) - Hook functions receive the cp.nvim state object (cp.State). See the state - module documentation (lua/cp/state.lua) for available methods and fields. + Hook functions receive the cp.nvim state object (|cp.State|). See + |lua/cp/state.lua| for available methods and fields. - Example usage in hook: + The I/O buffer hooks are called once when the buffers are first created + during problem setup. Use these to customize buffer appearance (e.g., + remove line numbers, set custom options). Access helpers via: +>lua + local helpers = require('cp').helpers +< + Example usage: >lua hooks = { setup_code = function(state) print("Setting up " .. state.get_base_name()) print("Source file: " .. state.get_source_file()) + end, + setup_io_input = function(bufnr, state) + -- Custom setup for input buffer + vim.api.nvim_set_option_value('number', false, { buf = bufnr }) end } < ============================================================================== -WORKFLOW *cp-workflow* +WORKFLOW *cp-workflow* For the sake of consistency and simplicity, cp.nvim extracts contest/problem identifiers from URLs. This means that, for example, CodeForces/AtCoder contests are configured by their round id rather than round number. See below. ============================================================================== -PLATFORM-SPECIFIC USAGE *cp-platforms* +PLATFORM-SPECIFIC USAGE *cp-platforms* AtCoder ~ - *cp-atcoder* + *cp-atcoder* URL format: https://atcoder.jp/contests/{contest_id}/tasks/{contest_id}_{problem_id} @@ -305,14 +330,14 @@ Usage examples: > :CP atcoder abc324 " Set up atcoder.jp/contests/abc324 Codeforces ~ - *cp-codeforces* + *cp-codeforces* URL format: https://codeforces.com/contest/{contest_id}/problem/{problem_id} Usage examples: > :CP codeforces 1934 " Set up codeforces.com/contest/1934 CSES ~ - *cp-cses* + *cp-cses* URL format: https://cses.fi/problemset/task/{problem_id} Usage examples: > @@ -320,7 +345,7 @@ Usage examples: > ============================================================================== -COMPLETE WORKFLOW EXAMPLE *cp-example* +COMPLETE WORKFLOW EXAMPLE *cp-example* Example: Setting up and solving AtCoder contest ABC324 @@ -333,8 +358,9 @@ Example: Setting up and solving AtCoder contest ABC324 3. Code your solution, then test: > :CP run -< Navigate with j/k, run specific tests with - Exit test panel with q or :CP run when done +< View test verdicts in I/O splits. For detailed analysis: + :CP panel +< Navigate tests with /, exit with q 4. Move to next problem: > :CP next @@ -350,28 +376,68 @@ Example: Setting up and solving AtCoder contest ABC324 7. Submit solutions on AtCoder website ============================================================================== -PICKER INTEGRATION *cp-picker* +I/O VIEW *cp-io-view* + +The I/O view provides the main view aggregate view into test input and +program output. Used time/memory per test case are appended to the output. +The |cp-panel| offers more fine-grained analysis into each test case. + +Access the I/O view with :CP run [n] + +Layout ~ + +The I/O view appears as 30% width splits on the right side: > + + ┌──────────────────────────┬──────────────────────────┐ + │ │ Output │ + │ │ Test 1: AC (42ms, 8MB) │ + │ │ Test 2: AC (38ms, 8MB) │ + │ Solution Code │ Test 3: WA (45ms, 8MB) │ + │ │ Test 4: AC (51ms, 9MB) │ + │ ├──────────────────────────┤ + │ │ Input │ + │ │ 5 3 │ + │ │ 1 2 3 4 5 │ + │ │ 2 1 │ + │ │ 10 20 │ + └──────────────────────────┴──────────────────────────┘ +< +Usage ~ + + :CP run Run all tests + :CP run 3 Run test 3 + +Buffer Customization ~ + +Use the setup_io_input and setup_io_output hooks (see |cp.Hooks|) to customize +buffer appearance. By default, line numbers and columns are removed via +helpers.clearcol (see |cp-helpers|). + +============================================================================== +PICKER INTEGRATION *cp-picker* When picker integration is enabled in configuration, cp.nvim provides interactive platform and contest selection using telescope.nvim or fzf-lua. -:CP pick *:CP-pick* +:CP pick *:CP-pick* Launch configured picker for interactive problem selection. Control Flow: Select Platform → Contest → Code! Requires picker = 'telescope' or picker = 'fzf-lua' in configuration. Requires corresponding plugin (telescope.nvim or fzf-lua) to be installed. -PICKER KEYMAPS *cp-picker-keys* +PICKER KEYMAPS *cp-picker-keys* Force refresh/update contest list. Useful when contest lists are outdated or incomplete ============================================================================== -PANEL *cp-run* +PANEL *cp-panel* -The panel provides individual test case debugging. Problem time/memory -limit constraints are in columns Time/Mem respectively. Used time/memory are -in columns Runtime/RSS respectively. +The panel provides full-screen test analysis with diff modes for detailed +debugging. Problem time/memory limit constraints are in columns Time/Mem +respectively. Used time/memory are in columns Runtime/RSS respectively. + +Access with :CP panel or :CP debug (uses debug build configuration). Interface ~ @@ -409,7 +475,7 @@ Test cases use competitive programming terminology with color highlighting: < ============================================================================== -INTERACTIVE MODE *cp-interact* +INTERACTIVE MODE *cp-interact* Run interactive problems manually or with an orchestrator. :CP interact is available for interactive problems. Test cases are ignored in interactive mode @@ -436,7 +502,7 @@ Keymaps ~ Close the terminal and restore the previous layout. ============================================================================== -ANSI COLORS AND HIGHLIGHTING *cp-ansi* +ANSI COLORS AND HIGHLIGHTING *cp-ansi* cp.nvim provides comprehensive ANSI color support and highlighting for compiler output, program stderr, and diff visualization. @@ -459,7 +525,7 @@ alter your config as follows: < ============================================================================== -HIGHLIGHT GROUPS *cp-highlights* +HIGHLIGHT GROUPS *cp-highlights* Test Status Groups ~ @@ -485,13 +551,13 @@ adapt to your colorscheme: DiffDelete Highlights removed text in git diffs ============================================================================== -TERMINAL COLOR INTEGRATION *cp-terminal-colors* +TERMINAL COLOR INTEGRATION *cp-terminal-colors* ANSI colors automatically use the terminal's color palette through Neovim's vim.g.terminal_color_* variables. ============================================================================== -HIGHLIGHT CUSTOMIZATION *cp-highlight-custom* +HIGHLIGHT CUSTOMIZATION *cp-highlight-custom* Customize highlight groups after your colorscheme loads: >lua @@ -502,12 +568,33 @@ Customize highlight groups after your colorscheme loads: }) ============================================================================== -PANEL KEYMAPS *cp-test-keys* +HELPERS *cp-helpers* + +The helpers module provides utility functions for buffer customization. +Access via: +>lua + local helpers = require('cp').helpers +< +Functions ~ + + helpers.clearcol({bufnr}) *helpers.clearcol* + Remove line numbers, columns, and signs from buffer. + Sets: + • number = false + • relativenumber = false + • signcolumn = 'no' + • statuscolumn = '' + + Parameters: ~ + {bufnr} (integer) Buffer handle + +============================================================================== +PANEL KEYMAPS *cp-panel-keys* Navigate to next test case Navigate to previous test case t Cycle through diff modes: none → git → vim -q Exit run panel and restore layout +q Exit panel and restore layout Exit interactive terminal and restore layout Diff Modes ~ @@ -528,7 +615,7 @@ execution pipeline, but with isolated input/output for precise failure analysis. ============================================================================== -FILE STRUCTURE *cp-files* +FILE STRUCTURE *cp-files* cp.nvim creates the following file structure upon problem setup: > @@ -537,11 +624,10 @@ cp.nvim creates the following file structure upon problem setup: > {problem_id}.run " Compiled binary io/ {problem_id}.n.cpin " nth test input - {problem_id}.n.cpout " nth program output - {problem_id}.expected " Expected output + {problem_id}.n.cpout " nth test expected output < ============================================================================== -HEALTH CHECK *cp-health* +HEALTH CHECK *cp-health* Run |:checkhealth| cp to verify your setup. From d4b88be44bb9e2744069e4d1c0cae4333162669c Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 23 Oct 2025 22:11:02 -0400 Subject: [PATCH 033/187] fix formatting --- tests/fixtures/cses_contests.html | 2174 ++++++++++++++++++++++++++++- 1 file changed, 2136 insertions(+), 38 deletions(-) diff --git a/tests/fixtures/cses_contests.html b/tests/fixtures/cses_contests.html index 1106f5a..0925bc4 100644 --- a/tests/fixtures/cses_contests.html +++ b/tests/fixtures/cses_contests.html @@ -1,43 +1,2141 @@ - + - - - - - - - - - + + + + + + + + + - -
-
- - - - -
- - - Dark mode -
+ +
+
+ + + + +
+ + + Dark mode +
+
-
-
- +
+ +
+ +
+ + + + + + +
+ + +
+
+
+ +
+ +
+

+ + - - diff --git a/tests/fixtures/atcoder_task_abc100_b.html b/tests/fixtures/atcoder_task_abc100_b.html index c7a28d3..dd0f1f9 100644 --- a/tests/fixtures/atcoder_task_abc100_b.html +++ b/tests/fixtures/atcoder_task_abc100_b.html @@ -1,600 +1,887 @@ - - - - - - - - - + - - B - Ringo's Favorite Numbers - - - - - + + B - Ringo's Favorite Numbers + + + + + - - - + + - - - + + - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + - + - - + + + + + + + + + + + + + + + + - - -
+ + + + + - + -
- -
-
- + + + + + -
-
-
- - - Contest Duration: - - (local time) - (100 minutes) - - - Back to Home -
- +
+
+ + B - Ringo's Favorite Numbers + Editorial + + + / + + +
+

Time Limit: 2 sec / Memory Limit: 976 MiB

-
+
+ + +

配点: 200

- +
+
+

問題文

+

+ 今日は, 記念すべき AtCoder Beginner Contest 100 + が開催される. そのため, 高橋君はりんごさんに, + ある整数をプレゼントしようと思った.
+ 今日のコンテストは「AtCoder Beginner Contest + 100」なので, りんごさんは 100 で + ちょうど + D + 回割りきれる正の整数をプレゼントされると喜ぶ. +

+

+ さて, りんごさんがプレゼントされると喜ぶような整数のうち + N 番目に小さいものを求めなさい. +

+
+
- -
-
+
+
+

制約

+
    +
  • + D0, 1, 2 のいずれかである +
  • +
  • + N1 以上 + 100 以下の整数 +
  • +
+
+
+
+
+
+
+

入力

+

入力は以下の形式で標準入力から与えられる.

+
D N
+
+
+
+
+
+

出力

+

+ 100 でちょうど + D 回割りきれる正の整数の中で + N 番目に小さいものを出力しなさい. +

+
+
+
- -
- - - -
- - - - - - -
+
- - - -
-
-
+
+
+

入力例 1

+
+0 5
+
+
+
-
- -
-

- +
+
+

出力例 1

+
+5
+
- +

+ 100 でちょうど + 0 回割り切れる(すなわち, + 100 で割り切れない)整数は, 1, + 2, 3, 4, 5, + 6, 7, ... と続く.
+ よって, 5 番目に小さいりんごさんが喜ぶ整数は + 5 である. +

+
+
+ +
+ +
+
+

入力例 2

+
+1 11
+
+
+
+ +
+
+

出力例 2

+
+1100
+
+ +

+ 100 でちょうど + 1 回割り切れる整数は, 100, + 200, 300, 400, + 500, 600, 700, + 800, 900, 1 \ 000, + 1 \ 100, ... と続く.
+ よって, 求めたい整数は 1 \ 100 である. +

+
+
+ +
+ +
+
+

入力例 3

+
+2 85
+
+
+
+ +
+
+

出力例 3

+
+850000
+
+ +

+ 100 でちょうど + 2 回割り切れる整数は, 10 \ 000, + 20 \ 000, 30 \ 000, ... と続く.
+ よって, 求めたい整数は 850 \ 000 である. +

+
+
+ + +

Score: 200 points

+ +
+
+

Problem Statement

+

+ Today, the memorable AtCoder Beginner Contest 100 takes + place. On this occasion, Takahashi would like to give an + integer to Ringo.
+ As the name of the contest is AtCoder Beginner Contest + 100, Ringo would be happy if he is given a positive + integer that can be divided by 100 + exactly D times. +

+

+ Find the N-th smallest integer that would + make Ringo happy. +

+
+
+ +
+
+

Constraints

+
    +
  • + D is 0, 1 or + 2. +
  • +
  • + N is an integer between 1 and + 100 (inclusive). +
  • +
+
+
+ +
+ +
+
+
+

Input

+

+ Input is given from Standard Input in the following + format: +

+
D N
+
+
+
+ +
+
+

Output

+

+ Print the N-th smallest integer that can be + divided by 100 exactly D times. +

+
+
+
+ +
+ +
+
+

Sample Input 1

+
+0 5
+
+
+
+ +
+
+

Sample Output 1

+
+5
+
+ +

+ The integers that can be divided by + 100 exactly 0 times (that is, not + divisible by 100) are as follows: + 1, 2, 3, 4, + 5, 6, 7, ...
+ Thus, the 5-th smallest integer that would + make Ringo happy is 5. +

+
+
+ +
+ +
+
+

Sample Input 2

+
+1 11
+
+
+
+ +
+
+

Sample Output 2

+
+1100
+
+ +

+ The integers that can be divided by + 100 exactly once are as follows: + 100, 200, 300, + 400, 500, 600, + 700, 800, 900, + 1 \ 000, 1 \ 100, ...
+ Thus, the integer we are seeking is 1 \ 100. +

+
+
+ +
+ +
+
+

Sample Input 3

+
+2 85
+
+
+
+ +
+
+

Sample Output 3

+
+850000
+
+ +

+ The integers that can be divided by + 100 exactly twice are as follows: + 10 \ 000, 20 \ 000, + 30 \ 000, ...
+ Thus, the integer we are seeking is + 850 \ 000. +

+
+
+
+ +
+ + + +
+ +
+ + + + + + +
+ + + +
+ + +
+ +
+

+ + - - diff --git a/tests/fixtures/atcoder_task_abc100_c.html b/tests/fixtures/atcoder_task_abc100_c.html index 6b298ba..351a2dc 100644 --- a/tests/fixtures/atcoder_task_abc100_c.html +++ b/tests/fixtures/atcoder_task_abc100_c.html @@ -1,618 +1,904 @@ - - - - - - - - - + - - C - *3 or /2 - - - - - + + C - *3 or /2 + + + + + - - - + + - - - + + - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + - + - - + + + + + + + + + + + + + + + + - - -
+ + + + + - + -
- -
-
- + + + + + -
-
-
- - - Contest Duration: - - (local time) - (100 minutes) - - - Back to Home -
- +
+
+ + C - *3 or /2 + Editorial + + + / + + +
+

Time Limit: 2 sec / Memory Limit: 976 MiB

-
+
+ + +

配点: 300

- +
+
+

問題文

+

+ AtCoder Beginner Contest 100 の開催にともなって, AtCoder + 社では長さ N の数列 a = {a_1, a_2, a_3, ..., a_N} が飾られることになった.
+ 社員のすぬけ君は, この数列で遊んでみようと思った. +

+

+ 具体的には, + 以下の操作をできるだけ多くの回数繰り返そうと思った. +

+
1 \leq i \leq N を満たす全ての i に対して, それぞれ「a_i の値を 2 で割る」「a_i の値を 3 倍する」のどちらかを行う.  
+ただし, 全ての i に対して 3 倍することはできず, 操作後の a_i の値は整数でなければならない.  
+
- -
-
+

最大で何回の操作が可能か, 求めなさい.

+ +
+
+
+

制約

+
    +
  • + N1 以上 + 10 \ 000 以下の整数 +
  • +
  • + a_i1 以上 + 1 \ 000 \ 000 \ 000 以下の整数 +
  • +
+
+
+
+
+
+
+

入力

+

入力は以下の形式で標準入力から与えられる.

+
N
+a_1 a_2 a_3 ... a_N
+
+
+
- -
- - - -
- - - - - - -
+
+
+

出力

+

すぬけ君が行える最大の操作回数を出力しなさい.

+
+
+
- - - -
-
-
+
-
- -
-

- +
+
+

入力例 1

+
+3
+5 2 4
+
+
+
- +
+
+

出力例 1

+
+3
+
+ +

+ 最初, 数列は {5, 2, 4} であるが, + 以下のように操作すれば + 3 回の操作を行うことができる. +

+
    +
  • + 最初に, a_13 倍し, + a_23 倍し, a_3 を + 2 で割る. すると数列は + {15, 6, 2} となる. +
  • +
  • + 次に, a_13 倍し, + a_22 で割り, + a_33 倍する. すると数列は + {45, 3, 6} となる. +
  • +
  • + 最後に, a_13 倍し, + a_23 倍し, a_3 を + 2 で割る. すると数列は + {135, 9, 3} となる. +
  • +
+
+
+ +
+ +
+
+

入力例 2

+
+4
+631 577 243 199
+
+
+
+ +
+
+

出力例 2

+
+0
+
+ +

+ 全ての要素が奇数なので, 操作はできない. よって答えは + 0 である. +

+
+
+ +
+ +
+
+

入力例 3

+
+10
+2184 2126 1721 1800 1024 2528 3360 1945 1280 1776
+
+
+
+ +
+
+

出力例 3

+
+39
+
+
+
+ + +

Score: 300 points

+ +
+
+

Problem Statement

+

+ As AtCoder Beginner Contest 100 is taking place, the + office of AtCoder, Inc. is decorated with a sequence of + length N, a = {a_1, a_2, a_3, ..., a_N}.
+ Snuke, an employee, would like to play with this + sequence. +

+

+ Specifically, he would like to repeat the following + operation as many times as possible: +

+
For every i satisfying 1 \leq i \leq N, perform one of the following: "divide a_i by 2" and "multiply a_i by 3".  
+Here, choosing "multiply a_i by 3" for every i is not allowed, and the value of a_i after the operation must be an integer.
+
+ +

At most how many operations can be performed?

+
+
+ +
+
+

Constraints

+
    +
  • + N is an integer between 1 and + 10 \ 000 (inclusive). +
  • +
  • + a_i is an integer between 1 and + 1 \ 000 \ 000 \ 000 (inclusive). +
  • +
+
+
+ +
+ +
+
+
+

Input

+

+ Input is given from Standard Input in the following + format: +

+
N
+a_1 a_2 a_3 ... a_N
+
+
+
+ +
+
+

Output

+

+ Print the maximum number of operations that Snuke can + perform. +

+
+
+
+ +
+ +
+
+

Sample Input 1

+
+3
+5 2 4
+
+
+
+ +
+
+

Sample Output 1

+
+3
+
+ +

+ The sequence is initially {5, 2, 4}. Three + operations can be performed as follows: +

+
    +
  • + First, multiply a_1 by 3, + multiply a_2 by 3 and divide + a_3 by 2. The sequence is now + {15, 6, 2}. +
  • +
  • + Next, multiply a_1 by 3, divide + a_2 by 2 and multiply + a_3 by 3. The sequence is now + {45, 3, 6}. +
  • +
  • + Finally, multiply a_1 by 3, + multiply a_2 by 3 and divide + a_3 by 2. The sequence is now + {135, 9, 3}. +
  • +
+
+
+ +
+ +
+
+

Sample Input 2

+
+4
+631 577 243 199
+
+
+
+ +
+
+

Sample Output 2

+
+0
+
+ +

+ No operation can be performed since all the elements are + odd. Thus, the answer is 0. +

+
+
+ +
+ +
+
+

Sample Input 3

+
+10
+2184 2126 1721 1800 1024 2528 3360 1945 1280 1776
+
+
+
+ +
+
+

Sample Output 3

+
+39
+
+
+
+
+ + + + + +
+ +
+ + + + + + +
+ + + +
+ + +
+ +
+

+ + - - diff --git a/tests/fixtures/atcoder_task_abc100_d.html b/tests/fixtures/atcoder_task_abc100_d.html index 552b276..ca47a6b 100644 --- a/tests/fixtures/atcoder_task_abc100_d.html +++ b/tests/fixtures/atcoder_task_abc100_d.html @@ -1,728 +1,1086 @@ - - - - - - - - - + - - D - Patisserie ABC - - - - - + + D - Patisserie ABC + + + + + - - - + + - - - + + - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + - + - - + + + + + + + + + + + + + + + + - - -
+ + + + + - + -
- -
-
- + + + + + -
-
-
- - - Contest Duration: - - (local time) - (100 minutes) - - - Back to Home -
- +
+
+ + D - Patisserie ABC + Editorial + + + / + + +
+

Time Limit: 2 sec / Memory Limit: 976 MiB

-
+
+ + +

配点: 400

- +
+
+

問題文

+

+ 高橋君はプロのパティシエになり, AtCoder Beginner Contest + 100 を記念して, 「ABC洋菓子店」というお店を開いた. +

+

+ ABC洋菓子店では, + N 種類のケーキを売っている.
+ 各種類のケーキには「綺麗さ」「おいしさ」「人気度」の + 3 つの値を持ち, + i 種類目のケーキの綺麗さは x_i, + おいしさは y_i, 人気度は + z_i である.
+ これらの値は 0 以下である可能性もある. +

+

+ りんごさんは, ABC洋菓子店で + M 個のケーキを食べることにした. + 彼は次のように, + 食べるケーキの組み合わせを選ぶことにした. +

+
    +
  • 同じ種類のケーキを 2 個以上食べない.
  • +
  • + 上の条件を満たしつつ, (綺麗さの合計の絶対値) + + (おいしさの合計の絶対値) + (人気度の合計の絶対値) + が最大になるように選ぶ. +
  • +
+

+ このとき, りんごさんが選ぶケーキの + (綺麗さの合計の絶対値) + (おいしさの合計の絶対値) + + (人気度の合計の絶対値) の最大値を求めなさい. +

+
+
- -
-
+
+
+

制約

+
    +
  • + N1 以上 + 1 \ 000 以下の整数 +
  • +
  • + M0 以上 + N 以下の整数 +
  • +
  • + x_i, y_i, z_i \ (1 \leq i \leq N) は, + それぞれ -10 \ 000 \ 000 \ 000 以上 + 10 \ 000 \ 000 \ 000 以下の整数. +
  • +
+
+
+
+
+
+
+

入力

+

入力は以下の形式で標準入力から与えられる.

+
N M
+x_1 y_1 z_1
+x_2 y_2 z_2
+ :  :
+x_N y_N z_N
+
+
+
+
+
+

出力

+

+ りんごさんが選ぶケーキの (綺麗さの合計の絶対値) + + (おいしさの合計の絶対値) + (人気度の合計の絶対値) + の最大値を出力しなさい. +

+
+
+
- -
- - - -
- - - - - - -
+
- - - -
-
-
+
+
+

入力例 1

+
+5 3
+3 1 4
+1 5 9
+2 6 5
+3 5 8
+9 7 9
+
+
+
-
- -
-

- +
+
+

出力例 1

+
+56
+
- +

+ 2, 4, 5 種類目のケーキを食べることを考える. + そのとき, + 「綺麗さ」「おいしさ」「人気度」の合計はそれぞれ次のようになる. +

+
    +
  • 綺麗さ:1 + 3 + 9 = 13
  • +
  • おいしさ:5 + 5 + 7 = 17
  • +
  • 人気度:9 + 8 + 9 = 26
  • +
+

+ このときの (綺麗さの合計の絶対値) + + (おいしさの合計の絶対値) + (人気度の合計の絶対値) は + 13 + 17 + 26 = 56 となり, これが最大になる. +

+
+
+ +
+ +
+
+

入力例 2

+
+5 3
+1 -2 3
+-4 5 -6
+7 -8 -9
+-10 11 -12
+13 -14 15
+
+
+
+ +
+
+

出力例 2

+
+54
+
+ +

+ 1, 3, 5 種類目のケーキを食べることを考える. + そのとき, + 「綺麗さ」「おいしさ」「人気度」の合計はそれぞれ次のようになる. +

+
    +
  • 綺麗さ:1 + 7 + 13 = 21
  • +
  • おいしさ:(-2) + (-8) + (-14) = -24
  • +
  • 人気度:3 + (-9) + 15 = 9
  • +
+

+ このときの (綺麗さの合計の絶対値) + + (おいしさの合計の絶対値) + (人気度の合計の絶対値) は + 21 + 24 + 9 = 54 となり, これが最大になる. +

+
+
+ +
+ +
+
+

入力例 3

+
+10 5
+10 -80 21
+23 8 38
+-94 28 11
+-26 -2 18
+-69 72 79
+-26 -86 -54
+-72 -50 59
+21 65 -32
+40 -94 87
+-62 18 82
+
+
+
+ +
+
+

出力例 3

+
+638
+
+ +

+ 3, 4, 5, 7, 10 種類目のケーキを食べると, + 綺麗さの合計は -323, おいしさの合計は + 66, 人気度の合計は + 249 となる.
+ このときの (綺麗さの合計の絶対値) + + (おいしさの合計の絶対値) + (人気度の合計の絶対値) は + 323 + 66 + 249 = 638 となり, + これが最大になる. +

+
+
+ +
+ +
+
+

入力例 4

+
+3 2
+2000000000 -9000000000 4000000000
+7000000000 -5000000000 3000000000
+6000000000 -1000000000 8000000000
+
+
+
+ +
+
+

出力例 4

+
+30000000000
+
+ +

+ ケーキの綺麗さ, おいしさ, 人気度や出力すべき値が, 32bit + 整数に収まらない場合もある. +

+
+
+ + +

Score: 400 points

+ +
+
+

Problem Statement

+

+ Takahashi became a pastry chef and opened a shop + La Confiserie d'ABC to celebrate AtCoder + Beginner Contest 100. +

+

+ The shop sells N kinds of cakes.
+ Each kind of cake has three parameters "beauty", + "tastiness" and "popularity". The i-th kind + of cake has the beauty of x_i, the tastiness + of y_i and the popularity of + z_i.
+ These values may be zero or negative. +

+

+ Ringo has decided to have M pieces of cakes + here. He will choose the set of cakes as follows: +

+
    +
  • + Do not have two or more pieces of the same kind of + cake. +
  • +
  • + Under the condition above, choose the set of cakes to + maximize (the absolute value of the total beauty) + + (the absolute value of the total tastiness) + (the + absolute value of the total popularity). +
  • +
+

+ Find the maximum possible value of (the absolute value + of the total beauty) + (the absolute value of the total + tastiness) + (the absolute value of the total + popularity) for the set of cakes that Ringo chooses. +

+
+
+ +
+
+

Constraints

+
    +
  • + N is an integer between 1 and + 1 \ 000 (inclusive). +
  • +
  • + M is an integer between 0 and + N (inclusive). +
  • +
  • + x_i, y_i, z_i \ (1 \leq i \leq N) are + integers between -10 \ 000 \ 000 \ 000 and + 10 \ 000 \ 000 \ 000 (inclusive). +
  • +
+
+
+ +
+ +
+
+
+

Input

+

+ Input is given from Standard Input in the following + format: +

+
N M
+x_1 y_1 z_1
+x_2 y_2 z_2
+ :  :
+x_N y_N z_N
+
+
+
+ +
+
+

Output

+

+ Print the maximum possible value of (the absolute + value of the total beauty) + (the absolute value of + the total tastiness) + (the absolute value of the + total popularity) for the set of cakes that Ringo + chooses. +

+
+
+
+ +
+ +
+
+

Sample Input 1

+
+5 3
+3 1 4
+1 5 9
+2 6 5
+3 5 8
+9 7 9
+
+
+
+ +
+
+

Sample Output 1

+
+56
+
+ +

+ Consider having the 2-nd, 4-th and + 5-th kinds of cakes. The total beauty, + tastiness and popularity will be as follows: +

+
    +
  • Beauty: 1 + 3 + 9 = 13
  • +
  • Tastiness: 5 + 5 + 7 = 17
  • +
  • Popularity: 9 + 8 + 9 = 26
  • +
+

+ The value (the absolute value of the total beauty) + + (the absolute value of the total tastiness) + (the + absolute value of the total popularity) here is + 13 + 17 + 26 = 56. This is the maximum value. +

+
+
+ +
+ +
+
+

Sample Input 2

+
+5 3
+1 -2 3
+-4 5 -6
+7 -8 -9
+-10 11 -12
+13 -14 15
+
+
+
+ +
+
+

Sample Output 2

+
+54
+
+ +

+ Consider having the 1-st, 3-rd and + 5-th kinds of cakes. The total beauty, + tastiness and popularity will be as follows: +

+
    +
  • Beauty: 1 + 7 + 13 = 21
  • +
  • Tastiness: (-2) + (-8) + (-14) = -24
  • +
  • Popularity: 3 + (-9) + 15 = 9
  • +
+

+ The value (the absolute value of the total beauty) + + (the absolute value of the total tastiness) + (the + absolute value of the total popularity) here is + 21 + 24 + 9 = 54. This is the maximum value. +

+
+
+ +
+ +
+
+

Sample Input 3

+
+10 5
+10 -80 21
+23 8 38
+-94 28 11
+-26 -2 18
+-69 72 79
+-26 -86 -54
+-72 -50 59
+21 65 -32
+40 -94 87
+-62 18 82
+
+
+
+ +
+
+

Sample Output 3

+
+638
+
+ +

+ If we have the 3-rd, 4-th, + 5-th, 7-th and 10-th + kinds of cakes, the total beauty, tastiness and + popularity will be -323, 66 and + 249, respectively.
+ The value (the absolute value of the total beauty) + + (the absolute value of the total tastiness) + (the + absolute value of the total popularity) here is + 323 + 66 + 249 = 638. This is the maximum + value. +

+
+
+ +
+ +
+
+

Sample Input 4

+
+3 2
+2000000000 -9000000000 4000000000
+7000000000 -5000000000 3000000000
+6000000000 -1000000000 8000000000
+
+
+
+ +
+
+

Sample Output 4

+
+30000000000
+
+ +

+ The values of the beauty, tastiness and popularity of + the cakes and the value to be printed may not fit into + 32-bit integers. +

+
+
+
+ + + + + +
+ +
+ + + + + + +
+ + + +
+ + +
+ +
+

+ + - - diff --git a/tests/fixtures/codeforces_1550_problems.html b/tests/fixtures/codeforces_1550_problems.html index fa19bbb..449cab5 100644 --- a/tests/fixtures/codeforces_1550_problems.html +++ b/tests/fixtures/codeforces_1550_problems.html @@ -1,977 +1,10122 @@ - + + + + + + + + + + Problems - Codeforces
Loading [MathJax]/jax/output/HTML-CSS/fonts/TeX/fontdata.js
+ + + + + + + + + + + + + Problems - Codeforces + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Loading [MathJax]/jax/output/HTML-CSS/fonts/TeX/fontdata.js +
+ +
+
+ +
+ + + +
-
- + +
\ No newline at end of file + if (document.body) { + var a = document.createElement('iframe') + a.height = 1 + a.width = 1 + a.style.position = 'absolute' + a.style.top = 0 + a.style.left = 0 + a.style.border = 'none' + a.style.visibility = 'hidden' + document.body.appendChild(a) + if ('loading' !== document.readyState) c() + else if (window.addEventListener) + document.addEventListener('DOMContentLoaded', c) + else { + var e = document.onreadystatechange || function () {} + document.onreadystatechange = function (b) { + e(b) + 'loading' !== document.readyState && + ((document.onreadystatechange = e), c()) + } + } + } + })() + + + + + + +
+
+
+ + From 57b4a3ff1571a76f96d6c9b34f2a096488f64bc5 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 23 Oct 2025 22:17:49 -0400 Subject: [PATCH 035/187] fix: rename --- .github/workflows/{luarocks.yml => luarocks.yaml} | 2 +- .github/workflows/{quality.yml => quality.yaml} | 0 .github/workflows/{test.yml => test.yaml} | 0 .luarc.json | 14 +++----------- .pre-commit-config.yaml | 7 +++---- 5 files changed, 7 insertions(+), 16 deletions(-) rename .github/workflows/{luarocks.yml => luarocks.yaml} (96%) rename .github/workflows/{quality.yml => quality.yaml} (100%) rename .github/workflows/{test.yml => test.yaml} (100%) diff --git a/.github/workflows/luarocks.yml b/.github/workflows/luarocks.yaml similarity index 96% rename from .github/workflows/luarocks.yml rename to .github/workflows/luarocks.yaml index f3460d1..c64568f 100644 --- a/.github/workflows/luarocks.yml +++ b/.github/workflows/luarocks.yaml @@ -3,7 +3,7 @@ name: Release on: push: tags: - - "*" + - '*' workflow_dispatch: jobs: diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yaml similarity index 100% rename from .github/workflows/quality.yml rename to .github/workflows/quality.yaml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yaml similarity index 100% rename from .github/workflows/test.yml rename to .github/workflows/test.yaml diff --git a/.luarc.json b/.luarc.json index 02ba89e..3ccfeda 100644 --- a/.luarc.json +++ b/.luarc.json @@ -1,16 +1,8 @@ { "runtime.version": "Lua 5.1", - "runtime.path": [ - "lua/?.lua", - "lua/?/init.lua" - ], - "diagnostics.globals": [ - "vim" - ], - "workspace.library": [ - "$VIMRUNTIME/lua", - "${3rd}/luv/library" - ], + "runtime.path": ["lua/?.lua", "lua/?/init.lua"], + "diagnostics.globals": ["vim"], + "workspace.library": ["$VIMRUNTIME/lua", "${3rd}/luv/library"], "workspace.checkThirdParty": false, "completion.callSnippet": "Replace" } diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 74499e8..4702e92 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -minimum_pre_commit_version: "3.5.0" +minimum_pre_commit_version: '3.5.0' repos: - repo: https://github.com/JohnnyMorganz/StyLua @@ -17,7 +17,7 @@ repos: files: \.py$ - id: ruff name: ruff (lint imports) - args: ["--fix", "--select=I"] + args: ['--fix', '--select=I'] files: \.py$ - repo: local @@ -26,7 +26,7 @@ repos: name: mypy (type check) entry: uv run mypy language: system - args: ["."] + args: ['.'] pass_filenames: false - repo: https://github.com/pre-commit/mirrors-prettier @@ -35,4 +35,3 @@ repos: - id: prettier name: prettier (format markdown) files: \.md$ - From ce975d0f1eb05893ff0c20b816053a7f31fb2491 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 23 Oct 2025 22:24:20 -0400 Subject: [PATCH 036/187] fix(ci): regex --- scrapers/cses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scrapers/cses.py b/scrapers/cses.py index b8a6145..422801e 100644 --- a/scrapers/cses.py +++ b/scrapers/cses.py @@ -76,7 +76,7 @@ CATEGORY_BLOCK_RE = re.compile( re.DOTALL, ) TASK_LINK_RE = re.compile( - r'
  • (?P[^<]+)</a>', + r'<li\s+class="task">\s*<a\s+href="/problemset/task/(?P<id>\d+)/?">(?P<title>[^<]+)</a\s*>', re.DOTALL, ) From a9ac06de838ba9a2aa092fbfc4bb2f200661618f Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Thu, 23 Oct 2025 22:24:39 -0400 Subject: [PATCH 037/187] fix(ci): regex --- scrapers/cses.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scrapers/cses.py b/scrapers/cses.py index 422801e..c66da96 100644 --- a/scrapers/cses.py +++ b/scrapers/cses.py @@ -72,7 +72,7 @@ async def fetch_text(client: httpx.AsyncClient, path: str) -> str: CATEGORY_BLOCK_RE = re.compile( - r'<h2>(?P<cat>[^<]+)</h2>\s*<ul class="task-list">(?P<body>.*?)</ul>', + r'<h2>(?P<cat>[^<]+)</h2>\s*<ul\s+class="task-list">(?P<body>.*?)</ul>', re.DOTALL, ) TASK_LINK_RE = re.compile( @@ -81,15 +81,15 @@ TASK_LINK_RE = re.compile( ) TITLE_RE = re.compile( - r'<div class="title-block">.*?<h1>(?P<title>[^<]+)</h1>', re.DOTALL + r'<div\s+class="title-block">.*?<h1>(?P<title>[^<]+)</h1>', re.DOTALL ) -TIME_RE = re.compile(r"<li><b>Time limit:</b>\s*([0-9.]+)\s*s</li>") -MEM_RE = re.compile(r"<li><b>Memory limit:</b>\s*(\d+)\s*MB</li>") +TIME_RE = re.compile(r"<li>\s*<b>Time limit:</b>\s*([0-9.]+)\s*s\s*</li>") +MEM_RE = re.compile(r"<li>\s*<b>Memory limit:</b>\s*(\d+)\s*MB\s*</li>") SIDEBAR_CAT_RE = re.compile( - r'<div class="nav sidebar">.*?<h4>(?P<cat>[^<]+)</h4>', re.DOTALL + r'<div\s+class="nav sidebar">.*?<h4>(?P<cat>[^<]+)</h4>', re.DOTALL ) -MD_BLOCK_RE = re.compile(r'<div class="md">(.*?)</div>', re.DOTALL | re.IGNORECASE) +MD_BLOCK_RE = re.compile(r'<div\s+class="md">(.*?)</div>', re.DOTALL | re.IGNORECASE) EXAMPLE_SECTION_RE = re.compile( r"<h[1-6][^>]*>\s*example[s]?:?\s*</h[1-6]>\s*(?P<section>.*?)(?=<h[1-6][^>]*>|$)", re.DOTALL | re.IGNORECASE, From b77c81d63ed97413c76cf1aa0f32cb64189c2c6d Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Thu, 23 Oct 2025 22:30:16 -0400 Subject: [PATCH 038/187] fix: ignore file --- .prettierignore | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .prettierignore diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..0b59b01 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,7 @@ +.pytest_cache/ +node_modules/ +.venv/ +build/ +dist/ +*.pyc +__pycache__/ From b735af6a2503f576b0375bec21457f2c907fa038 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Thu, 23 Oct 2025 22:31:23 -0400 Subject: [PATCH 039/187] fix: ignore fixtures --- .prettierignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.prettierignore b/.prettierignore index 0b59b01..72a3fa4 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,3 +5,4 @@ build/ dist/ *.pyc __pycache__/ +tests/fixtures/ From 92ffa41ed01f53e7dcd945837a426bde506003ab Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Thu, 23 Oct 2025 23:02:48 -0400 Subject: [PATCH 040/187] feat: fix test rendering --- lua/cp/helpers.lua | 17 +++++ lua/cp/ui/panel.lua | 162 +++++++++++++++++++++++++++++--------------- 2 files changed, 126 insertions(+), 53 deletions(-) diff --git a/lua/cp/helpers.lua b/lua/cp/helpers.lua index 27c6cba..ba59192 100644 --- a/lua/cp/helpers.lua +++ b/lua/cp/helpers.lua @@ -10,4 +10,21 @@ function M.clearcol(bufnr) end end +function M.pad_right(text, width) + local pad = width - #text + if pad <= 0 then + return text + end + return text .. string.rep(' ', pad) +end + +function M.center(text, width) + local pad = width - #text + if pad <= 0 then + return text + end + local left = math.ceil(pad / 2) + return string.rep(' ', left) .. text .. string.rep(' ', pad - left) +end + return M diff --git a/lua/cp/ui/panel.lua b/lua/cp/ui/panel.lua index ce846ba..bb04c66 100644 --- a/lua/cp/ui/panel.lua +++ b/lua/cp/ui/panel.lua @@ -68,9 +68,9 @@ function M.toggle_interactive(interactor_cmd) if not contest_data or not contest_data.index_map - or contest_data.problems[contest_data.index_map[problem_id]].interactive + or not contest_data.problems[contest_data.index_map[problem_id]].interactive then - logger.log('This problem is interactive. Use :CP {run,panel}.', vim.log.levels.ERROR) + logger.log('This problem is interactive. Use :CP interact.', vim.log.levels.ERROR) return end @@ -210,7 +210,7 @@ function M.ensure_io_view() and contest_data.index_map and contest_data.problems[contest_data.index_map[problem_id]].interactive then - logger.log('No platform configured.', vim.log.levels.ERROR) + logger.log('This problem is not interactive. Use :CP {run,panel}.', vim.log.levels.ERROR) return end @@ -285,12 +285,8 @@ function M.run_io_view(test_index) cache.load() local contest_data = cache.get_contest_data(platform, contest_id) - if - not contest_data - or not contest_data.index_map - or contest_data.problems[contest_data.index_map[problem_id]].interactive - then - logger.log('This problem is interactive. Use :CP {run,panel}.', vim.log.levels.ERROR) + if not contest_data or not contest_data.index_map then + logger.log('No test cases available.', vim.log.levels.ERROR) return end @@ -358,62 +354,122 @@ function M.run_io_view(test_index) run.run_all_test_cases(test_indices) - local input_lines = {} - for _, idx in ipairs(test_indices) do - local tc = test_state.test_cases[idx] - for _, line in ipairs(vim.split(tc.input, '\n')) do - table.insert(input_lines, line) - end - end - utils.update_buffer_content(io_state.input_buf, input_lines, nil, nil) - local run_render = require('cp.runner.run_render') run_render.setup_highlights() - if #test_indices == 1 then - local idx = test_indices[1] - local tc = test_state.test_cases[idx] - local status = run_render.get_status_info(tc) + local input_lines = {} + local output_lines = {} + local verdict_data = {} + + local widths = { test_num = 0, status = 0, time = 0, memory = 0, exit = 0 } + + for _, idx in ipairs(test_indices) do + local tc = test_state.test_cases[idx] - local output_lines = {} if tc.actual then for _, line in ipairs(vim.split(tc.actual, '\n', { plain = true, trimempty = false })) do table.insert(output_lines, line) end end - - table.insert(output_lines, '') - local time = tc.time_ms and string.format('%.2fms', tc.time_ms) or '—' - local code = tc.code and tostring(tc.code) or '—' - table.insert(output_lines, string.format('--- %s: %s | Exit: %s ---', status.text, time, code)) - - local highlights = tc.actual_highlights or {} - local ns = vim.api.nvim_create_namespace('cp_io_view_output') - utils.update_buffer_content(io_state.output_buf, output_lines, highlights, ns) - else - local verdict_lines = {} - local verdict_highlights = {} - for _, idx in ipairs(test_indices) do - local tc = test_state.test_cases[idx] - local status = run_render.get_status_info(tc) - local time = tc.time_ms and string.format('%.2f', tc.time_ms) or '—' - local mem = tc.rss_mb and string.format('%.0f', tc.rss_mb) or '—' - local line = string.format('Test %d: %s (%sms, %sMB)', idx, status.text, time, mem) - table.insert(verdict_lines, line) - local status_pos = line:find(status.text, 1, true) - if status_pos then - table.insert(verdict_highlights, { - line = #verdict_lines - 1, - col_start = status_pos - 1, - col_end = status_pos - 1 + #status.text, - highlight_group = status.highlight_group, - }) - end + if idx < #test_indices then + table.insert(output_lines, '') end - local verdict_ns = vim.api.nvim_create_namespace('cp_io_view_verdict') - utils.update_buffer_content(io_state.output_buf, verdict_lines, verdict_highlights, verdict_ns) + local status = run_render.get_status_info(tc) + + local time_actual = tc.time_ms and string.format('%.2f', tc.time_ms) or '—' + local time_limit = test_state.constraints and tostring(test_state.constraints.timeout_ms) + or '—' + local time_str = time_actual .. '/' .. time_limit .. ' ms' + + local mem_actual = tc.rss_mb and string.format('%.0f', tc.rss_mb) or '—' + local mem_limit = test_state.constraints + and string.format('%.0f', test_state.constraints.memory_mb) + or '—' + local mem_str = mem_actual .. '/' .. mem_limit .. ' MB' + + local exit_code = tc.code or 0 + local signal_name = exit_code >= 128 and require('cp.constants').signal_codes[exit_code] or nil + local exit_str = signal_name and string.format('%d (%s)', exit_code, signal_name) + or tostring(exit_code) + + widths.test_num = math.max(widths.test_num, #('Test ' .. idx .. ':')) + widths.status = math.max(widths.status, #status.text) + widths.time = math.max(widths.time, #time_str) + widths.memory = math.max(widths.memory, #mem_str) + widths.exit = math.max(widths.exit, #('exit: ' .. exit_str)) + + table.insert(verdict_data, { + idx = idx, + status = status, + time_str = time_str, + mem_str = mem_str, + exit_str = exit_str, + }) + + for _, line in ipairs(vim.split(tc.input, '\n')) do + table.insert(input_lines, line) + end + if idx < #test_indices then + table.insert(input_lines, '') + end end + + local verdict_lines = {} + local verdict_highlights = {} + for _, vd in ipairs(verdict_data) do + local test_num_part = helpers.pad_right('Test ' .. vd.idx .. ':', widths.test_num) + local status_part = helpers.pad_right(vd.status.text, widths.status) + local time_part = helpers.pad_right(vd.time_str, widths.time) + local mem_part = helpers.pad_right(vd.mem_str, widths.memory) + local exit_part = helpers.pad_right('exit: ' .. vd.exit_str, widths.exit) + + local verdict_line = test_num_part + .. ' ' + .. status_part + .. ' | ' + .. time_part + .. ' | ' + .. mem_part + .. ' | ' + .. exit_part + table.insert(verdict_lines, verdict_line) + + local status_pos = verdict_line:find(vd.status.text, 1, true) + if status_pos then + table.insert(verdict_highlights, { + status = vd.status, + verdict_line = verdict_line, + }) + end + end + + if #output_lines > 0 and #verdict_lines > 0 then + table.insert(output_lines, '') + end + + local verdict_start = #output_lines + for _, line in ipairs(verdict_lines) do + table.insert(output_lines, line) + end + + local final_highlights = {} + for i, vh in ipairs(verdict_highlights) do + local status_pos = vh.verdict_line:find(vh.status.text, 1, true) + if status_pos then + table.insert(final_highlights, { + line = verdict_start + i - 1, + col_start = status_pos - 1, + col_end = status_pos - 1 + #vh.status.text, + highlight_group = vh.status.highlight_group, + }) + end + end + + utils.update_buffer_content(io_state.input_buf, input_lines, nil, nil) + + local output_ns = vim.api.nvim_create_namespace('cp_io_view_output') + utils.update_buffer_content(io_state.output_buf, output_lines, final_highlights, output_ns) end ---@param panel_opts? PanelOpts From 038fcd36f870b4a1e373d06e01c0f2a674c218cb Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Thu, 23 Oct 2025 23:14:53 -0400 Subject: [PATCH 041/187] feat(ui): fix alignment --- doc/cp.nvim.txt | 43 ++++++++++++++++++++++++++----------------- lua/cp/helpers.lua | 8 ++++++++ lua/cp/ui/panel.lua | 16 ++++++++-------- 3 files changed, 42 insertions(+), 25 deletions(-) diff --git a/doc/cp.nvim.txt b/doc/cp.nvim.txt index c429314..2ab4ee4 100644 --- a/doc/cp.nvim.txt +++ b/doc/cp.nvim.txt @@ -378,9 +378,9 @@ Example: Setting up and solving AtCoder contest ABC324 ============================================================================== I/O VIEW *cp-io-view* -The I/O view provides the main view aggregate view into test input and -program output. Used time/memory per test case are appended to the output. -The |cp-panel| offers more fine-grained analysis into each test case. +The I/O view provides lightweight test feedback in persistent side splits. +All test outputs are concatenated with verdict summaries at the bottom. +The |cp-panel| offers more fine-grained analysis with diff modes. Access the I/O view with :CP run [n] @@ -388,24 +388,33 @@ Layout ~ The I/O view appears as 30% width splits on the right side: > - ┌──────────────────────────┬──────────────────────────┐ - │ │ Output │ - │ │ Test 1: AC (42ms, 8MB) │ - │ │ Test 2: AC (38ms, 8MB) │ - │ Solution Code │ Test 3: WA (45ms, 8MB) │ - │ │ Test 4: AC (51ms, 9MB) │ - │ ├──────────────────────────┤ - │ │ Input │ - │ │ 5 3 │ - │ │ 1 2 3 4 5 │ - │ │ 2 1 │ - │ │ 10 20 │ - └──────────────────────────┴──────────────────────────┘ + ┌──────────────────────────┬─────────────────────────────────────────────┐ + │ │ Output (Top Split) │ + │ │ 5 510 │ + │ │ │ + │ │ 7 714 │ + │ Solution Code │ │ + │ │ Test 1: WA | 212.07/2000 ms | 1/512 MB |...│ + │ │ Test 2: WA | 81.94/2000 ms | 1/512 MB |...│ + │ ├─────────────────────────────────────────────┤ + │ │ Input (Bottom Split) │ + │ │ 1 2 3 │ + │ │ │ + │ │ 4 5 6 │ + └──────────────────────────┴─────────────────────────────────────────────┘ < +The output split shows: +1. Concatenated test outputs (separated by blank lines) +2. Space-aligned verdict summary with: + - Test number and status (AC/WA/TLE/MLE/RTE with color highlighting) + - Runtime: actual/limit in milliseconds + - Memory: actual/limit in megabytes + - Exit code (with signal name for crashes) + Usage ~ :CP run Run all tests - :CP run 3 Run test 3 + :CP run 3 Run test 3 only Buffer Customization ~ diff --git a/lua/cp/helpers.lua b/lua/cp/helpers.lua index ba59192..408ad0a 100644 --- a/lua/cp/helpers.lua +++ b/lua/cp/helpers.lua @@ -18,6 +18,14 @@ function M.pad_right(text, width) return text .. string.rep(' ', pad) end +function M.pad_left(text, width) + local pad = width - #text + if pad <= 0 then + return text + end + return string.rep(' ', pad) .. text +end + function M.center(text, width) local pad = width - #text if pad <= 0 then diff --git a/lua/cp/ui/panel.lua b/lua/cp/ui/panel.lua index bb04c66..12093d7 100644 --- a/lua/cp/ui/panel.lua +++ b/lua/cp/ui/panel.lua @@ -380,13 +380,13 @@ function M.run_io_view(test_index) local time_actual = tc.time_ms and string.format('%.2f', tc.time_ms) or '—' local time_limit = test_state.constraints and tostring(test_state.constraints.timeout_ms) or '—' - local time_str = time_actual .. '/' .. time_limit .. ' ms' + local time_data = time_actual .. '/' .. time_limit local mem_actual = tc.rss_mb and string.format('%.0f', tc.rss_mb) or '—' local mem_limit = test_state.constraints and string.format('%.0f', test_state.constraints.memory_mb) or '—' - local mem_str = mem_actual .. '/' .. mem_limit .. ' MB' + local mem_data = mem_actual .. '/' .. mem_limit local exit_code = tc.code or 0 local signal_name = exit_code >= 128 and require('cp.constants').signal_codes[exit_code] or nil @@ -395,15 +395,15 @@ function M.run_io_view(test_index) widths.test_num = math.max(widths.test_num, #('Test ' .. idx .. ':')) widths.status = math.max(widths.status, #status.text) - widths.time = math.max(widths.time, #time_str) - widths.memory = math.max(widths.memory, #mem_str) + widths.time = math.max(widths.time, #(time_data .. ' ms')) + widths.memory = math.max(widths.memory, #(mem_data .. ' MB')) widths.exit = math.max(widths.exit, #('exit: ' .. exit_str)) table.insert(verdict_data, { idx = idx, status = status, - time_str = time_str, - mem_str = mem_str, + time_data = time_data, + mem_data = mem_data, exit_str = exit_str, }) @@ -420,8 +420,8 @@ function M.run_io_view(test_index) for _, vd in ipairs(verdict_data) do local test_num_part = helpers.pad_right('Test ' .. vd.idx .. ':', widths.test_num) local status_part = helpers.pad_right(vd.status.text, widths.status) - local time_part = helpers.pad_right(vd.time_str, widths.time) - local mem_part = helpers.pad_right(vd.mem_str, widths.memory) + local time_part = helpers.pad_right(vd.time_data, widths.time - 3) .. ' ms' + local mem_part = helpers.pad_right(vd.mem_data, widths.memory - 3) .. ' MB' local exit_part = helpers.pad_right('exit: ' .. vd.exit_str, widths.exit) local verdict_line = test_num_part From 6a6cf2c5943b65d5d87e7152be9e19e9a486a0c2 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Thu, 23 Oct 2025 23:36:09 -0400 Subject: [PATCH 042/187] feat: bindings and --debug flag --- doc/cp.nvim.txt | 49 +++++++++++++++++++++++++++++++-------- lua/cp/commands/init.lua | 43 +++++++++++++++++++--------------- lua/cp/config.lua | 18 ++++++++++++++ lua/cp/constants.lua | 2 +- lua/cp/runner/execute.lua | 10 ++++---- lua/cp/runner/run.lua | 15 +++++++----- lua/cp/state.lua | 7 ++++++ lua/cp/ui/panel.lua | 44 ++++++++++++++++++++++++++++++----- 8 files changed, 142 insertions(+), 46 deletions(-) diff --git a/doc/cp.nvim.txt b/doc/cp.nvim.txt index 2ab4ee4..3ef99be 100644 --- a/doc/cp.nvim.txt +++ b/doc/cp.nvim.txt @@ -39,22 +39,25 @@ COMMANDS *cp-commands* :CP atcoder abc324 < View Commands ~ - :CP run [n] Run tests in I/O view (see |cp-io-view|). + :CP run [--debug] [n] + Run tests in I/O view (see |cp-io-view|). Lightweight split showing test verdicts. Without [n]: runs all tests, shows verdict summary With [n]: runs test n, shows detailed output + --debug: Use debug build (builds to build/<name>.dbg) Examples: > - :CP run " All tests, verdict list - :CP run 3 " Test 3 detail + :CP run " All tests + :CP run --debug 2 " Test 2, debug build < - :CP panel [n] Open full-screen test panel (see |cp-panel|). + :CP panel [--debug] [n] + Open full-screen test panel (see |cp-panel|). Aggregate table with diff modes for detailed analysis. Optional [n] focuses on specific test. - Example: > - :CP panel " All tests with diffs - :CP panel 2 " Focus on test 2 + --debug: Use debug build (with sanitizers, etc.) + Examples: > + :CP panel " All tests + :CP panel --debug 3 " Test 3, debug build < - :CP debug [n] Same as :CP panel but uses debug build configuration. :CP pick Launch configured picker for interactive platform/contest selection. @@ -97,13 +100,39 @@ Template Variables ~ Command templates support variable substitution using {variable} syntax: • {source} Source file path (e.g. "abc324a.cpp") - • {binary} Output binary path (e.g. "build/abc324a.run") + • {binary} Output binary path (e.g. "build/abc324a.run" or + "build/abc324a.dbg" for debug builds) Example template: > build = { 'g++', '{source}', '-o', '{binary}', '-std=c++17' } < Would expand to: > g++ abc324a.cpp -o build/abc324a.run -std=c++17 < +Debug Builds ~ + *cp-debug-builds* + The --debug flag uses the debug command configuration instead of build: + + • Normal build: commands.build → outputs to build/<name>.run + • Debug build: commands.debug → outputs to build/<name>.dbg + + Debug builds typically include sanitizers (address, undefined behavior) to + catch memory errors, buffer overflows, and other issues. Both binaries + coexist, so you can switch between normal and debug mode without + recompiling. + + Example debug configuration: > + languages = { + cpp = { + extension = 'cc', + commands = { + build = { 'g++', '-std=c++17', '{source}', '-o', '{binary}' }, + run = { '{binary}' }, + debug = { 'g++', '-std=c++17', '-fsanitize=address,undefined', + '{source}', '-o', '{binary}' }, + } + } + } +< ============================================================================== CONFIGURATION *cp-config* @@ -446,7 +475,7 @@ The panel provides full-screen test analysis with diff modes for detailed debugging. Problem time/memory limit constraints are in columns Time/Mem respectively. Used time/memory are in columns Runtime/RSS respectively. -Access with :CP panel or :CP debug (uses debug build configuration). +Access with :CP panel or :CP panel --debug (uses debug build configuration). Interface ~ diff --git a/lua/cp/commands/init.lua b/lua/cp/commands/init.lua index 319f952..ad612a7 100644 --- a/lua/cp/commands/init.lua +++ b/lua/cp/commands/init.lua @@ -53,23 +53,30 @@ local function parse_command(args) else return { type = 'action', action = 'interact' } end - elseif first == 'run' then - local test_arg = args[2] - if test_arg then - local test_index = tonumber(test_arg) - if not test_index then - return { - type = 'error', - message = ("Test index '%s' is not a number"):format(test_index), - } + elseif first == 'run' or first == 'panel' then + local debug = false + local test_index = nil + + for i = 2, #args do + local arg = args[i] + if arg == '--debug' then + debug = true + else + local idx = tonumber(arg) + if not idx then + return { + type = 'error', + message = ("Invalid argument '%s': expected test number or --debug"):format(arg), + } + end + if idx < 1 or idx ~= math.floor(idx) then + return { type = 'error', message = ("'%s' is not a valid test index"):format(idx) } + end + test_index = idx end - if test_index < 1 or test_index ~= math.floor(test_index) then - return { type = 'error', message = ("'%s' is not a valid test index"):format(test_index) } - end - return { type = 'action', action = 'run', test_index = test_index } - else - return { type = 'action', action = 'run' } end + + return { type = 'action', action = first, test_index = test_index, debug = debug } else return { type = 'action', action = first } end @@ -127,11 +134,9 @@ function M.handle_command(opts) if cmd.action == 'interact' then ui.toggle_interactive(cmd.interactor_cmd) elseif cmd.action == 'run' then - ui.run_io_view(cmd.test_index) + ui.run_io_view(cmd.test_index, cmd.debug) elseif cmd.action == 'panel' then - ui.toggle_panel() - elseif cmd.action == 'debug' then - ui.toggle_panel({ debug = true }) + ui.toggle_panel({ debug = cmd.debug, test_index = cmd.test_index }) elseif cmd.action == 'next' then setup.navigate_problem(1) elseif cmd.action == 'prev' then diff --git a/lua/cp/config.lua b/lua/cp/config.lua index 54515ae..26767e7 100644 --- a/lua/cp/config.lua +++ b/lua/cp/config.lua @@ -34,8 +34,12 @@ ---@field setup_io_input? fun(bufnr: integer, state: cp.State) ---@field setup_io_output? fun(bufnr: integer, state: cp.State) +---@class RunConfig +---@field width number + ---@class CpUI ---@field ansi boolean +---@field run RunConfig ---@field panel PanelConfig ---@field diff DiffConfig ---@field picker string|nil @@ -116,6 +120,7 @@ M.defaults = { filename = nil, ui = { ansi = true, + run = { width = 0.3 }, panel = { diff_mode = 'none', max_output_lines = 50 }, diff = { git = { @@ -157,6 +162,11 @@ local function validate_language(id, lang) extension = { lang.extension, 'string' }, commands = { lang.commands, { 'table' } }, }) + + if not lang.commands.run then + error(('[cp.nvim] languages.%s.commands.run is required'):format(id)) + end + if lang.commands.build ~= nil then vim.validate({ build = { lang.commands.build, { 'table' } } }) if not has_tokens(lang.commands.build, { '{source}', '{binary}' }) then @@ -232,6 +242,14 @@ function M.setup(user_config) vim.validate({ user_config = { user_config, { 'table', 'nil' }, true } }) local cfg = vim.tbl_deep_extend('force', vim.deepcopy(M.defaults), user_config or {}) + if not next(cfg.languages) then + error('[cp.nvim] At least one language must be configured') + end + + if not next(cfg.platforms) then + error('[cp.nvim] At least one platform must be configured') + end + vim.validate({ hooks = { cfg.hooks, { 'table' } }, ui = { cfg.ui, { 'table' } }, diff --git a/lua/cp/constants.lua b/lua/cp/constants.lua index 310363f..b19e06b 100644 --- a/lua/cp/constants.lua +++ b/lua/cp/constants.lua @@ -1,7 +1,7 @@ local M = {} M.PLATFORMS = { 'atcoder', 'codeforces', 'cses' } -M.ACTIONS = { 'run', 'panel', 'debug', 'next', 'prev', 'pick', 'cache', 'interact' } +M.ACTIONS = { 'run', 'panel', 'next', 'prev', 'pick', 'cache', 'interact' } M.PLATFORM_DISPLAY_NAMES = { atcoder = 'AtCoder', diff --git a/lua/cp/runner/execute.lua b/lua/cp/runner/execute.lua index bfe0178..a871d6f 100644 --- a/lua/cp/runner/execute.lua +++ b/lua/cp/runner/execute.lua @@ -160,19 +160,21 @@ function M.run(cmd, stdin, timeout_ms, memory_mb) } end -function M.compile_problem() +function M.compile_problem(debug) local state = require('cp.state') local config = require('cp.config').get_config() - local platform = state.get_platform() or '' + local platform = state.get_platform() local language = config.platforms[platform].default_language local eff = config.runtime.effective[platform][language] - local compile_config = eff and eff.commands and eff.commands.build + + local compile_config = (debug and eff.commands.debug) or eff.commands.build if not compile_config then return { success = true, output = nil } end - local substitutions = { source = state.get_source_file(), binary = state.get_binary_file() } + local binary = debug and state.get_debug_file() or state.get_binary_file() + local substitutions = { source = state.get_source_file(), binary = binary } local r = M.compile(compile_config, substitutions) if r.code ~= 0 then diff --git a/lua/cp/runner/run.lua b/lua/cp/runner/run.lua index ab3d8af..c8fcd0c 100644 --- a/lua/cp/runner/run.lua +++ b/lua/cp/runner/run.lua @@ -100,11 +100,12 @@ local function build_command(cmd, substitutions) end ---@param test_case RanTestCase +---@param debug boolean? ---@return { status: "pass"|"fail"|"tle"|"mle", actual: string, actual_highlights: Highlight[], error: string, stderr: string, time_ms: number, code: integer, ok: boolean, signal: string, tled: boolean, mled: boolean, rss_mb: number } -local function run_single_test_case(test_case) +local function run_single_test_case(test_case, debug) local source_file = state.get_source_file() - local binary_file = state.get_binary_file() + local binary_file = debug and state.get_debug_file() or state.get_binary_file() local substitutions = { source = source_file, binary = binary_file } local platform_config = config.platforms[state.get_platform() or ''] @@ -198,15 +199,16 @@ function M.load_test_cases() end ---@param index number +---@param debug boolean? ---@return boolean -function M.run_test_case(index) +function M.run_test_case(index, debug) local tc = panel_state.test_cases[index] if not tc then return false end tc.status = 'running' - local r = run_single_test_case(tc) + local r = run_single_test_case(tc, debug) tc.status = r.status tc.actual = r.actual @@ -225,8 +227,9 @@ function M.run_test_case(index) end ---@param indices? integer[] +---@param debug boolean? ---@return RanTestCase[] -function M.run_all_test_cases(indices) +function M.run_all_test_cases(indices, debug) local to_run = indices if not to_run then to_run = {} @@ -236,7 +239,7 @@ function M.run_all_test_cases(indices) end for _, i in ipairs(to_run) do - M.run_test_case(i) + M.run_test_case(i, debug) end return panel_state.test_cases diff --git a/lua/cp/state.lua b/lua/cp/state.lua index 4a3ff79..caf5044 100644 --- a/lua/cp/state.lua +++ b/lua/cp/state.lua @@ -11,6 +11,7 @@ ---@field input_buf integer ---@field output_win integer ---@field input_win integer +---@field current_test_index integer? ---@class cp.State ---@field get_platform fun(): string? @@ -127,6 +128,12 @@ function M.get_binary_file() return base_name and ('build/%s.run'):format(base_name) or nil end +---@return string? +function M.get_debug_file() + local base_name = M.get_base_name() + return base_name and ('build/%s.dbg'):format(base_name) or nil +end + ---@return string? function M.get_input_file() local base_name = M.get_base_name() diff --git a/lua/cp/ui/panel.lua b/lua/cp/ui/panel.lua index 12093d7..5954ca8 100644 --- a/lua/cp/ui/panel.lua +++ b/lua/cp/ui/panel.lua @@ -228,7 +228,8 @@ function M.ensure_io_view() vim.cmd.vsplit() output_win = vim.api.nvim_get_current_win() - local width = math.floor(vim.o.columns * 0.3) + local config = config_module.get_config() + local width = math.floor(vim.o.columns * (config.ui.run.width or 0.3)) vim.api.nvim_win_set_width(output_win, width) output_buf = utils.create_buffer_with_options() vim.api.nvim_win_set_buf(output_win, output_buf) @@ -243,6 +244,7 @@ function M.ensure_io_view() input_buf = input_buf, output_win = output_win, input_win = input_win, + current_test_index = 1, }) local config = config_module.get_config() @@ -253,6 +255,36 @@ function M.ensure_io_view() if config.hooks and config.hooks.setup_io_input then pcall(config.hooks.setup_io_input, input_buf, state) end + + local function navigate_test(delta) + local io_state = state.get_io_view_state() + if not io_state then + return + end + local test_cases = cache.get_test_cases(platform, contest_id, problem_id) + if not test_cases or #test_cases == 0 then + return + end + local new_index = (io_state.current_test_index or 1) + delta + if new_index < 1 or new_index > #test_cases then + return + end + io_state.current_test_index = new_index + M.run_io_view(new_index) + end + + vim.keymap.set('n', '<c-n>', function() + navigate_test(1) + end, { buffer = output_buf, silent = true, desc = 'Next test' }) + vim.keymap.set('n', '<c-p>', function() + navigate_test(-1) + end, { buffer = output_buf, silent = true, desc = 'Previous test' }) + vim.keymap.set('n', '<c-n>', function() + navigate_test(1) + end, { buffer = input_buf, silent = true, desc = 'Next test' }) + vim.keymap.set('n', '<c-p>', function() + navigate_test(-1) + end, { buffer = input_buf, silent = true, desc = 'Previous test' }) end utils.update_buffer_content(input_buf, {}) @@ -272,7 +304,7 @@ function M.ensure_io_view() vim.api.nvim_set_current_win(solution_win) end -function M.run_io_view(test_index) +function M.run_io_view(test_index, debug) local platform, contest_id, problem_id = state.get_platform(), state.get_contest_id(), state.get_problem_id() if not platform or not contest_id or not problem_id then @@ -332,7 +364,7 @@ function M.run_io_view(test_index) end local execute = require('cp.runner.execute') - local compile_result = execute.compile_problem() + local compile_result = execute.compile_problem(debug) if not compile_result.success then local ansi = require('cp.ui.ansi') local output = compile_result.output or '' @@ -352,7 +384,7 @@ function M.run_io_view(test_index) return end - run.run_all_test_cases(test_indices) + run.run_all_test_cases(test_indices, debug) local run_render = require('cp.runner.run_render') run_render.setup_highlights() @@ -629,9 +661,9 @@ function M.toggle_panel(panel_opts) end local execute = require('cp.runner.execute') - local compile_result = execute.compile_problem() + local compile_result = execute.compile_problem(panel_opts and panel_opts.debug) if compile_result.success then - run.run_all_test_cases() + run.run_all_test_cases(nil, panel_opts and panel_opts.debug) else run.handle_compilation_failure(compile_result.output) end From 9ffc285e16f1f7fb9a880429686532ba088c8d1c Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Thu, 23 Oct 2025 23:45:05 -0400 Subject: [PATCH 043/187] feat: document bdingins --- doc/cp.nvim.txt | 21 +++++++++++++++++++++ lua/cp/config.lua | 18 +++++++++++++++++- lua/cp/ui/panel.lua | 29 +++++++++++++++++------------ 3 files changed, 55 insertions(+), 13 deletions(-) diff --git a/doc/cp.nvim.txt b/doc/cp.nvim.txt index 3ef99be..53c0ed7 100644 --- a/doc/cp.nvim.txt +++ b/doc/cp.nvim.txt @@ -184,6 +184,11 @@ Here's an example configuration with lazy.nvim: debug = false, ui = { ansi = true, + run = { + width = 0.3, + next_test_key = '<c-n>', -- or nil to disable + prev_test_key = '<c-p>', -- or nil to disable + }, panel = { diff_mode = 'vim', max_output_lines = 50, @@ -278,10 +283,20 @@ run CSES problems with Rust using the single schema: Fields: ~ {ansi} (boolean, default: true) Enable ANSI color parsing and highlighting in both I/O view and panel. + {run} (|RunConfig|) I/O view configuration. {panel} (|PanelConfig|) Test panel behavior configuration. {diff} (|DiffConfig|) Diff backend configuration. {picker} (string|nil) 'telescope', 'fzf-lua', or nil. + *RunConfig* + Fields: ~ + {width} (number, default: 0.3) Width of I/O view splits as + fraction of screen (0.0 to 1.0). + {next_test_key} (string|nil, default: '<c-n>') Keymap to navigate + to next test in I/O view. Set to nil to disable. + {prev_test_key} (string|nil, default: '<c-p>') Keymap to navigate + to previous test in I/O view. Set to nil to disable. + *cp.PanelConfig* Fields: ~ {diff_mode} (string, default: "none") Diff backend: "none", @@ -445,6 +460,12 @@ Usage ~ :CP run Run all tests :CP run 3 Run test 3 only +Navigation ~ + +While in the I/O view buffers, use the configured keymaps to cycle through tests: + <c-n> Next test (default, see |RunConfig|.next_test_key) + <c-p> Previous test (default, see |RunConfig|.prev_test_key) + Buffer Customization ~ Use the setup_io_input and setup_io_output hooks (see |cp.Hooks|) to customize diff --git a/lua/cp/config.lua b/lua/cp/config.lua index 26767e7..069cf75 100644 --- a/lua/cp/config.lua +++ b/lua/cp/config.lua @@ -36,6 +36,8 @@ ---@class RunConfig ---@field width number +---@field next_test_key string|nil +---@field prev_test_key string|nil ---@class CpUI ---@field ansi boolean @@ -120,7 +122,7 @@ M.defaults = { filename = nil, ui = { ansi = true, - run = { width = 0.3 }, + run = { width = 0.3, next_test_key = '<c-n>', prev_test_key = '<c-p>' }, panel = { diff_mode = 'none', max_output_lines = 50 }, diff = { git = { @@ -278,6 +280,20 @@ function M.setup(user_config) 'positive integer', }, git = { cfg.ui.diff.git, { 'table' } }, + next_test_key = { + cfg.ui.run.next_test_key, + function(v) + return v == nil or (type(v) == 'string' and #v > 0) + end, + 'nil or non-empty string', + }, + prev_test_key = { + cfg.ui.run.prev_test_key, + function(v) + return v == nil or (type(v) == 'string' and #v > 0) + end, + 'nil or non-empty string', + }, }) for id, lang in pairs(cfg.languages) do diff --git a/lua/cp/ui/panel.lua b/lua/cp/ui/panel.lua index 5954ca8..3b31029 100644 --- a/lua/cp/ui/panel.lua +++ b/lua/cp/ui/panel.lua @@ -273,18 +273,23 @@ function M.ensure_io_view() M.run_io_view(new_index) end - vim.keymap.set('n', '<c-n>', function() - navigate_test(1) - end, { buffer = output_buf, silent = true, desc = 'Next test' }) - vim.keymap.set('n', '<c-p>', function() - navigate_test(-1) - end, { buffer = output_buf, silent = true, desc = 'Previous test' }) - vim.keymap.set('n', '<c-n>', function() - navigate_test(1) - end, { buffer = input_buf, silent = true, desc = 'Next test' }) - vim.keymap.set('n', '<c-p>', function() - navigate_test(-1) - end, { buffer = input_buf, silent = true, desc = 'Previous test' }) + if config.ui.run.next_test_key then + vim.keymap.set('n', config.ui.run.next_test_key, function() + navigate_test(1) + end, { buffer = output_buf, silent = true, desc = 'Next test' }) + vim.keymap.set('n', config.ui.run.next_test_key, function() + navigate_test(1) + end, { buffer = input_buf, silent = true, desc = 'Next test' }) + end + + if config.ui.run.prev_test_key then + vim.keymap.set('n', config.ui.run.prev_test_key, function() + navigate_test(-1) + end, { buffer = output_buf, silent = true, desc = 'Previous test' }) + vim.keymap.set('n', config.ui.run.prev_test_key, function() + navigate_test(-1) + end, { buffer = input_buf, silent = true, desc = 'Previous test' }) + end end utils.update_buffer_content(input_buf, {}) From 82021e3d97d58d0eef78137c5cca61fd56578b2b Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Thu, 23 Oct 2025 23:48:32 -0400 Subject: [PATCH 044/187] fix ci --- lua/cp/commands/init.lua | 1 + lua/cp/ui/panel.lua | 18 +++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/lua/cp/commands/init.lua b/lua/cp/commands/init.lua index ad612a7..0e06437 100644 --- a/lua/cp/commands/init.lua +++ b/lua/cp/commands/init.lua @@ -17,6 +17,7 @@ local actions = constants.ACTIONS ---@field problem_id? string ---@field interactor_cmd? string ---@field test_index? integer +---@field debug? boolean --- Turn raw args into normalized structure to later dispatch ---@param args string[] The raw command-line mode args diff --git a/lua/cp/ui/panel.lua b/lua/cp/ui/panel.lua index 3b31029..018579e 100644 --- a/lua/cp/ui/panel.lua +++ b/lua/cp/ui/panel.lua @@ -247,29 +247,29 @@ function M.ensure_io_view() current_test_index = 1, }) - local config = config_module.get_config() - if config.hooks and config.hooks.setup_io_output then - pcall(config.hooks.setup_io_output, output_buf, state) + local cfg = config_module.get_config() + if cfg.hooks and cfg.hooks.setup_io_output then + pcall(cfg.hooks.setup_io_output, output_buf, state) end - if config.hooks and config.hooks.setup_io_input then - pcall(config.hooks.setup_io_input, input_buf, state) + if cfg.hooks and cfg.hooks.setup_io_input then + pcall(cfg.hooks.setup_io_input, input_buf, state) end local function navigate_test(delta) - local io_state = state.get_io_view_state() - if not io_state then + local io_view_state = state.get_io_view_state() + if not io_view_state then return end local test_cases = cache.get_test_cases(platform, contest_id, problem_id) if not test_cases or #test_cases == 0 then return end - local new_index = (io_state.current_test_index or 1) + delta + local new_index = (io_view_state.current_test_index or 1) + delta if new_index < 1 or new_index > #test_cases then return end - io_state.current_test_index = new_index + io_view_state.current_test_index = new_index M.run_io_view(new_index) end From 64b8b03cca4ec716de7c8c7afe32100763d7a824 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Thu, 23 Oct 2025 23:49:50 -0400 Subject: [PATCH 045/187] fix var name --- lua/cp/ui/panel.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lua/cp/ui/panel.lua b/lua/cp/ui/panel.lua index 018579e..39afdae 100644 --- a/lua/cp/ui/panel.lua +++ b/lua/cp/ui/panel.lua @@ -228,8 +228,8 @@ function M.ensure_io_view() vim.cmd.vsplit() output_win = vim.api.nvim_get_current_win() - local config = config_module.get_config() - local width = math.floor(vim.o.columns * (config.ui.run.width or 0.3)) + local cfg = config_module.get_config() + local width = math.floor(vim.o.columns * (cfg.ui.run.width or 0.3)) vim.api.nvim_win_set_width(output_win, width) output_buf = utils.create_buffer_with_options() vim.api.nvim_win_set_buf(output_win, output_buf) @@ -247,7 +247,6 @@ function M.ensure_io_view() current_test_index = 1, }) - local cfg = config_module.get_config() if cfg.hooks and cfg.hooks.setup_io_output then pcall(cfg.hooks.setup_io_output, output_buf, state) end From 7e2e712b567a43bdc263d8ddc3ec7d1ada378596 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Thu, 23 Oct 2025 23:55:27 -0400 Subject: [PATCH 046/187] fix: rename file --- lua/cp/commands/init.lua | 2 +- lua/cp/setup.lua | 4 ++-- lua/cp/ui/{panel.lua => views.lua} | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename lua/cp/ui/{panel.lua => views.lua} (100%) diff --git a/lua/cp/commands/init.lua b/lua/cp/commands/init.lua index 0e06437..70c07b0 100644 --- a/lua/cp/commands/init.lua +++ b/lua/cp/commands/init.lua @@ -130,7 +130,7 @@ function M.handle_command(opts) restore.restore_from_current_file() elseif cmd.type == 'action' then local setup = require('cp.setup') - local ui = require('cp.ui.panel') + local ui = require('cp.ui.views') if cmd.action == 'interact' then ui.toggle_interactive(cmd.interactor_cmd) diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index d6e2f38..bbad9a4 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -203,7 +203,7 @@ function M.setup_problem(problem_id, language) state.get_problem_id() or '', lang ) - require('cp.ui.panel').ensure_io_view() + require('cp.ui.views').ensure_io_view() end state.set_provisional(nil) return @@ -271,7 +271,7 @@ function M.navigate_problem(direction) local active_panel = state.get_active_panel() if active_panel == 'run' then - require('cp.ui.panel').disable() + require('cp.ui.views').disable() end M.setup_contest(platform, contest_id, problems[new_index].id) diff --git a/lua/cp/ui/panel.lua b/lua/cp/ui/views.lua similarity index 100% rename from lua/cp/ui/panel.lua rename to lua/cp/ui/views.lua From 6f9452c7e195d3b1d3f23d802f4c246ce48f1301 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Thu, 23 Oct 2025 23:57:23 -0400 Subject: [PATCH 047/187] renme --- lua/cp/ui/views.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lua/cp/ui/views.lua b/lua/cp/ui/views.lua index 39afdae..044884a 100644 --- a/lua/cp/ui/views.lua +++ b/lua/cp/ui/views.lua @@ -272,20 +272,20 @@ function M.ensure_io_view() M.run_io_view(new_index) end - if config.ui.run.next_test_key then - vim.keymap.set('n', config.ui.run.next_test_key, function() + if cfg.ui.run.next_test_key then + vim.keymap.set('n', cfg.ui.run.next_test_key, function() navigate_test(1) end, { buffer = output_buf, silent = true, desc = 'Next test' }) - vim.keymap.set('n', config.ui.run.next_test_key, function() + vim.keymap.set('n', cfg.ui.run.next_test_key, function() navigate_test(1) end, { buffer = input_buf, silent = true, desc = 'Next test' }) end - if config.ui.run.prev_test_key then - vim.keymap.set('n', config.ui.run.prev_test_key, function() + if cfg.ui.run.prev_test_key then + vim.keymap.set('n', cfg.ui.run.prev_test_key, function() navigate_test(-1) end, { buffer = output_buf, silent = true, desc = 'Previous test' }) - vim.keymap.set('n', config.ui.run.prev_test_key, function() + vim.keymap.set('n', cfg.ui.run.prev_test_key, function() navigate_test(-1) end, { buffer = input_buf, silent = true, desc = 'Previous test' }) end From 249e84eb5a624b5a1e109f67d0309e519bd8afe6 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 00:26:14 -0400 Subject: [PATCH 048/187] feat: customization --- doc/cp.nvim.txt | 70 ++++++++++++++++++++++++++++ lua/cp/config.lua | 33 +++++++++++++- lua/cp/helpers.lua | 52 +++++++++++++++++++++ lua/cp/setup.lua | 2 +- lua/cp/ui/views.lua | 108 +++++++++++++++----------------------------- 5 files changed, 192 insertions(+), 73 deletions(-) diff --git a/doc/cp.nvim.txt b/doc/cp.nvim.txt index 53c0ed7..0dfd9dd 100644 --- a/doc/cp.nvim.txt +++ b/doc/cp.nvim.txt @@ -296,6 +296,8 @@ run CSES problems with Rust using the single schema: to next test in I/O view. Set to nil to disable. {prev_test_key} (string|nil, default: '<c-p>') Keymap to navigate to previous test in I/O view. Set to nil to disable. + {format_verdict} (|VerdictFormatter|, default: nil) Custom verdict line + formatter. See |cp-verdict-format|. *cp.PanelConfig* Fields: ~ @@ -472,6 +474,74 @@ Use the setup_io_input and setup_io_output hooks (see |cp.Hooks|) to customize buffer appearance. By default, line numbers and columns are removed via helpers.clearcol (see |cp-helpers|). +============================================================================== +VERDICT FORMATTING *cp-verdict-format* + +Customize how verdict summaries appear in the I/O view using format_verdict. + +Configuration ~ + +Set ui.run.format_verdict to a function that formats verdict data: >lua + format_verdict = function(data) + return { line = "...", highlights = {...} } + end +< +Format Function ~ + *VerdictFormatter* +Input: |VerdictFormatData| table with test results +Output: |VerdictFormatResult| table with formatted line and optional highlights + + *VerdictFormatData* + {index} (integer) Test case number + {status} (table) { text: string, highlight_group: string } + {time_ms} (number) Execution time in milliseconds + {time_limit_ms} (number) Time limit in milliseconds + {memory_mb} (number) Peak memory usage in megabytes + {memory_limit_mb} (number) Memory limit in megabytes + {exit_code} (integer) Process exit code + {signal} (string|nil) Signal name for crashes (e.g. "SIGSEGV") + + *VerdictFormatResult* + {line} (string) The formatted verdict line + {highlights} (table[], optional) Highlight regions: + {col_start} (integer) Start column (0-indexed) + {col_end} (integer) End column (exclusive) + {group} (string) Highlight group name + +Examples ~ + +Minimal format: >lua + format_verdict = function(data) + return { + line = string.format("#%d %s", data.index, data.status.text) + } + end +< +With custom alignment using helpers: >lua + local helpers = require('cp').helpers + format_verdict = function(data) + local status = helpers.pad_right(data.status.text, 3) + local time = string.format("%.1fms", data.time_ms) + return { line = string.format("Test %d: %s %s", data.index, status, time) } + end +< +With highlighting: >lua + format_verdict = function(data) + local line = string.format("%d: %s", data.index, data.status.text) + return { + line = line, + highlights = { + { + col_start = #tostring(data.index) + 2, + col_end = #line, + group = data.status.highlight_group + } + } + } + end +< +See |cp-helpers| for alignment functions: pad_right, pad_left, center. + ============================================================================== PICKER INTEGRATION *cp-picker* diff --git a/lua/cp/config.lua b/lua/cp/config.lua index 069cf75..8ba1517 100644 --- a/lua/cp/config.lua +++ b/lua/cp/config.lua @@ -34,10 +34,32 @@ ---@field setup_io_input? fun(bufnr: integer, state: cp.State) ---@field setup_io_output? fun(bufnr: integer, state: cp.State) +---@class VerdictFormatData +---@field index integer +---@field status { text: string, highlight_group: string } +---@field time_ms number +---@field time_limit_ms number +---@field memory_mb number +---@field memory_limit_mb number +---@field exit_code integer +---@field signal string|nil + +---@class VerdictHighlight +---@field col_start integer +---@field col_end integer +---@field group string + +---@class VerdictFormatResult +---@field line string +---@field highlights? VerdictHighlight[] + +---@alias VerdictFormatter fun(data: VerdictFormatData): VerdictFormatResult + ---@class RunConfig ---@field width number ---@field next_test_key string|nil ---@field prev_test_key string|nil +---@field format_verdict VerdictFormatter|nil ---@class CpUI ---@field ansi boolean @@ -122,7 +144,12 @@ M.defaults = { filename = nil, ui = { ansi = true, - run = { width = 0.3, next_test_key = '<c-n>', prev_test_key = '<c-p>' }, + run = { + width = 0.3, + next_test_key = '<c-n>', + prev_test_key = '<c-p>', + format_verdict = helpers.default_verdict_formatter, + }, panel = { diff_mode = 'none', max_output_lines = 50 }, diff = { git = { @@ -294,6 +321,10 @@ function M.setup(user_config) end, 'nil or non-empty string', }, + format_verdict = { + cfg.ui.run.format_verdict, + 'function', + }, }) for id, lang in pairs(cfg.languages) do diff --git a/lua/cp/helpers.lua b/lua/cp/helpers.lua index 408ad0a..e31b6f9 100644 --- a/lua/cp/helpers.lua +++ b/lua/cp/helpers.lua @@ -10,6 +10,10 @@ function M.clearcol(bufnr) end end +---Pad text on the right (left-align text within width) +---@param text string +---@param width integer +---@return string function M.pad_right(text, width) local pad = width - #text if pad <= 0 then @@ -18,6 +22,10 @@ function M.pad_right(text, width) return text .. string.rep(' ', pad) end +---Pad text on the left (right-align text within width) +---@param text string +---@param width integer +---@return string function M.pad_left(text, width) local pad = width - #text if pad <= 0 then @@ -26,6 +34,10 @@ function M.pad_left(text, width) return string.rep(' ', pad) .. text end +---Center text within width +---@param text string +---@param width integer +---@return string function M.center(text, width) local pad = width - #text if pad <= 0 then @@ -35,4 +47,44 @@ function M.center(text, width) return string.rep(' ', left) .. text .. string.rep(' ', pad - left) end +---Default verdict formatter for I/O view +---@param data VerdictFormatData +---@return VerdictFormatResult +function M.default_verdict_formatter(data) + local time_data = string.format('%.2f', data.time_ms) .. '/' .. data.time_limit_ms + local mem_data = string.format('%.0f', data.memory_mb) + .. '/' + .. string.format('%.0f', data.memory_limit_mb) + local exit_str = data.signal and string.format('%d (%s)', data.exit_code, data.signal) + or tostring(data.exit_code) + + local test_num_part = 'Test ' .. data.index .. ':' + local status_part = M.pad_right(data.status.text, 3) + local time_part = time_data .. ' ms' + local mem_part = mem_data .. ' MB' + local exit_part = 'exit: ' .. exit_str + + local line = test_num_part + .. ' ' + .. status_part + .. ' | ' + .. time_part + .. ' | ' + .. mem_part + .. ' | ' + .. exit_part + + local highlights = {} + local status_pos = line:find(data.status.text, 1, true) + if status_pos then + table.insert(highlights, { + col_start = status_pos - 1, + col_end = status_pos - 1 + #data.status.text, + group = data.status.highlight_group, + }) + end + + return { line = line, highlights = highlights } +end + return M diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index bbad9a4..50d603d 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -230,7 +230,7 @@ function M.setup_problem(problem_id, language) state.get_problem_id() or '', lang ) - require('cp.ui.panel').ensure_io_view() + require('cp.ui.views').ensure_io_view() end) end diff --git a/lua/cp/ui/views.lua b/lua/cp/ui/views.lua index 044884a..130da3b 100644 --- a/lua/cp/ui/views.lua +++ b/lua/cp/ui/views.lua @@ -231,12 +231,12 @@ function M.ensure_io_view() local cfg = config_module.get_config() local width = math.floor(vim.o.columns * (cfg.ui.run.width or 0.3)) vim.api.nvim_win_set_width(output_win, width) - output_buf = utils.create_buffer_with_options() + output_buf = utils.create_buffer_with_options('cpout') vim.api.nvim_win_set_buf(output_win, output_buf) vim.cmd.split() input_win = vim.api.nvim_get_current_win() - input_buf = utils.create_buffer_with_options() + input_buf = utils.create_buffer_with_options('cpin') vim.api.nvim_win_set_buf(input_win, input_buf) state.set_io_view_state({ @@ -395,9 +395,10 @@ function M.run_io_view(test_index, debug) local input_lines = {} local output_lines = {} - local verdict_data = {} + local verdict_lines = {} + local verdict_highlights = {} - local widths = { test_num = 0, status = 0, time = 0, memory = 0, exit = 0 } + local formatter = config.ui.run.format_verdict for _, idx in ipairs(test_indices) do local tc = test_state.test_cases[idx] @@ -413,35 +414,32 @@ function M.run_io_view(test_index, debug) local status = run_render.get_status_info(tc) - local time_actual = tc.time_ms and string.format('%.2f', tc.time_ms) or '—' - local time_limit = test_state.constraints and tostring(test_state.constraints.timeout_ms) - or '—' - local time_data = time_actual .. '/' .. time_limit - - local mem_actual = tc.rss_mb and string.format('%.0f', tc.rss_mb) or '—' - local mem_limit = test_state.constraints - and string.format('%.0f', test_state.constraints.memory_mb) - or '—' - local mem_data = mem_actual .. '/' .. mem_limit - - local exit_code = tc.code or 0 - local signal_name = exit_code >= 128 and require('cp.constants').signal_codes[exit_code] or nil - local exit_str = signal_name and string.format('%d (%s)', exit_code, signal_name) - or tostring(exit_code) - - widths.test_num = math.max(widths.test_num, #('Test ' .. idx .. ':')) - widths.status = math.max(widths.status, #status.text) - widths.time = math.max(widths.time, #(time_data .. ' ms')) - widths.memory = math.max(widths.memory, #(mem_data .. ' MB')) - widths.exit = math.max(widths.exit, #('exit: ' .. exit_str)) - - table.insert(verdict_data, { - idx = idx, + ---@type VerdictFormatData + local format_data = { + index = idx, status = status, - time_data = time_data, - mem_data = mem_data, - exit_str = exit_str, - }) + time_ms = tc.time_ms or 0, + time_limit_ms = test_state.constraints and test_state.constraints.timeout_ms or 0, + memory_mb = tc.rss_mb or 0, + memory_limit_mb = test_state.constraints and test_state.constraints.memory_mb or 0, + exit_code = tc.code or 0, + signal = (tc.code and tc.code >= 128) and require('cp.constants').signal_codes[tc.code] + or nil, + } + + local result = formatter(format_data) + table.insert(verdict_lines, result.line) + + if result.highlights then + for _, hl in ipairs(result.highlights) do + table.insert(verdict_highlights, { + line_offset = #verdict_lines - 1, + col_start = hl.col_start, + col_end = hl.col_end, + group = hl.group, + }) + end + end for _, line in ipairs(vim.split(tc.input, '\n')) do table.insert(input_lines, line) @@ -451,35 +449,6 @@ function M.run_io_view(test_index, debug) end end - local verdict_lines = {} - local verdict_highlights = {} - for _, vd in ipairs(verdict_data) do - local test_num_part = helpers.pad_right('Test ' .. vd.idx .. ':', widths.test_num) - local status_part = helpers.pad_right(vd.status.text, widths.status) - local time_part = helpers.pad_right(vd.time_data, widths.time - 3) .. ' ms' - local mem_part = helpers.pad_right(vd.mem_data, widths.memory - 3) .. ' MB' - local exit_part = helpers.pad_right('exit: ' .. vd.exit_str, widths.exit) - - local verdict_line = test_num_part - .. ' ' - .. status_part - .. ' | ' - .. time_part - .. ' | ' - .. mem_part - .. ' | ' - .. exit_part - table.insert(verdict_lines, verdict_line) - - local status_pos = verdict_line:find(vd.status.text, 1, true) - if status_pos then - table.insert(verdict_highlights, { - status = vd.status, - verdict_line = verdict_line, - }) - end - end - if #output_lines > 0 and #verdict_lines > 0 then table.insert(output_lines, '') end @@ -490,16 +459,13 @@ function M.run_io_view(test_index, debug) end local final_highlights = {} - for i, vh in ipairs(verdict_highlights) do - local status_pos = vh.verdict_line:find(vh.status.text, 1, true) - if status_pos then - table.insert(final_highlights, { - line = verdict_start + i - 1, - col_start = status_pos - 1, - col_end = status_pos - 1 + #vh.status.text, - highlight_group = vh.status.highlight_group, - }) - end + for _, vh in ipairs(verdict_highlights) do + table.insert(final_highlights, { + line = verdict_start + vh.line_offset, + col_start = vh.col_start, + col_end = vh.col_end, + highlight_group = vh.group, + }) end utils.update_buffer_content(io_state.input_buf, input_lines, nil, nil) From f715075dbecb2345828b83c2c4660fcf52f90526 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 00:34:42 -0400 Subject: [PATCH 049/187] fix types --- lua/cp/config.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/cp/config.lua b/lua/cp/config.lua index 8ba1517..1f926b5 100644 --- a/lua/cp/config.lua +++ b/lua/cp/config.lua @@ -59,7 +59,7 @@ ---@field width number ---@field next_test_key string|nil ---@field prev_test_key string|nil ----@field format_verdict VerdictFormatter|nil +---@field format_verdict VerdictFormatter ---@class CpUI ---@field ansi boolean From ce12ab0e1a5e57d8a47d7245e5544519151984bb Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 00:37:27 -0400 Subject: [PATCH 050/187] minimize docs --- doc/cp.nvim.txt | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/doc/cp.nvim.txt b/doc/cp.nvim.txt index 0dfd9dd..27cf18e 100644 --- a/doc/cp.nvim.txt +++ b/doc/cp.nvim.txt @@ -517,29 +517,6 @@ Minimal format: >lua } end < -With custom alignment using helpers: >lua - local helpers = require('cp').helpers - format_verdict = function(data) - local status = helpers.pad_right(data.status.text, 3) - local time = string.format("%.1fms", data.time_ms) - return { line = string.format("Test %d: %s %s", data.index, status, time) } - end -< -With highlighting: >lua - format_verdict = function(data) - local line = string.format("%d: %s", data.index, data.status.text) - return { - line = line, - highlights = { - { - col_start = #tostring(data.index) + 2, - col_end = #line, - group = data.status.highlight_group - } - } - } - end -< See |cp-helpers| for alignment functions: pad_right, pad_left, center. ============================================================================== From bd30fb626c88fa0c31ea60f5775e1377885ddce9 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 01:11:19 -0400 Subject: [PATCH 051/187] feat: start lang refactor --- doc/cp.nvim.txt | 109 +++++++++++++++++++++++++++++------ lua/cp/commands/init.lua | 41 +++++++++---- lua/cp/commands/picker.lua | 5 +- lua/cp/config.lua | 44 ++++++++++++++ lua/cp/pickers/fzf_lua.lua | 15 +++-- lua/cp/pickers/telescope.lua | 18 +++--- lua/cp/setup.lua | 42 +++++++++++++- 7 files changed, 229 insertions(+), 45 deletions(-) diff --git a/doc/cp.nvim.txt b/doc/cp.nvim.txt index 27cf18e..c8b17ce 100644 --- a/doc/cp.nvim.txt +++ b/doc/cp.nvim.txt @@ -25,18 +25,13 @@ COMMANDS *cp-commands* cp.nvim uses a single :CP command with intelligent argument parsing: Setup Commands ~ - :CP {platform} {contest_id} + :CP {platform} {contest_id} [--lang {language}] Full setup: set platform and load contest metadata. Scrapes test cases and creates source file. - Example: > + --lang: Use specific language (default: platform default) + Examples: > :CP codeforces 1933 -< - :CP {platform} {contest_id} - Contest setup: set platform, load contest metadata, - and scrape all test cases in the contest. - Opens the first problem after completion. - Example: > - :CP atcoder abc324 + :CP codeforces 1933 --lang python < View Commands ~ :CP run [--debug] [n] @@ -59,8 +54,14 @@ COMMANDS *cp-commands* :CP panel --debug 3 " Test 3, debug build < - :CP pick Launch configured picker for interactive + :CP pick [--lang {language}] + Launch configured picker for interactive platform/contest selection. + --lang: Pre-select language for chosen contest. + Example: > + :CP pick + :CP pick --lang python +< :CP interact [script] Open an interactive terminal for the current problem. @@ -70,15 +71,36 @@ COMMANDS *cp-commands* file. Only valid for interactive problems. Navigation Commands ~ - :CP next Navigate to next problem in current contest. + :CP next [--lang {language}] + Navigate to next problem in current contest. Stops at last problem (no wrapping). - - - :CP prev Navigate to previous problem in current contest. + --lang: Use specific language for next problem. + By default, preserves current file's language if + enabled for the new problem, otherwise uses platform + default. + Examples: > + :CP next + :CP next --lang python +< + :CP prev [--lang {language}] + Navigate to previous problem in current contest. Stops at first problem (no wrapping). - - :CP {problem_id} Jump to problem {problem_id} in a contest. + --lang: Use specific language for previous problem. + By default, preserves current file's language if + enabled for the new problem, otherwise uses platform + default. + Examples: > + :CP prev + :CP prev --lang cpp +< + :CP {problem_id} [--lang {language}] + Jump to problem {problem_id} in a contest. Requires that a contest has already been set up. + --lang: Use specific language for this problem. + Examples: > + :CP B + :CP C --lang python +< State Restoration ~ :CP Restore state from current file. @@ -357,6 +379,49 @@ run CSES problems with Rust using the single schema: } < +============================================================================== +LANGUAGE SELECTION *cp-lang-selection* + +cp.nvim supports multiple languages per problem. Each platform enables specific +languages and has a default. You can override the language for any setup or +navigation command using the --lang flag. + +Language Selection Behavior ~ + +When setting up or navigating to a problem: + +1. Explicit --lang flag takes highest priority +2. If no --lang flag, tries to preserve current file's language + (only if that language is enabled for the new problem) +3. Falls back to platform's default language + +Multiple Solution Files ~ + +Different languages create different solution files. For example: + 1848a.cc (C++ solution) + 1848a.py (Python solution) + +Both files can exist simultaneously with their own state. Switching between +languages means switching between different files. + +Examples ~ +> + :CP codeforces 1848 " Use platform default (likely C++) + :CP codeforces 1848 --lang python " Use Python explicitly + + " In 1848a.cc (C++ file): + :CP next " Next problem tries to use C++ + :CP next --lang python " Next problem uses Python + + " In 1848a.py (Python file): + :CP next " Next problem tries to use Python + :CP next --lang cpp " Next problem switches to C++ +< +Language Validation ~ + +If you request a language that isn't enabled for a platform, cp.nvim will show +a helpful error message listing available languages for that platform. + ============================================================================== WORKFLOW *cp-workflow* @@ -374,6 +439,7 @@ https://atcoder.jp/contests/{contest_id}/tasks/{contest_id}_{problem_id} Usage examples: > :CP atcoder abc324 " Set up atcoder.jp/contests/abc324 + :CP atcoder abc324 --lang python " Set up with Python instead of default Codeforces ~ *cp-codeforces* @@ -381,6 +447,7 @@ URL format: https://codeforces.com/contest/{contest_id}/problem/{problem_id} Usage examples: > :CP codeforces 1934 " Set up codeforces.com/contest/1934 + :CP codeforces 1934 --lang cpp " Set up with C++ CSES ~ *cp-cses* @@ -404,7 +471,7 @@ Example: Setting up and solving AtCoder contest ABC324 3. Code your solution, then test: > :CP run -< View test verdicts in I/O splits. For detailed analysis: +< View test verdicts in I/O splits. For detailed analysis: > :CP panel < Navigate tests with <c-n>/<c-p>, exit with q @@ -414,12 +481,16 @@ Example: Setting up and solving AtCoder contest ABC324 5. Continue solving problems with :CP next/:CP prev navigation -6. Switch to another file (e.g. previous contest): > +6. Try a different language for a problem: > + :CP C --lang python +< Opens problem C with Python instead of C++ + +7. Switch to another file (e.g. previous contest): > :e ~/contests/abc323/a.cpp :CP < Automatically restores abc323 contest context -7. Submit solutions on AtCoder website +8. Submit solutions on AtCoder website ============================================================================== I/O VIEW *cp-io-view* diff --git a/lua/cp/commands/init.lua b/lua/cp/commands/init.lua index 70c07b0..fa4f658 100644 --- a/lua/cp/commands/init.lua +++ b/lua/cp/commands/init.lua @@ -18,6 +18,7 @@ local actions = constants.ACTIONS ---@field interactor_cmd? string ---@field test_index? integer ---@field debug? boolean +---@field language? string --- Turn raw args into normalized structure to later dispatch ---@param args string[] The raw command-line mode args @@ -79,7 +80,16 @@ local function parse_command(args) return { type = 'action', action = first, test_index = test_index, debug = debug } else - return { type = 'action', action = first } + local language = nil + if #args >= 3 and args[2] == '--lang' then + language = args[3] + elseif #args >= 2 and args[2] ~= nil and args[2]:sub(1, 2) ~= '--' then + return { + type = 'error', + message = ("Unknown argument '%s' for action '%s'"):format(args[2], first), + } + end + return { type = 'action', action = first, language = language } end end @@ -95,13 +105,18 @@ local function parse_command(args) platform = first, contest = args[2], } - elseif #args == 3 then + elseif #args == 4 and args[3] == '--lang' then return { - type = 'error', - message = 'Setup contests with :CP <platform> <contest_id>.', + type = 'contest_setup', + platform = first, + contest = args[2], + language = args[4], } else - return { type = 'error', message = 'Too many arguments' } + return { + type = 'error', + message = 'Invalid arguments. Usage: :CP <platform> <contest> [--lang <language>]', + } end end @@ -110,6 +125,12 @@ local function parse_command(args) type = 'problem_jump', problem_id = first, } + elseif #args == 3 and args[2] == '--lang' then + return { + type = 'problem_jump', + problem_id = first, + language = args[3], + } end return { type = 'error', message = 'Unknown command or no contest context.' } @@ -139,12 +160,12 @@ function M.handle_command(opts) elseif cmd.action == 'panel' then ui.toggle_panel({ debug = cmd.debug, test_index = cmd.test_index }) elseif cmd.action == 'next' then - setup.navigate_problem(1) + setup.navigate_problem(1, cmd.language) elseif cmd.action == 'prev' then - setup.navigate_problem(-1) + setup.navigate_problem(-1, cmd.language) elseif cmd.action == 'pick' then local picker = require('cp.commands.picker') - picker.handle_pick_action() + picker.handle_pick_action(cmd.language) end elseif cmd.type == 'problem_jump' then local platform = state.get_platform() @@ -173,13 +194,13 @@ function M.handle_command(opts) end local setup = require('cp.setup') - setup.setup_contest(platform, contest_id, problem_id) + setup.setup_contest(platform, contest_id, problem_id, cmd.language) elseif cmd.type == 'cache' then local cache_commands = require('cp.commands.cache') cache_commands.handle_cache_command(cmd) elseif cmd.type == 'contest_setup' then local setup = require('cp.setup') - setup.setup_contest(cmd.platform, cmd.contest, nil) + setup.setup_contest(cmd.platform, cmd.contest, nil, cmd.language) return end end diff --git a/lua/cp/commands/picker.lua b/lua/cp/commands/picker.lua index a733b58..08cbcd9 100644 --- a/lua/cp/commands/picker.lua +++ b/lua/cp/commands/picker.lua @@ -4,8 +4,9 @@ local config_module = require('cp.config') local logger = require('cp.log') --- Dispatch `:CP pick` to appropriate picker +---@param language? string ---@return nil -function M.handle_pick_action() +function M.handle_pick_action(language) local config = config_module.get_config() if not (config.ui and config.ui.picker) then @@ -53,7 +54,7 @@ function M.handle_pick_action() picker = fzf_picker end - picker.pick() + picker.pick(language) end return M diff --git a/lua/cp/config.lua b/lua/cp/config.lua index 1f926b5..4ae06d1 100644 --- a/lua/cp/config.lua +++ b/lua/cp/config.lua @@ -351,6 +351,50 @@ function M.get_config() return current_config or M.defaults end +---Validate and get effective language config for a platform +---@param platform_id string +---@param language_id string +---@return { valid: boolean, effective?: CpLanguage, extension?: string, error?: string } +function M.get_language_for_platform(platform_id, language_id) + local cfg = M.get_config() + + if not cfg.platforms[platform_id] then + return { valid = false, error = string.format("Unknown platform '%s'", platform_id) } + end + + if not cfg.languages[language_id] then + return { valid = false, error = string.format("Unknown language '%s'", language_id) } + end + + local platform = cfg.platforms[platform_id] + if not vim.tbl_contains(platform.enabled_languages, language_id) then + local available = table.concat(platform.enabled_languages, ', ') + return { + valid = false, + error = string.format( + "Language '%s' not enabled for %s. Available: %s", + language_id, + platform_id, + available + ), + } + end + + local effective = cfg.runtime.effective[platform_id][language_id] + if not effective then + return { + valid = false, + error = string.format('No effective config for %s/%s', platform_id, language_id), + } + end + + return { + valid = true, + effective = effective, + extension = effective.extension, + } +end + ---@param contest_id string ---@param problem_id? string ---@return string diff --git a/lua/cp/pickers/fzf_lua.lua b/lua/cp/pickers/fzf_lua.lua index 6735f54..d1af5d2 100644 --- a/lua/cp/pickers/fzf_lua.lua +++ b/lua/cp/pickers/fzf_lua.lua @@ -2,7 +2,7 @@ local picker_utils = require('cp.pickers') local M = {} -local function contest_picker(platform, refresh) +local function contest_picker(platform, refresh, language) local constants = require('cp.constants') local platform_display_name = constants.PLATFORM_DISPLAY_NAMES[platform] local fzf = require('fzf-lua') @@ -42,19 +42,24 @@ local function contest_picker(platform, refresh) if contest then local cp = require('cp') - cp.handle_command({ fargs = { platform, contest.id } }) + local fargs = { platform, contest.id } + if language then + table.insert(fargs, '--lang') + table.insert(fargs, language) + end + cp.handle_command({ fargs = fargs }) end end, ['ctrl-r'] = function() local cache = require('cp.cache') cache.clear_contest_list(platform) - contest_picker(platform, true) + contest_picker(platform, true, language) end, }, }) end -function M.pick() +function M.pick(language) local fzf = require('fzf-lua') local platforms = picker_utils.get_platforms() local entries = vim.tbl_map(function(platform) @@ -79,7 +84,7 @@ function M.pick() end if platform then - contest_picker(platform.id) + contest_picker(platform.id, false, language) end end, }, diff --git a/lua/cp/pickers/telescope.lua b/lua/cp/pickers/telescope.lua index 9b3c0db..0a7a676 100644 --- a/lua/cp/pickers/telescope.lua +++ b/lua/cp/pickers/telescope.lua @@ -8,7 +8,7 @@ local picker_utils = require('cp.pickers') local M = {} -local function contest_picker(opts, platform, refresh) +local function contest_picker(opts, platform, refresh, language) local constants = require('cp.constants') local platform_display_name = constants.PLATFORM_DISPLAY_NAMES[platform] local contests = picker_utils.get_platform_contests(platform, refresh) @@ -43,13 +43,18 @@ local function contest_picker(opts, platform, refresh) if selection then local cp = require('cp') - cp.handle_command({ fargs = { platform, selection.value.id } }) + local fargs = { platform, selection.value.id } + if language then + table.insert(fargs, '--lang') + table.insert(fargs, language) + end + cp.handle_command({ fargs = fargs }) end end) map('i', '<c-r>', function() actions.close(prompt_bufnr) - contest_picker(opts, platform, true) + contest_picker(opts, platform, true, language) end) return true @@ -58,9 +63,8 @@ local function contest_picker(opts, platform, refresh) :find() end -function M.pick(opts) - opts = opts or {} - +function M.pick(language) + local opts = {} local platforms = picker_utils.get_platforms() pickers @@ -83,7 +87,7 @@ function M.pick(opts) actions.close(prompt_bufnr) if selection then - contest_picker(opts, selection.value.id) + contest_picker(opts, selection.value.id, false, language) end end) return true diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index 50d603d..6129614 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -8,6 +8,18 @@ local logger = require('cp.log') local scraper = require('cp.scraper') local state = require('cp.state') +---Get the language of the current file from cache +---@return string|nil +local function get_current_file_language() + local current_file = vim.fn.expand('%:p') + if current_file == '' then + return nil + end + cache.load() + local file_state = cache.get_file_state(current_file) + return file_state and file_state.language or nil +end + ---@class TestCaseLite ---@field input string ---@field expected string @@ -86,6 +98,14 @@ function M.setup_contest(platform, contest_id, problem_id, language) state.set_platform(platform) state.set_contest_id(contest_id) + if language then + local lang_result = config_module.get_language_for_platform(platform, language) + if not lang_result.valid then + logger.log(lang_result.error, vim.log.levels.ERROR) + return + end + end + local is_new_contest = old_platform ~= platform and old_contest_id ~= contest_id cache.load() @@ -173,6 +193,15 @@ function M.setup_problem(problem_id, language) local config = config_module.get_config() local lang = language or (config.platforms[platform] and config.platforms[platform].default_language) + + if language then + local lang_result = config_module.get_language_for_platform(platform, language) + if not lang_result.valid then + logger.log(lang_result.error, vim.log.levels.ERROR) + return + end + end + local source_file = state.get_source_file(lang) if not source_file then return @@ -235,7 +264,8 @@ function M.setup_problem(problem_id, language) end ---@param direction integer -function M.navigate_problem(direction) +---@param language? string +function M.navigate_problem(direction, language) if direction == 0 then return end @@ -274,7 +304,15 @@ function M.navigate_problem(direction) require('cp.ui.views').disable() end - M.setup_contest(platform, contest_id, problems[new_index].id) + local lang = language or get_current_file_language() + if lang then + local lang_result = config_module.get_language_for_platform(platform, lang) + if not lang_result.valid then + lang = nil + end + end + + M.setup_contest(platform, contest_id, problems[new_index].id, lang) end return M From 48d4c6f1133793cafdd4ce897fba100734347541 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 01:21:16 -0400 Subject: [PATCH 052/187] feat: language --- lua/cp/runner/execute.lua | 2 +- lua/cp/runner/run.lua | 2 +- lua/cp/setup.lua | 2 ++ lua/cp/state.lua | 15 ++++++++++++++- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lua/cp/runner/execute.lua b/lua/cp/runner/execute.lua index a871d6f..8f004e5 100644 --- a/lua/cp/runner/execute.lua +++ b/lua/cp/runner/execute.lua @@ -164,7 +164,7 @@ function M.compile_problem(debug) local state = require('cp.state') local config = require('cp.config').get_config() local platform = state.get_platform() - local language = config.platforms[platform].default_language + local language = state.get_language() or config.platforms[platform].default_language local eff = config.runtime.effective[platform][language] local compile_config = (debug and eff.commands.debug) or eff.commands.build diff --git a/lua/cp/runner/run.lua b/lua/cp/runner/run.lua index c8fcd0c..eaec30b 100644 --- a/lua/cp/runner/run.lua +++ b/lua/cp/runner/run.lua @@ -109,7 +109,7 @@ local function run_single_test_case(test_case, debug) local substitutions = { source = source_file, binary = binary_file } local platform_config = config.platforms[state.get_platform() or ''] - local language = platform_config.default_language + local language = state.get_language() or platform_config.default_language local eff = config.runtime.effective[state.get_platform() or ''][language] local run_template = eff and eff.commands and eff.commands.run or {} local cmd = build_command(run_template, substitutions) diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index 6129614..20f852a 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -202,6 +202,8 @@ function M.setup_problem(problem_id, language) end end + state.set_language(lang) + local source_file = state.get_source_file(lang) if not source_file then return diff --git a/lua/cp/state.lua b/lua/cp/state.lua index caf5044..621b184 100644 --- a/lua/cp/state.lua +++ b/lua/cp/state.lua @@ -20,6 +20,8 @@ ---@field set_contest_id fun(contest_id: string) ---@field get_problem_id fun(): string? ---@field set_problem_id fun(problem_id: string) +---@field get_language fun(): string? +---@field set_language fun(language: string) ---@field get_active_panel fun(): string? ---@field set_active_panel fun(panel: string?) ---@field get_base_name fun(): string? @@ -42,6 +44,7 @@ local state = { platform = nil, contest_id = nil, problem_id = nil, + language = nil, test_cases = nil, saved_session = nil, active_panel = nil, @@ -80,6 +83,16 @@ function M.set_problem_id(problem_id) state.problem_id = problem_id end +---@return string? +function M.get_language() + return state.language +end + +---@param language string +function M.set_language(language) + state.language = language +end + ---@return string? function M.get_base_name() local platform, contest_id, problem_id = M.get_platform(), M.get_contest_id(), M.get_problem_id() @@ -112,7 +125,7 @@ function M.get_source_file(language) return nil end - local target_language = language or platform_cfg.default_language + local target_language = language or state.language or platform_cfg.default_language local eff = config.runtime.effective[plat] and config.runtime.effective[plat][target_language] or nil if not eff or not eff.extension then From c48cf384a48c4ca454ffa493411f21e29c668f3d Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 01:21:54 -0400 Subject: [PATCH 053/187] feat: error on invalid language --- lua/cp/setup.lua | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index 20f852a..e6f9d21 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -306,8 +306,16 @@ function M.navigate_problem(direction, language) require('cp.ui.views').disable() end + if language then + local lang_result = config_module.get_language_for_platform(platform, language) + if not lang_result.valid then + logger.log(lang_result.error, vim.log.levels.ERROR) + return + end + end + local lang = language or get_current_file_language() - if lang then + if lang and not language then local lang_result = config_module.get_language_for_platform(platform, lang) if not lang_result.valid then lang = nil From f52244c534c7bef31e39b04f5e0e48760239ca89 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 01:32:48 -0400 Subject: [PATCH 054/187] better errors --- lua/cp/config.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lua/cp/config.lua b/lua/cp/config.lua index 4ae06d1..46b13b4 100644 --- a/lua/cp/config.lua +++ b/lua/cp/config.lua @@ -362,17 +362,22 @@ function M.get_language_for_platform(platform_id, language_id) return { valid = false, error = string.format("Unknown platform '%s'", platform_id) } end + local platform = cfg.platforms[platform_id] + if not cfg.languages[language_id] then - return { valid = false, error = string.format("Unknown language '%s'", language_id) } + local available = table.concat(platform.enabled_languages, ', ') + return { + valid = false, + error = string.format("Unknown language '%s'. Available: [%s]", language_id, available), + } end - local platform = cfg.platforms[platform_id] if not vim.tbl_contains(platform.enabled_languages, language_id) then local available = table.concat(platform.enabled_languages, ', ') return { valid = false, error = string.format( - "Language '%s' not enabled for %s. Available: %s", + "Language '%s' not enabled for %s. Available: [%s]", language_id, platform_id, available From 9d848eba225acc509289555be6894a3583d1631e Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 01:44:06 -0400 Subject: [PATCH 055/187] feat: improve autocomplete --- lua/cp/cache.lua | 20 +++++++++ lua/cp/commands/init.lua | 33 +++++++++++--- plugin/cp.lua | 93 ++++++++++++++++++++++++++++++---------- 3 files changed, 119 insertions(+), 27 deletions(-) diff --git a/lua/cp/cache.lua b/lua/cp/cache.lua index 5c56ef8..86d806f 100644 --- a/lua/cp/cache.lua +++ b/lua/cp/cache.lua @@ -92,6 +92,26 @@ function M.get_contest_data(platform, contest_id) return cache_data[platform][contest_id] end +---Get all cached contest IDs for a platform +---@param platform string +---@return string[] +function M.get_cached_contest_ids(platform) + vim.validate({ + platform = { platform, 'string' }, + }) + + if not cache_data[platform] then + return {} + end + + local contest_ids = {} + for contest_id, _ in pairs(cache_data[platform]) do + table.insert(contest_ids, contest_id) + end + table.sort(contest_ids) + return contest_ids +end + ---@param platform string ---@param contest_id string ---@param problems Problem[] diff --git a/lua/cp/commands/init.lua b/lua/cp/commands/init.lua index fa4f658..f48727d 100644 --- a/lua/cp/commands/init.lua +++ b/lua/cp/commands/init.lua @@ -59,16 +59,15 @@ local function parse_command(args) local debug = false local test_index = nil - for i = 2, #args do - local arg = args[i] - if arg == '--debug' then + if #args == 2 then + if args[2] == '--debug' then debug = true else - local idx = tonumber(arg) + local idx = tonumber(args[2]) if not idx then return { type = 'error', - message = ("Invalid argument '%s': expected test number or --debug"):format(arg), + message = ("Invalid argument '%s': expected test number or --debug"):format(args[2]), } end if idx < 1 or idx ~= math.floor(idx) then @@ -76,6 +75,30 @@ local function parse_command(args) end test_index = idx end + elseif #args == 3 then + local idx = tonumber(args[2]) + if not idx then + return { + type = 'error', + message = ("Invalid argument '%s': expected test number"):format(args[2]), + } + end + if idx < 1 or idx ~= math.floor(idx) then + return { type = 'error', message = ("'%s' is not a valid test index"):format(idx) } + end + if args[3] ~= '--debug' then + return { + type = 'error', + message = ("Invalid argument '%s': expected --debug"):format(args[3]), + } + end + test_index = idx + debug = true + elseif #args > 3 then + return { + type = 'error', + message = 'Too many arguments. Usage: :CP ' .. first .. ' [test_num] [--debug]', + } end return { type = 'action', action = first, test_index = test_index, debug = debug } diff --git a/plugin/cp.lua b/plugin/cp.lua index 5d4df32..b4954a4 100644 --- a/plugin/cp.lua +++ b/plugin/cp.lua @@ -22,12 +22,30 @@ end, { num_args = num_args + 1 end + local function filter_candidates(candidates) + return vim.tbl_filter(function(cmd) + return cmd:find(ArgLead, 1, true) == 1 + end, candidates) + end + + local function get_enabled_languages(platform) + local config = require('cp.config').get_config() + if platform and config.platforms[platform] then + return config.platforms[platform].enabled_languages + end + return vim.tbl_keys(config.languages) + end + if num_args == 2 then local candidates = {} local state = require('cp.state') local platform = state.get_platform() local contest_id = state.get_contest_id() + vim.list_extend(candidates, platforms) + table.insert(candidates, 'cache') + table.insert(candidates, 'pick') + if platform and contest_id then vim.list_extend(candidates, actions) local cache = require('cp.cache') @@ -39,44 +57,75 @@ end, { table.sort(ids) vim.list_extend(candidates, ids) end - else - vim.list_extend(candidates, platforms) - table.insert(candidates, 'cache') - table.insert(candidates, 'pick') end - return vim.tbl_filter(function(cmd) - return cmd:find(ArgLead, 1, true) == 1 - end, candidates) + return filter_candidates(candidates) elseif num_args == 3 then - if args[2] == 'cache' then - return vim.tbl_filter(function(cmd) - return cmd:find(ArgLead, 1, true) == 1 - end, { 'clear', 'read' }) + if vim.tbl_contains(platforms, args[2]) then + local cache = require('cp.cache') + cache.load() + local contests = cache.get_cached_contest_ids(args[2]) + return filter_candidates(contests) + elseif args[2] == 'cache' then + return filter_candidates({ 'clear', 'read' }) elseif args[2] == 'interact' then - local cands = utils.cwd_executables() - return vim.tbl_filter(function(cmd) - return cmd:find(ArgLead, 1, true) == 1 - end, cands) + return filter_candidates(utils.cwd_executables()) + elseif args[2] == 'run' or args[2] == 'panel' then + local state = require('cp.state') + local platform = state.get_platform() + local contest_id = state.get_contest_id() + local problem_id = state.get_problem_id() + local candidates = { '--debug' } + if platform and contest_id and problem_id then + local cache = require('cp.cache') + cache.load() + local test_cases = cache.get_test_cases(platform, contest_id, problem_id) + if test_cases then + for i = 1, #test_cases do + table.insert(candidates, tostring(i)) + end + end + end + return filter_candidates(candidates) + elseif args[2] == 'next' or args[2] == 'prev' or args[2] == 'pick' then + return filter_candidates({ '--lang' }) + else + local state = require('cp.state') + if state.get_platform() and state.get_contest_id() then + return filter_candidates({ '--lang' }) + end end elseif num_args == 4 then if args[2] == 'cache' and args[3] == 'clear' then - return vim.tbl_filter(function(cmd) - return cmd:find(ArgLead, 1, true) == 1 - end, platforms) + return filter_candidates(platforms) + elseif args[3] == '--lang' then + local platform = require('cp.state').get_platform() + return filter_candidates(get_enabled_languages(platform)) + elseif (args[2] == 'run' or args[2] == 'panel') and tonumber(args[3]) then + return filter_candidates({ '--debug' }) elseif vim.tbl_contains(platforms, args[2]) then local cache = require('cp.cache') cache.load() local contest_data = cache.get_contest_data(args[2], args[3]) + local candidates = { '--lang' } if contest_data and contest_data.problems then - local candidates = {} for _, problem in ipairs(contest_data.problems) do table.insert(candidates, problem.id) end - return vim.tbl_filter(function(cmd) - return cmd:find(ArgLead, 1, true) == 1 - end, candidates) end + return filter_candidates(candidates) + end + elseif num_args == 5 then + if vim.tbl_contains(platforms, args[2]) then + if args[4] == '--lang' then + return filter_candidates(get_enabled_languages(args[2])) + else + return filter_candidates({ '--lang' }) + end + end + elseif num_args == 6 then + if vim.tbl_contains(platforms, args[2]) and args[5] == '--lang' then + return filter_candidates(get_enabled_languages(args[2])) end end return {} From 38223486423bfeae333902041c7ab740d0724315 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrett-ruth@users.noreply.github.com> Date: Fri, 24 Oct 2025 11:15:46 -0400 Subject: [PATCH 056/187] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7130889..7feb50b 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Scrape problems, run tests, and debug solutions across multiple platforms with zero configuration. -https://github.com/user-attachments/assets/50b19481-8e6d-47b4-bebc-15e16c61a9c9 +https://github.com/user-attachments/assets/2f01db4a-718a-482b-89c0-e841d37a63b4 ## Features From 9bf343846697e4cf55255e8321863a70e2ecf114 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 11:49:48 -0400 Subject: [PATCH 057/187] fix: defer to previous problem language --- lua/cp/setup.lua | 53 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index e6f9d21..991242e 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -9,7 +9,7 @@ local scraper = require('cp.scraper') local state = require('cp.state') ---Get the language of the current file from cache ----@return string|nil +---@return string? local function get_current_file_language() local current_file = vim.fn.expand('%:p') if current_file == '' then @@ -20,6 +20,34 @@ local function get_current_file_language() return file_state and file_state.language or nil end +---Check if a problem file exists for any enabled language +---@param platform string +---@param contest_id string +---@param problem_id string +---@return string? +local function get_existing_problem_language(platform, contest_id, problem_id) + local config = config_module.get_config() + local platform_config = config.platforms[platform] + if not platform_config then + return nil + end + + for _, lang_id in ipairs(platform_config.enabled_languages) do + local effective = config.runtime.effective[platform][lang_id] + if effective and effective.extension then + local basename = config.filename + and config.filename(platform, contest_id, problem_id, config, lang_id) + or config_module.default_filename(contest_id, problem_id) + local filepath = basename .. '.' .. effective.extension + if vim.fn.filereadable(filepath) == 1 then + return lang_id + end + end + end + + return nil +end + ---@class TestCaseLite ---@field input string ---@field expected string @@ -306,19 +334,28 @@ function M.navigate_problem(direction, language) require('cp.ui.views').disable() end + local lang = nil + if language then local lang_result = config_module.get_language_for_platform(platform, language) if not lang_result.valid then logger.log(lang_result.error, vim.log.levels.ERROR) return end - end - - local lang = language or get_current_file_language() - if lang and not language then - local lang_result = config_module.get_language_for_platform(platform, lang) - if not lang_result.valid then - lang = nil + lang = language + else + local existing_lang = + get_existing_problem_language(platform, contest_id, problems[new_index].id) + if existing_lang then + lang = existing_lang + else + lang = get_current_file_language() + if lang then + local lang_result = config_module.get_language_for_platform(platform, lang) + if not lang_result.valid then + lang = nil + end + end end end From 6ff0320531716aa67dfb01aafb03026482f5a49e Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 13:48:56 -0400 Subject: [PATCH 058/187] cleanup --- plugin/cp.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugin/cp.lua b/plugin/cp.lua index b4954a4..61f3b3d 100644 --- a/plugin/cp.lua +++ b/plugin/cp.lua @@ -3,8 +3,6 @@ if vim.g.loaded_cp then end vim.g.loaded_cp = 1 -local utils = require('cp.utils') - vim.api.nvim_create_user_command('CP', function(opts) local cp = require('cp') cp.handle_command(opts) @@ -69,6 +67,7 @@ end, { elseif args[2] == 'cache' then return filter_candidates({ 'clear', 'read' }) elseif args[2] == 'interact' then + local utils = require('cp.utils') return filter_candidates(utils.cwd_executables()) elseif args[2] == 'run' or args[2] == 'panel' then local state = require('cp.state') From b3168ff3f04bcfa96a3ef723319a6ad3e51a7600 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 14:03:00 -0400 Subject: [PATCH 059/187] feat: center the curso --- lua/cp/runner/run_render.lua | 12 ++++++++++-- lua/cp/ui/views.lua | 13 ++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/lua/cp/runner/run_render.lua b/lua/cp/runner/run_render.lua index 0847793..714ecd3 100644 --- a/lua/cp/runner/run_render.lua +++ b/lua/cp/runner/run_render.lua @@ -276,10 +276,13 @@ local function data_row(c, idx, tc, is_current, test_state) end ---@param test_state PanelState ----@return string[], Highlight[] lines and highlight positions +---@return string[] lines +---@return Highlight[] highlights +---@return integer current_test_line function M.render_test_list(test_state) local lines, highlights = {}, {} local c = compute_cols(test_state) + local current_test_line = nil table.insert(lines, top_border(c)) table.insert(lines, header_line(c)) @@ -289,6 +292,11 @@ function M.render_test_list(test_state) local is_current = (i == test_state.current_index) local row, hi = data_row(c, i, tc, is_current, test_state) table.insert(lines, row) + + if is_current then + current_test_line = #lines + end + if hi then hi.line = #lines - 1 table.insert(highlights, hi) @@ -327,7 +335,7 @@ function M.render_test_list(test_state) end end - return lines, highlights + return lines, highlights, current_test_line or 1 end ---@param ran_test_case RanTestCase? diff --git a/lua/cp/ui/views.lua b/lua/cp/ui/views.lua index 130da3b..23e2fc6 100644 --- a/lua/cp/ui/views.lua +++ b/lua/cp/ui/views.lua @@ -574,7 +574,7 @@ function M.toggle_panel(panel_opts) end run_render.setup_highlights() local test_state = run.get_panel_state() - local tab_lines, tab_highlights = run_render.render_test_list(test_state) + local tab_lines, tab_highlights, current_line = run_render.render_test_list(test_state) utils.update_buffer_content( test_buffers.tab_buf, tab_lines, @@ -582,6 +582,17 @@ function M.toggle_panel(panel_opts) test_list_namespace ) update_diff_panes() + + if + current_line + and test_windows.tab_win + and vim.api.nvim_win_is_valid(test_windows.tab_win) + then + vim.api.nvim_win_set_cursor(test_windows.tab_win, { current_line, 0 }) + vim.api.nvim_win_call(test_windows.tab_win, function() + vim.cmd('normal! zz') + end) + end end local function navigate_test_case(delta) From 3daf582b7a4966030f837470dbdc2f42bb4f32bd Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 14:26:51 -0400 Subject: [PATCH 060/187] feat(cache): update cache --- doc/cp.nvim.txt | 14 ++++++++++---- lua/cp/commands/cache.lua | 16 +++++++++++++++- lua/cp/commands/init.lua | 18 ++++++++++++++++++ lua/cp/constants.lua | 2 +- plugin/cp.lua | 11 +++++++++-- 5 files changed, 53 insertions(+), 8 deletions(-) diff --git a/doc/cp.nvim.txt b/doc/cp.nvim.txt index c8b17ce..a90ca9b 100644 --- a/doc/cp.nvim.txt +++ b/doc/cp.nvim.txt @@ -109,10 +109,16 @@ COMMANDS *cp-commands* switching files to restore your CP environment. Cache Commands ~ - :CP cache clear [contest] - Clear the cache data for the specified contest, - or all contests if none specified. - + :CP cache clear [platform] [contest] + Clear cache data at different granularities: + • No args: Clear all cached data + • [platform]: Clear all data for a platform + • [platform] [contest]: Clear specific contest + Examples: > + :CP cache clear " Clear all + :CP cache clear codeforces " Clear CF + :CP cache clear codeforces 1848 " Clear CF 1848 +< :CP cache read View the cache in a pretty-printed lua buffer. Exit with q. diff --git a/lua/cp/commands/cache.lua b/lua/cp/commands/cache.lua index e85e7ea..aba8bf5 100644 --- a/lua/cp/commands/cache.lua +++ b/lua/cp/commands/cache.lua @@ -39,7 +39,21 @@ function M.handle_cache_command(cmd) vim.api.nvim_set_current_buf(buf) elseif cmd.subcommand == 'clear' then cache.load() - if cmd.platform then + if cmd.platform and cmd.contest then + if vim.tbl_contains(platforms, cmd.platform) then + cache.clear_contest_data(cmd.platform, cmd.contest) + logger.log( + ("Cache cleared for %s contest '%s'"):format( + constants.PLATFORM_DISPLAY_NAMES[cmd.platform], + cmd.contest + ), + vim.log.levels.INFO, + true + ) + else + logger.log(("Unknown platform '%s'."):format(cmd.platform), vim.log.levels.ERROR) + end + elseif cmd.platform then if vim.tbl_contains(platforms, cmd.platform) then cache.clear_platform(cmd.platform) logger.log( diff --git a/lua/cp/commands/init.lua b/lua/cp/commands/init.lua index f48727d..06e0be4 100644 --- a/lua/cp/commands/init.lua +++ b/lua/cp/commands/init.lua @@ -40,10 +40,12 @@ local function parse_command(args) end if vim.tbl_contains({ 'clear', 'read' }, subcommand) then local platform = args[3] + local contest = args[4] return { type = 'cache', subcommand = subcommand, platform = platform, + contest = contest, } else return { type = 'error', message = 'unknown cache subcommand: ' .. subcommand } @@ -55,6 +57,22 @@ local function parse_command(args) else return { type = 'action', action = 'interact' } end + elseif first == 'edit' then + local test_index = nil + if #args >= 2 then + local idx = tonumber(args[2]) + if not idx then + return { + type = 'error', + message = ("Invalid argument '%s': expected test number"):format(args[2]), + } + end + if idx < 1 or idx ~= math.floor(idx) then + return { type = 'error', message = ("'%s' is not a valid test index"):format(idx) } + end + test_index = idx + end + return { type = 'action', action = 'edit', test_index = test_index } elseif first == 'run' or first == 'panel' then local debug = false local test_index = nil diff --git a/lua/cp/constants.lua b/lua/cp/constants.lua index b19e06b..9d1f0cc 100644 --- a/lua/cp/constants.lua +++ b/lua/cp/constants.lua @@ -1,7 +1,7 @@ local M = {} M.PLATFORMS = { 'atcoder', 'codeforces', 'cses' } -M.ACTIONS = { 'run', 'panel', 'next', 'prev', 'pick', 'cache', 'interact' } +M.ACTIONS = { 'run', 'panel', 'next', 'prev', 'pick', 'cache', 'interact', 'edit' } M.PLATFORM_DISPLAY_NAMES = { atcoder = 'AtCoder', diff --git a/plugin/cp.lua b/plugin/cp.lua index 61f3b3d..66023fc 100644 --- a/plugin/cp.lua +++ b/plugin/cp.lua @@ -96,7 +96,9 @@ end, { end elseif num_args == 4 then if args[2] == 'cache' and args[3] == 'clear' then - return filter_candidates(platforms) + local candidates = vim.list_extend({}, platforms) + table.insert(candidates, '') + return filter_candidates(candidates) elseif args[3] == '--lang' then local platform = require('cp.state').get_platform() return filter_candidates(get_enabled_languages(platform)) @@ -115,7 +117,12 @@ end, { return filter_candidates(candidates) end elseif num_args == 5 then - if vim.tbl_contains(platforms, args[2]) then + if args[2] == 'cache' and args[3] == 'clear' and vim.tbl_contains(platforms, args[4]) then + local cache = require('cp.cache') + cache.load() + local contests = cache.get_cached_contest_ids(args[4]) + return filter_candidates(contests) + elseif vim.tbl_contains(platforms, args[2]) then if args[4] == '--lang' then return filter_candidates(get_enabled_languages(args[2])) else From 4b1b75fd6ee0b328bfcd7c21c61e4f3ffcee7b38 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 14:44:33 -0400 Subject: [PATCH 061/187] fix(config): padding spacing --- doc/cp.nvim.txt | 27 ++++- lua/cp/commands/init.lua | 3 + lua/cp/config.lua | 4 + lua/cp/helpers.lua | 24 +++- lua/cp/ui/edit.lua | 231 +++++++++++++++++++++++++++++++++++++++ lua/cp/ui/views.lua | 23 ++++ plugin/cp.lua | 17 +++ 7 files changed, 320 insertions(+), 9 deletions(-) create mode 100644 lua/cp/ui/edit.lua diff --git a/doc/cp.nvim.txt b/doc/cp.nvim.txt index a90ca9b..71d73d7 100644 --- a/doc/cp.nvim.txt +++ b/doc/cp.nvim.txt @@ -102,6 +102,27 @@ COMMANDS *cp-commands* :CP C --lang python < + Edit Commands ~ + :CP edit [n] + Open grid test editor showing all test cases. + Tests displayed as 2×N grid (2 rows, N columns): + • Top row: Test inputs (editable) + • Bottom row: Expected outputs (editable) + + Optional [n]: Jump cursor to test n's input buffer + + Changes saved to both cache and disk on exit, + taking effect immediately in :CP run and CLI. + + Keybindings: + q Save all and exit editor + <c-w> Normal window navigation + + Examples: > + :CP edit " Edit all tests + :CP edit 3 " Edit all, start at test 3 +< + State Restoration ~ :CP Restore state from current file. Automatically detects platform, contest, problem, @@ -115,9 +136,9 @@ COMMANDS *cp-commands* • [platform]: Clear all data for a platform • [platform] [contest]: Clear specific contest Examples: > - :CP cache clear " Clear all - :CP cache clear codeforces " Clear CF - :CP cache clear codeforces 1848 " Clear CF 1848 + :CP cache clear + :CP cache clear codeforces + :CP cache clear codeforces 1848 < :CP cache read View the cache in a pretty-printed lua buffer. diff --git a/lua/cp/commands/init.lua b/lua/cp/commands/init.lua index 06e0be4..b585a5b 100644 --- a/lua/cp/commands/init.lua +++ b/lua/cp/commands/init.lua @@ -207,6 +207,9 @@ function M.handle_command(opts) elseif cmd.action == 'pick' then local picker = require('cp.commands.picker') picker.handle_pick_action(cmd.language) + elseif cmd.action == 'edit' then + local edit = require('cp.ui.edit') + edit.toggle_edit(cmd.test_index) end elseif cmd.type == 'problem_jump' then local platform = state.get_platform() diff --git a/lua/cp/config.lua b/lua/cp/config.lua index 46b13b4..764f324 100644 --- a/lua/cp/config.lua +++ b/lua/cp/config.lua @@ -43,6 +43,10 @@ ---@field memory_limit_mb number ---@field exit_code integer ---@field signal string|nil +---@field time_actual_width? integer +---@field time_limit_width? integer +---@field mem_actual_width? integer +---@field mem_limit_width? integer ---@class VerdictHighlight ---@field col_start integer diff --git a/lua/cp/helpers.lua b/lua/cp/helpers.lua index e31b6f9..070193c 100644 --- a/lua/cp/helpers.lua +++ b/lua/cp/helpers.lua @@ -51,17 +51,29 @@ end ---@param data VerdictFormatData ---@return VerdictFormatResult function M.default_verdict_formatter(data) - local time_data = string.format('%.2f', data.time_ms) .. '/' .. data.time_limit_ms - local mem_data = string.format('%.0f', data.memory_mb) - .. '/' - .. string.format('%.0f', data.memory_limit_mb) + local time_actual = string.format('%.2f', data.time_ms) + local time_limit = tostring(data.time_limit_ms) + local mem_actual = string.format('%.0f', data.memory_mb) + local mem_limit = string.format('%.0f', data.memory_limit_mb) local exit_str = data.signal and string.format('%d (%s)', data.exit_code, data.signal) or tostring(data.exit_code) + -- Use dynamic widths if provided, otherwise use reasonable defaults + local time_actual_w = data.time_actual_width or 6 + local time_limit_w = data.time_limit_width or 4 + local mem_actual_w = data.mem_actual_width or 3 + local mem_limit_w = data.mem_limit_width or 3 + local test_num_part = 'Test ' .. data.index .. ':' local status_part = M.pad_right(data.status.text, 3) - local time_part = time_data .. ' ms' - local mem_part = mem_data .. ' MB' + local time_part = M.pad_left(time_actual, time_actual_w) + .. '/' + .. M.pad_left(time_limit, time_limit_w) + .. ' ms' + local mem_part = M.pad_left(mem_actual, mem_actual_w) + .. '/' + .. M.pad_left(mem_limit, mem_limit_w) + .. ' MB' local exit_part = 'exit: ' .. exit_str local line = test_num_part diff --git a/lua/cp/ui/edit.lua b/lua/cp/ui/edit.lua new file mode 100644 index 0000000..897c4c4 --- /dev/null +++ b/lua/cp/ui/edit.lua @@ -0,0 +1,231 @@ +local M = {} + +local cache = require('cp.cache') +local config_module = require('cp.config') +local helpers = require('cp.helpers') +local logger = require('cp.log') +local state = require('cp.state') +local utils = require('cp.utils') + +---@class TestBufferPair +---@field input_buf integer +---@field expected_buf integer +---@field input_win integer +---@field expected_win integer + +---@class EditState +---@field test_buffers TestBufferPair[] +---@field test_cases TestCase[] +---@field constraints ProblemConstraints? + +---@type EditState? +local edit_state = nil + +local function setup_keybindings(buf) + vim.keymap.set('n', 'q', function() + M.toggle_edit() + end, { buffer = buf, silent = true, desc = 'Save and exit test editor' }) +end + +local function load_test_into_buffer(test_index) + if not edit_state then + return + end + + local tc = edit_state.test_cases[test_index] + local pair = edit_state.test_buffers[test_index] + + if not tc or not pair then + return + end + + local input_lines = vim.split(tc.input or '', '\n', { plain = true, trimempty = false }) + vim.api.nvim_buf_set_lines(pair.input_buf, 0, -1, false, input_lines) + + local expected_lines = vim.split(tc.expected or '', '\n', { plain = true, trimempty = false }) + vim.api.nvim_buf_set_lines(pair.expected_buf, 0, -1, false, expected_lines) + + vim.api.nvim_buf_set_name(pair.input_buf, string.format('cp://test-%d-input', test_index)) + vim.api.nvim_buf_set_name(pair.expected_buf, string.format('cp://test-%d-expected', test_index)) +end + +local function save_all_tests() + if not edit_state then + return + end + + local platform = state.get_platform() + local contest_id = state.get_contest_id() + local problem_id = state.get_problem_id() + + if not platform or not contest_id or not problem_id then + return + end + + for i, pair in ipairs(edit_state.test_buffers) do + if + vim.api.nvim_buf_is_valid(pair.input_buf) and vim.api.nvim_buf_is_valid(pair.expected_buf) + then + local input_lines = vim.api.nvim_buf_get_lines(pair.input_buf, 0, -1, false) + local expected_lines = vim.api.nvim_buf_get_lines(pair.expected_buf, 0, -1, false) + + edit_state.test_cases[i].input = table.concat(input_lines, '\n') + edit_state.test_cases[i].expected = table.concat(expected_lines, '\n') + end + end + + cache.set_test_cases( + platform, + contest_id, + problem_id, + edit_state.test_cases, + edit_state.constraints and edit_state.constraints.timeout_ms or 0, + edit_state.constraints and edit_state.constraints.memory_mb or 0, + false + ) + + local config = config_module.get_config() + local base_name = config.filename and config.filename(platform, contest_id, problem_id, config) + or config_module.default_filename(contest_id, problem_id) + + vim.fn.mkdir('io', 'p') + + for i, tc in ipairs(edit_state.test_cases) do + local input_file = string.format('io/%s.%d.cpin', base_name, i) + local expected_file = string.format('io/%s.%d.cpout', base_name, i) + + local input_content = (tc.input or ''):gsub('\r', '') + local expected_content = (tc.expected or ''):gsub('\r', '') + + vim.fn.writefile(vim.split(input_content, '\n', { trimempty = true }), input_file) + vim.fn.writefile(vim.split(expected_content, '\n', { trimempty = true }), expected_file) + end + + logger.log('Saved all test cases') +end + +function M.toggle_edit(test_index) + if edit_state then + save_all_tests() + local saved = state.get_saved_session() + if saved then + vim.cmd(('source %s'):format(saved)) + vim.fn.delete(saved) + state.set_saved_session(nil) + end + edit_state = nil + logger.log('Closed test editor') + return + end + + local platform, contest_id, problem_id = + state.get_platform(), state.get_contest_id(), state.get_problem_id() + + if not platform or not contest_id or not problem_id then + logger.log('No problem context. Run :CP <platform> <contest> first.', vim.log.levels.ERROR) + return + end + + cache.load() + local test_cases = cache.get_test_cases(platform, contest_id, problem_id) + + if not test_cases or #test_cases == 0 then + logger.log('No test cases available for editing.', vim.log.levels.ERROR) + return + end + + local timeout_ms, memory_mb = cache.get_constraints(platform, contest_id, problem_id) + local constraints = (timeout_ms and memory_mb) + and { timeout_ms = timeout_ms, memory_mb = memory_mb } + or nil + + local target_index = test_index or 1 + if target_index < 1 or target_index > #test_cases then + logger.log( + ('Test %d does not exist (only %d tests available)'):format(target_index, #test_cases), + vim.log.levels.ERROR + ) + return + end + + local session_file = vim.fn.tempname() + state.set_saved_session(session_file) + vim.cmd(('mksession! %s'):format(session_file)) + vim.cmd('silent only') + + local test_buffers = {} + local num_tests = #test_cases + + -- Step 1: Create N columns (vsplit creates full-height columns) + for i = 1, num_tests - 1 do + vim.cmd('vsplit') + end + + -- Step 2: Go to leftmost window + vim.cmd('1wincmd w') + + -- Step 3: For each column, split horizontally into input (top) and expected (bottom) + for col = 1, num_tests do + -- Split current window horizontally + vim.cmd('split') + + -- After split, cursor is in bottom window. Go up to input window. + vim.cmd('wincmd k') + local input_win = vim.api.nvim_get_current_win() + local input_buf = utils.create_buffer_with_options() + vim.api.nvim_win_set_buf(input_win, input_buf) + vim.bo[input_buf].modifiable = true + vim.bo[input_buf].readonly = false + vim.bo[input_buf].buftype = 'nofile' + vim.bo[input_buf].buflisted = false + helpers.clearcol(input_buf) + + -- Go down to expected window + vim.cmd('wincmd j') + local expected_win = vim.api.nvim_get_current_win() + local expected_buf = utils.create_buffer_with_options() + vim.api.nvim_win_set_buf(expected_win, expected_buf) + vim.bo[expected_buf].modifiable = true + vim.bo[expected_buf].readonly = false + vim.bo[expected_buf].buftype = 'nofile' + vim.bo[expected_buf].buflisted = false + helpers.clearcol(expected_buf) + + test_buffers[col] = { + input_buf = input_buf, + expected_buf = expected_buf, + input_win = input_win, + expected_win = expected_win, + } + + -- Move to next column (go up to top, then right) + vim.cmd('wincmd k') + vim.cmd('wincmd l') + end + + edit_state = { + test_buffers = test_buffers, + test_cases = test_cases, + constraints = constraints, + } + + for i = 1, num_tests do + load_test_into_buffer(i) + end + + for _, pair in ipairs(test_buffers) do + setup_keybindings(pair.input_buf) + setup_keybindings(pair.expected_buf) + end + + if + test_buffers[target_index] + and vim.api.nvim_win_is_valid(test_buffers[target_index].input_win) + then + vim.api.nvim_set_current_win(test_buffers[target_index].input_win) + end + + logger.log(('Editing %d test cases'):format(num_tests)) +end + +return M diff --git a/lua/cp/ui/views.lua b/lua/cp/ui/views.lua index 23e2fc6..4aa877f 100644 --- a/lua/cp/ui/views.lua +++ b/lua/cp/ui/views.lua @@ -400,6 +400,25 @@ function M.run_io_view(test_index, debug) local formatter = config.ui.run.format_verdict + local max_time_actual = 0 + local max_time_limit = 0 + local max_mem_actual = 0 + local max_mem_limit = 0 + + for _, idx in ipairs(test_indices) do + local tc = test_state.test_cases[idx] + max_time_actual = math.max(max_time_actual, #string.format('%.2f', tc.time_ms or 0)) + max_time_limit = math.max( + max_time_limit, + #tostring(test_state.constraints and test_state.constraints.timeout_ms or 0) + ) + max_mem_actual = math.max(max_mem_actual, #string.format('%.0f', tc.rss_mb or 0)) + max_mem_limit = math.max( + max_mem_limit, + #string.format('%.0f', test_state.constraints and test_state.constraints.memory_mb or 0) + ) + end + for _, idx in ipairs(test_indices) do local tc = test_state.test_cases[idx] @@ -425,6 +444,10 @@ function M.run_io_view(test_index, debug) exit_code = tc.code or 0, signal = (tc.code and tc.code >= 128) and require('cp.constants').signal_codes[tc.code] or nil, + time_actual_width = max_time_actual, + time_limit_width = max_time_limit, + mem_actual_width = max_mem_actual, + mem_limit_width = max_mem_limit, } local result = formatter(format_data) diff --git a/plugin/cp.lua b/plugin/cp.lua index 66023fc..b91a3d5 100644 --- a/plugin/cp.lua +++ b/plugin/cp.lua @@ -69,6 +69,23 @@ end, { elseif args[2] == 'interact' then local utils = require('cp.utils') return filter_candidates(utils.cwd_executables()) + elseif args[2] == 'edit' then + local state = require('cp.state') + local platform = state.get_platform() + local contest_id = state.get_contest_id() + local problem_id = state.get_problem_id() + local candidates = {} + if platform and contest_id and problem_id then + local cache = require('cp.cache') + cache.load() + local test_cases = cache.get_test_cases(platform, contest_id, problem_id) + if test_cases then + for i = 1, #test_cases do + table.insert(candidates, tostring(i)) + end + end + end + return filter_candidates(candidates) elseif args[2] == 'run' or args[2] == 'panel' then local state = require('cp.state') local platform = state.get_platform() From a842886933d83ec5580c3efb2a06a5a7d9cc9c27 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 14:47:12 -0400 Subject: [PATCH 062/187] feat(ui): auto-hide source buffer on close --- doc/cp.nvim.txt | 20 ++++++++++++-------- lua/cp/helpers.lua | 1 - lua/cp/ui/edit.lua | 7 ------- lua/cp/ui/views.lua | 17 +++++++++++++++++ 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/doc/cp.nvim.txt b/doc/cp.nvim.txt index 71d73d7..2956d4b 100644 --- a/doc/cp.nvim.txt +++ b/doc/cp.nvim.txt @@ -590,14 +590,18 @@ Input: |VerdictFormatData| table with test results Output: |VerdictFormatResult| table with formatted line and optional highlights *VerdictFormatData* - {index} (integer) Test case number - {status} (table) { text: string, highlight_group: string } - {time_ms} (number) Execution time in milliseconds - {time_limit_ms} (number) Time limit in milliseconds - {memory_mb} (number) Peak memory usage in megabytes - {memory_limit_mb} (number) Memory limit in megabytes - {exit_code} (integer) Process exit code - {signal} (string|nil) Signal name for crashes (e.g. "SIGSEGV") + {index} (integer) Test case number + {status} (table) { text: string, highlight_group: string } + {time_ms} (number) Execution time in milliseconds + {time_limit_ms} (number) Time limit in milliseconds + {memory_mb} (number) Peak memory usage in megabytes + {memory_limit_mb} (number) Memory limit in megabytes + {exit_code} (integer) Process exit code + {signal} (string|nil) Signal name for crashes (e.g. "SIGSEGV") + {time_actual_width} (integer|nil) Dynamic width for time value alignment + {time_limit_width} (integer|nil) Dynamic width for time limit alignment + {mem_actual_width} (integer|nil) Dynamic width for memory value alignment + {mem_limit_width} (integer|nil) Dynamic width for memory limit alignment *VerdictFormatResult* {line} (string) The formatted verdict line diff --git a/lua/cp/helpers.lua b/lua/cp/helpers.lua index 070193c..57f87ca 100644 --- a/lua/cp/helpers.lua +++ b/lua/cp/helpers.lua @@ -58,7 +58,6 @@ function M.default_verdict_formatter(data) local exit_str = data.signal and string.format('%d (%s)', data.exit_code, data.signal) or tostring(data.exit_code) - -- Use dynamic widths if provided, otherwise use reasonable defaults local time_actual_w = data.time_actual_width or 6 local time_limit_w = data.time_limit_width or 4 local mem_actual_w = data.mem_actual_width or 3 diff --git a/lua/cp/ui/edit.lua b/lua/cp/ui/edit.lua index 897c4c4..2616016 100644 --- a/lua/cp/ui/edit.lua +++ b/lua/cp/ui/edit.lua @@ -156,20 +156,15 @@ function M.toggle_edit(test_index) local test_buffers = {} local num_tests = #test_cases - -- Step 1: Create N columns (vsplit creates full-height columns) for i = 1, num_tests - 1 do vim.cmd('vsplit') end - -- Step 2: Go to leftmost window vim.cmd('1wincmd w') - -- Step 3: For each column, split horizontally into input (top) and expected (bottom) for col = 1, num_tests do - -- Split current window horizontally vim.cmd('split') - -- After split, cursor is in bottom window. Go up to input window. vim.cmd('wincmd k') local input_win = vim.api.nvim_get_current_win() local input_buf = utils.create_buffer_with_options() @@ -180,7 +175,6 @@ function M.toggle_edit(test_index) vim.bo[input_buf].buflisted = false helpers.clearcol(input_buf) - -- Go down to expected window vim.cmd('wincmd j') local expected_win = vim.api.nvim_get_current_win() local expected_buf = utils.create_buffer_with_options() @@ -198,7 +192,6 @@ function M.toggle_edit(test_index) expected_win = expected_win, } - -- Move to next column (go up to top, then right) vim.cmd('wincmd k') vim.cmd('wincmd l') end diff --git a/lua/cp/ui/views.lua b/lua/cp/ui/views.lua index 4aa877f..ab71d5b 100644 --- a/lua/cp/ui/views.lua +++ b/lua/cp/ui/views.lua @@ -247,6 +247,23 @@ function M.ensure_io_view() current_test_index = 1, }) + local source_buf = vim.api.nvim_win_get_buf(solution_win) + vim.api.nvim_create_autocmd('BufDelete', { + buffer = source_buf, + callback = function() + local io = state.get_io_view_state() + if io then + if io.output_buf and vim.api.nvim_buf_is_valid(io.output_buf) then + vim.api.nvim_buf_delete(io.output_buf, { force = true }) + end + if io.input_buf and vim.api.nvim_buf_is_valid(io.input_buf) then + vim.api.nvim_buf_delete(io.input_buf, { force = true }) + end + state.set_io_view_state(nil) + end + end, + }) + if cfg.hooks and cfg.hooks.setup_io_output then pcall(cfg.hooks.setup_io_output, output_buf, state) end From 8ffa3cb0d232d35c2f742dd1ac4df32a3bcc7044 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 15:10:58 -0400 Subject: [PATCH 063/187] fix: modernize use of typing --- lua/cp/ui/edit.lua | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/lua/cp/ui/edit.lua b/lua/cp/ui/edit.lua index 2616016..70b0edd 100644 --- a/lua/cp/ui/edit.lua +++ b/lua/cp/ui/edit.lua @@ -107,13 +107,23 @@ end function M.toggle_edit(test_index) if edit_state then save_all_tests() + edit_state = nil + local saved = state.get_saved_session() if saved then - vim.cmd(('source %s'):format(saved)) vim.fn.delete(saved) state.set_saved_session(nil) end - edit_state = nil + + vim.cmd.only({ mods = { silent = true } }) + local source_file = state.get_source_file() + if source_file and vim.fn.filereadable(source_file) == 1 then + vim.cmd.edit(source_file) + end + + local views = require('cp.ui.views') + views.run_io_view() + logger.log('Closed test editor') return end @@ -148,24 +158,35 @@ function M.toggle_edit(test_index) return end + local io_view_state = state.get_io_view_state() + if io_view_state then + if io_view_state.output_buf and vim.api.nvim_buf_is_valid(io_view_state.output_buf) then + vim.api.nvim_buf_delete(io_view_state.output_buf, { force = true }) + end + if io_view_state.input_buf and vim.api.nvim_buf_is_valid(io_view_state.input_buf) then + vim.api.nvim_buf_delete(io_view_state.input_buf, { force = true }) + end + state.set_io_view_state(nil) + end + local session_file = vim.fn.tempname() state.set_saved_session(session_file) - vim.cmd(('mksession! %s'):format(session_file)) - vim.cmd('silent only') + vim.cmd.mksession({ session_file, bang = true }) + vim.cmd.only({ mods = { silent = true } }) local test_buffers = {} local num_tests = #test_cases for i = 1, num_tests - 1 do - vim.cmd('vsplit') + vim.cmd.vsplit() end - vim.cmd('1wincmd w') + vim.cmd.wincmd('w', { count = 1 }) for col = 1, num_tests do - vim.cmd('split') + vim.cmd.split() - vim.cmd('wincmd k') + vim.cmd.wincmd('k') local input_win = vim.api.nvim_get_current_win() local input_buf = utils.create_buffer_with_options() vim.api.nvim_win_set_buf(input_win, input_buf) @@ -175,7 +196,7 @@ function M.toggle_edit(test_index) vim.bo[input_buf].buflisted = false helpers.clearcol(input_buf) - vim.cmd('wincmd j') + vim.cmd.wincmd('j') local expected_win = vim.api.nvim_get_current_win() local expected_buf = utils.create_buffer_with_options() vim.api.nvim_win_set_buf(expected_win, expected_buf) @@ -192,8 +213,8 @@ function M.toggle_edit(test_index) expected_win = expected_win, } - vim.cmd('wincmd k') - vim.cmd('wincmd l') + vim.cmd.wincmd('k') + vim.cmd.wincmd('l') end edit_state = { From de45fd339361f678853bf3f3cad469b921d42a72 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 15:16:22 -0400 Subject: [PATCH 064/187] fix: modernize use of `vim.cmd` --- lua/cp/setup.lua | 6 +++++- lua/cp/ui/layouts.lua | 8 ++++---- lua/cp/ui/views.lua | 20 ++++++++++---------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index 991242e..588abca 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -244,7 +244,11 @@ function M.setup_problem(problem_id, language) if vim.api.nvim_buf_is_valid(prov.bufnr) then vim.api.nvim_buf_set_name(prov.bufnr, source_file) vim.bo[prov.bufnr].swapfile = true - vim.cmd(string.format('silent keepalt noautocmd write! %s', vim.fn.fnameescape(source_file))) + vim.cmd.write({ + vim.fn.fnameescape(source_file), + bang = true, + mods = { silent = true, noautocmd = true, keepalt = true }, + }) state.set_solution_win(vim.api.nvim_get_current_win()) if config.hooks and config.hooks.setup_code and not vim.b[prov.bufnr].cp_setup_done then local ok = pcall(config.hooks.setup_code, state) diff --git a/lua/cp/ui/layouts.lua b/lua/cp/ui/layouts.lua index 730c17e..4e737d3 100644 --- a/lua/cp/ui/layouts.lua +++ b/lua/cp/ui/layouts.lua @@ -11,7 +11,7 @@ local function create_none_diff_layout(parent_win, expected_content, actual_cont vim.api.nvim_set_current_win(parent_win) vim.cmd.split() - vim.cmd('resize ' .. math.floor(vim.o.lines * 0.35)) + vim.cmd.resize(math.floor(vim.o.lines * 0.35)) local actual_win = vim.api.nvim_get_current_win() vim.api.nvim_win_set_buf(actual_win, actual_buf) @@ -50,7 +50,7 @@ local function create_vim_diff_layout(parent_win, expected_content, actual_conte vim.api.nvim_set_current_win(parent_win) vim.cmd.split() - vim.cmd('resize ' .. math.floor(vim.o.lines * 0.35)) + vim.cmd.resize(math.floor(vim.o.lines * 0.35)) local actual_win = vim.api.nvim_get_current_win() vim.api.nvim_win_set_buf(actual_win, actual_buf) @@ -98,7 +98,7 @@ local function create_git_diff_layout(parent_win, expected_content, actual_conte vim.api.nvim_set_current_win(parent_win) vim.cmd.split() - vim.cmd('resize ' .. math.floor(vim.o.lines * 0.35)) + vim.cmd.resize(math.floor(vim.o.lines * 0.35)) local diff_win = vim.api.nvim_get_current_win() vim.api.nvim_win_set_buf(diff_win, diff_buf) @@ -135,7 +135,7 @@ local function create_single_layout(parent_win, content) vim.api.nvim_set_current_win(parent_win) vim.cmd.split() - vim.cmd('resize ' .. math.floor(vim.o.lines * 0.35)) + vim.cmd.resize(math.floor(vim.o.lines * 0.35)) local win = vim.api.nvim_get_current_win() vim.api.nvim_win_set_buf(win, buf) vim.api.nvim_set_option_value('filetype', 'cp', { buf = buf }) diff --git a/lua/cp/ui/views.lua b/lua/cp/ui/views.lua index ab71d5b..d36ee41 100644 --- a/lua/cp/ui/views.lua +++ b/lua/cp/ui/views.lua @@ -40,7 +40,7 @@ function M.toggle_interactive(interactor_cmd) end end if state.saved_interactive_session then - vim.cmd(('source %s'):format(state.saved_interactive_session)) + vim.cmd.source(state.saved_interactive_session) vim.fn.delete(state.saved_interactive_session) state.saved_interactive_session = nil end @@ -75,8 +75,8 @@ function M.toggle_interactive(interactor_cmd) end state.saved_interactive_session = vim.fn.tempname() - vim.cmd(('mksession! %s'):format(state.saved_interactive_session)) - vim.cmd('silent only') + vim.cmd.mksession({ state.saved_interactive_session, bang = true }) + vim.cmd.only({ mods = { silent = true } }) local execute = require('cp.runner.execute') local run = require('cp.runner.run') @@ -104,7 +104,7 @@ function M.toggle_interactive(interactor_cmd) vim.log.levels.ERROR ) if state.saved_interactive_session then - vim.cmd(('source %s'):format(state.saved_interactive_session)) + vim.cmd.source(state.saved_interactive_session) vim.fn.delete(state.saved_interactive_session) state.saved_interactive_session = nil end @@ -122,7 +122,7 @@ function M.toggle_interactive(interactor_cmd) cmdline = vim.fn.shellescape(binary) end - vim.cmd('terminal ' .. cmdline) + vim.cmd.terminal(cmdline) local term_buf = vim.api.nvim_get_current_buf() local term_win = vim.api.nvim_get_current_win() @@ -139,7 +139,7 @@ function M.toggle_interactive(interactor_cmd) end end if state.saved_interactive_session then - vim.cmd(('source %s'):format(state.saved_interactive_session)) + vim.cmd.source(state.saved_interactive_session) vim.fn.delete(state.saved_interactive_session) state.saved_interactive_session = nil end @@ -524,7 +524,7 @@ function M.toggle_panel(panel_opts) end local saved = state.get_saved_session() if saved then - vim.cmd(('source %s'):format(saved)) + vim.cmd.source(saved) vim.fn.delete(saved) state.set_saved_session(nil) end @@ -582,8 +582,8 @@ function M.toggle_panel(panel_opts) local session_file = vim.fn.tempname() state.set_saved_session(session_file) - vim.cmd(('mksession! %s'):format(session_file)) - vim.cmd('silent only') + vim.cmd.mksession({ session_file, bang = true }) + vim.cmd.only({ mods = { silent = true } }) local tab_buf = utils.create_buffer_with_options() helpers.clearcol(tab_buf) @@ -630,7 +630,7 @@ function M.toggle_panel(panel_opts) then vim.api.nvim_win_set_cursor(test_windows.tab_win, { current_line, 0 }) vim.api.nvim_win_call(test_windows.tab_win, function() - vim.cmd('normal! zz') + vim.cmd.normal({ 'zz', bang = true }) end) end end From 11b6056d8c5579568d60734050726d58749d0a0c Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 16:12:53 -0400 Subject: [PATCH 065/187] fix --- lua/cp/setup.lua | 1 + lua/cp/ui/edit.lua | 7 ++++--- lua/cp/ui/views.lua | 3 +++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index 588abca..b7173e1 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -244,6 +244,7 @@ function M.setup_problem(problem_id, language) if vim.api.nvim_buf_is_valid(prov.bufnr) then vim.api.nvim_buf_set_name(prov.bufnr, source_file) vim.bo[prov.bufnr].swapfile = true + -- selene: allow(mixed_table) vim.cmd.write({ vim.fn.fnameescape(source_file), bang = true, diff --git a/lua/cp/ui/edit.lua b/lua/cp/ui/edit.lua index 70b0edd..a19d06d 100644 --- a/lua/cp/ui/edit.lua +++ b/lua/cp/ui/edit.lua @@ -122,7 +122,7 @@ function M.toggle_edit(test_index) end local views = require('cp.ui.views') - views.run_io_view() + views.ensure_io_view() logger.log('Closed test editor') return @@ -171,17 +171,18 @@ function M.toggle_edit(test_index) local session_file = vim.fn.tempname() state.set_saved_session(session_file) + -- selene: allow(mixed_table) vim.cmd.mksession({ session_file, bang = true }) vim.cmd.only({ mods = { silent = true } }) local test_buffers = {} local num_tests = #test_cases - for i = 1, num_tests - 1 do + for _ = 1, num_tests - 1 do vim.cmd.vsplit() end - vim.cmd.wincmd('w', { count = 1 }) + vim.cmd('1 wincmd w') for col = 1, num_tests do vim.cmd.split() diff --git a/lua/cp/ui/views.lua b/lua/cp/ui/views.lua index d36ee41..ab7a407 100644 --- a/lua/cp/ui/views.lua +++ b/lua/cp/ui/views.lua @@ -75,6 +75,7 @@ function M.toggle_interactive(interactor_cmd) end state.saved_interactive_session = vim.fn.tempname() + -- selene: allow(mixed_table) vim.cmd.mksession({ state.saved_interactive_session, bang = true }) vim.cmd.only({ mods = { silent = true } }) @@ -582,6 +583,7 @@ function M.toggle_panel(panel_opts) local session_file = vim.fn.tempname() state.set_saved_session(session_file) + -- selene: allow(mixed_table) vim.cmd.mksession({ session_file, bang = true }) vim.cmd.only({ mods = { silent = true } }) @@ -629,6 +631,7 @@ function M.toggle_panel(panel_opts) and vim.api.nvim_win_is_valid(test_windows.tab_win) then vim.api.nvim_win_set_cursor(test_windows.tab_win, { current_line, 0 }) + -- selene: allow(mixed_table) vim.api.nvim_win_call(test_windows.tab_win, function() vim.cmd.normal({ 'zz', bang = true }) end) From 3fdb74a3d82532fd121ad9a336f5b58f50285c75 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 16:17:56 -0400 Subject: [PATCH 066/187] fix: cleanup script --- scripts/interact.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/interact.py b/scripts/interact.py index 4c24173..d4ddfa4 100644 --- a/scripts/interact.py +++ b/scripts/interact.py @@ -12,8 +12,8 @@ async def pump( data = await reader.readline() if not data: break - sys.stdout.buffer.write(data) - sys.stdout.flush() + _ = sys.stdout.buffer.write(data) + _ = sys.stdout.flush() if writer: writer.write(data) await writer.drain() @@ -42,9 +42,9 @@ async def main(interactor_cmd: Sequence[str], interactee_cmd: Sequence[str]) -> asyncio.create_task(pump(interactor.stdout, interactee.stdin)), asyncio.create_task(pump(interactee.stdout, interactor.stdin)), ] - await asyncio.wait(tasks, return_when=asyncio.ALL_COMPLETED) - await interactor.wait() - await interactee.wait() + _ = await asyncio.wait(tasks, return_when=asyncio.ALL_COMPLETED) + _ = await interactor.wait() + _ = await interactee.wait() if __name__ == "__main__": @@ -55,4 +55,4 @@ if __name__ == "__main__": interactor_cmd = shlex.split(sys.argv[1]) interactee_cmd = shlex.split(sys.argv[2]) - asyncio.run(main(interactor_cmd, interactee_cmd)) + _ = asyncio.run(main(interactor_cmd, interactee_cmd)) From 181fff42dee7348847fe7a9f578569f922d4042e Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 16:35:00 -0400 Subject: [PATCH 067/187] feat(ui): documentation for :CP edit abilities --- doc/cp.nvim.txt | 15 +++++++++++++- lua/cp/config.lua | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/doc/cp.nvim.txt b/doc/cp.nvim.txt index 2956d4b..3e450ce 100644 --- a/doc/cp.nvim.txt +++ b/doc/cp.nvim.txt @@ -114,8 +114,12 @@ COMMANDS *cp-commands* Changes saved to both cache and disk on exit, taking effect immediately in :CP run and CLI. - Keybindings: + Keybindings (configurable via |EditConfig|): q Save all and exit editor + ]t Jump to next test column + [t Jump to previous test column + gd Delete current test column + ga Add new test column at end <c-w> Normal window navigation Examples: > @@ -348,6 +352,15 @@ run CSES problems with Rust using the single schema: {format_verdict} (|VerdictFormatter|, default: nil) Custom verdict line formatter. See |cp-verdict-format|. + *EditConfig* + Fields: ~ + {next_test_key} (string|nil, default: ']t') Jump to next test. + {prev_test_key} (string|nil, default: '[t') Jump to previous test. + {delete_test_key} (string|nil, default: 'gd') Delete current test. + {add_test_key} (string|nil, default: 'ga') Add new test. + {save_and_exit_key} (string|nil, default: 'q') Save and exit editor. + All keys are nil-able. Set to nil to disable. + *cp.PanelConfig* Fields: ~ {diff_mode} (string, default: "none") Diff backend: "none", diff --git a/lua/cp/config.lua b/lua/cp/config.lua index 764f324..5b3b584 100644 --- a/lua/cp/config.lua +++ b/lua/cp/config.lua @@ -65,9 +65,17 @@ ---@field prev_test_key string|nil ---@field format_verdict VerdictFormatter +---@class EditConfig +---@field next_test_key string|nil +---@field prev_test_key string|nil +---@field delete_test_key string|nil +---@field add_test_key string|nil +---@field save_and_exit_key string|nil + ---@class CpUI ---@field ansi boolean ---@field run RunConfig +---@field edit EditConfig ---@field panel PanelConfig ---@field diff DiffConfig ---@field picker string|nil @@ -154,6 +162,13 @@ M.defaults = { prev_test_key = '<c-p>', format_verdict = helpers.default_verdict_formatter, }, + edit = { + next_test_key = ']t', + prev_test_key = '[t', + delete_test_key = 'gd', + add_test_key = 'ga', + save_and_exit_key = 'q', + }, panel = { diff_mode = 'none', max_output_lines = 50 }, diff = { git = { @@ -329,6 +344,41 @@ function M.setup(user_config) cfg.ui.run.format_verdict, 'function', }, + edit_next_test_key = { + cfg.ui.edit.next_test_key, + function(v) + return v == nil or (type(v) == 'string' and #v > 0) + end, + 'nil or non-empty string', + }, + edit_prev_test_key = { + cfg.ui.edit.prev_test_key, + function(v) + return v == nil or (type(v) == 'string' and #v > 0) + end, + 'nil or non-empty string', + }, + delete_test_key = { + cfg.ui.edit.delete_test_key, + function(v) + return v == nil or (type(v) == 'string' and #v > 0) + end, + 'nil or non-empty string', + }, + add_test_key = { + cfg.ui.edit.add_test_key, + function(v) + return v == nil or (type(v) == 'string' and #v > 0) + end, + 'nil or non-empty string', + }, + save_and_exit_key = { + cfg.ui.edit.save_and_exit_key, + function(v) + return v == nil or (type(v) == 'string' and #v > 0) + end, + 'nil or non-empty string', + }, }) for id, lang in pairs(cfg.languages) do From b736fd01314e3cdcef21e98a8494ef4d65b70c3a Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 17:02:43 -0400 Subject: [PATCH 068/187] feat(ui): test editor --- lua/cp/ui/edit.lua | 178 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 174 insertions(+), 4 deletions(-) diff --git a/lua/cp/ui/edit.lua b/lua/cp/ui/edit.lua index a19d06d..ada41bb 100644 --- a/lua/cp/ui/edit.lua +++ b/lua/cp/ui/edit.lua @@ -21,12 +21,48 @@ local utils = require('cp.utils') ---@type EditState? local edit_state = nil -local function setup_keybindings(buf) - vim.keymap.set('n', 'q', function() - M.toggle_edit() - end, { buffer = buf, silent = true, desc = 'Save and exit test editor' }) +local setup_keybindings + +---@param bufnr integer +---@return integer? test_index +local function get_current_test_index(bufnr) + if not edit_state then + return nil + end + for i, pair in ipairs(edit_state.test_buffers) do + if pair.input_buf == bufnr or pair.expected_buf == bufnr then + return i + end + end + return nil end +---@param index integer +local function jump_to_test(index) + if not edit_state then + return + end + local pair = edit_state.test_buffers[index] + if pair and vim.api.nvim_win_is_valid(pair.input_win) then + vim.api.nvim_set_current_win(pair.input_win) + end +end + +---@param delta integer +local function navigate_test(delta) + local current_buf = vim.api.nvim_get_current_buf() + local current_index = get_current_test_index(current_buf) + if not current_index or not edit_state then + return + end + local new_index = current_index + delta + if new_index < 1 or new_index > #edit_state.test_buffers then + return + end + jump_to_test(new_index) +end + +---@param test_index integer local function load_test_into_buffer(test_index) if not edit_state then return @@ -49,6 +85,140 @@ local function load_test_into_buffer(test_index) vim.api.nvim_buf_set_name(pair.expected_buf, string.format('cp://test-%d-expected', test_index)) end +local function delete_current_test() + if not edit_state then + return + end + if #edit_state.test_buffers == 1 then + logger.log('Cannot have 0 problem tests.', vim.log.levels.ERROR) + return + end + + local current_buf = vim.api.nvim_get_current_buf() + local current_index = get_current_test_index(current_buf) + if not current_index then + return + end + + local pair = edit_state.test_buffers[current_index] + if vim.api.nvim_win_is_valid(pair.input_win) then + vim.api.nvim_win_close(pair.input_win, true) + end + if vim.api.nvim_win_is_valid(pair.expected_win) then + vim.api.nvim_win_close(pair.expected_win, true) + end + if vim.api.nvim_buf_is_valid(pair.input_buf) then + vim.api.nvim_buf_delete(pair.input_buf, { force = true }) + end + if vim.api.nvim_buf_is_valid(pair.expected_buf) then + vim.api.nvim_buf_delete(pair.expected_buf, { force = true }) + end + + table.remove(edit_state.test_buffers, current_index) + table.remove(edit_state.test_cases, current_index) + + for i = current_index, #edit_state.test_buffers do + load_test_into_buffer(i) + end + + local next_index = math.min(current_index, #edit_state.test_buffers) + jump_to_test(next_index) + + logger.log(('Deleted test %d'):format(current_index)) +end + +local function add_new_test() + if not edit_state then + return + end + + local last_pair = edit_state.test_buffers[#edit_state.test_buffers] + if not last_pair or not vim.api.nvim_win_is_valid(last_pair.input_win) then + return + end + + vim.api.nvim_set_current_win(last_pair.input_win) + vim.cmd.vsplit() + local input_win = vim.api.nvim_get_current_win() + local input_buf = utils.create_buffer_with_options() + vim.api.nvim_win_set_buf(input_win, input_buf) + vim.bo[input_buf].modifiable = true + vim.bo[input_buf].readonly = false + vim.bo[input_buf].buftype = 'nofile' + vim.bo[input_buf].buflisted = false + helpers.clearcol(input_buf) + + vim.api.nvim_set_current_win(last_pair.expected_win) + vim.cmd.vsplit() + local expected_win = vim.api.nvim_get_current_win() + local expected_buf = utils.create_buffer_with_options() + vim.api.nvim_win_set_buf(expected_win, expected_buf) + vim.bo[expected_buf].modifiable = true + vim.bo[expected_buf].readonly = false + vim.bo[expected_buf].buftype = 'nofile' + vim.bo[expected_buf].buflisted = false + helpers.clearcol(expected_buf) + + local new_index = #edit_state.test_buffers + 1 + local new_pair = { + input_buf = input_buf, + expected_buf = expected_buf, + input_win = input_win, + expected_win = expected_win, + } + table.insert(edit_state.test_buffers, new_pair) + table.insert(edit_state.test_cases, { index = new_index, input = '', expected = '' }) + + setup_keybindings(input_buf) + setup_keybindings(expected_buf) + load_test_into_buffer(new_index) + + vim.api.nvim_set_current_win(input_win) + logger.log(('Added test %d'):format(new_index)) +end + +---@param buf integer +setup_keybindings = function(buf) + local config = config_module.get_config() + local keys = config.ui.edit + + if keys.save_and_exit_key then + vim.keymap.set('n', keys.save_and_exit_key, function() + M.toggle_edit() + end, { buffer = buf, silent = true, desc = 'Save and exit test editor' }) + end + + if keys.next_test_key then + vim.keymap.set('n', keys.next_test_key, function() + navigate_test(1) + end, { buffer = buf, silent = true, desc = 'Next test' }) + end + + if keys.prev_test_key then + vim.keymap.set('n', keys.prev_test_key, function() + navigate_test(-1) + end, { buffer = buf, silent = true, desc = 'Previous test' }) + end + + if keys.delete_test_key then + vim.keymap.set( + 'n', + keys.delete_test_key, + delete_current_test, + { buffer = buf, silent = true, desc = 'Delete test' } + ) + end + + if keys.add_test_key then + vim.keymap.set( + 'n', + keys.add_test_key, + add_new_test, + { buffer = buf, silent = true, desc = 'Add test' } + ) + end +end + local function save_all_tests() if not edit_state then return From 4eb9c9a21fbd3d20088ff07c3f27b73bbf15a532 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 17:06:30 -0400 Subject: [PATCH 069/187] feat(docs): update readme by mentioning test case mgmt --- README.md | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 7130889..23b4df8 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ https://github.com/user-attachments/assets/50b19481-8e6d-47b4-bebc-15e16c61a9c9 - **Automatic problem setup**: Scrape test cases and metadata in seconds - **Dual view modes**: Lightweight I/O view for quick feedback, full panel for detailed analysis +- **Test case management**: Quickly view, edit, add, & remove test cases - **Rich test output**: 256 color ANSI support for compiler errors and program output - **Language agnostic**: Works with any language @@ -31,21 +32,20 @@ cp.nvim follows a simple principle: **solve locally, submit remotely**. ### Basic Usage -1. **Find a contest or problem** on the judge website -2. **Set up locally** with `:CP <platform> <contest>` +1. Find a contest or problem +2. Set up contests locally ``` :CP codeforces 1848 ``` -3. **Code and test** with instant feedback +3. Code and test ``` - :CP run " Quick verdict summary in splits - :CP panel " Detailed analysis with diffs + :CP run ``` -4. **Navigate between problems** +4. Navigate between problems ``` :CP next @@ -53,7 +53,14 @@ cp.nvim follows a simple principle: **solve locally, submit remotely**. :CP e1 ``` -5. **Submit** on the original website +5. Debug and edit test cases + +``` +:CP edit +:CP panel --debug +``` + +5. Submit on the original website ## Documentation From b978c3ed1352f713a295be71bc5ee0828fa487ae Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 17:07:49 -0400 Subject: [PATCH 070/187] fix(docs): site readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 23b4df8..ef94df0 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ cp.nvim follows a simple principle: **solve locally, submit remotely**. See [my config](https://github.com/barrett-ruth/dots/blob/main/nvim/lua/plugins/cp.lua) -for a relatively advanced setup. +for the setup in the video shown above. ## Similar Projects From 8345d147cfa7a558f2d112165f7f62594dbc42ce Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 21:31:03 -0400 Subject: [PATCH 071/187] fix(ui): remove extra line from test cases --- lua/cp/ui/views.lua | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lua/cp/ui/views.lua b/lua/cp/ui/views.lua index ab7a407..4cdc8d6 100644 --- a/lua/cp/ui/views.lua +++ b/lua/cp/ui/views.lua @@ -445,9 +445,6 @@ function M.run_io_view(test_index, debug) table.insert(output_lines, line) end end - if idx < #test_indices then - table.insert(output_lines, '') - end local status = run_render.get_status_info(tc) @@ -485,9 +482,6 @@ function M.run_io_view(test_index, debug) for _, line in ipairs(vim.split(tc.input, '\n')) do table.insert(input_lines, line) end - if idx < #test_indices then - table.insert(input_lines, '') - end end if #output_lines > 0 and #verdict_lines > 0 then From 9b90e3a452c153f273765cb60f704c3082e9850d Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Fri, 24 Oct 2025 21:40:13 -0400 Subject: [PATCH 072/187] feat(ui): close all buffers on edit --- README.md | 2 +- lua/cp/ui/edit.lua | 30 +++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fec275a..5d6088c 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Scrape problems, run tests, and debug solutions across multiple platforms with zero configuration. -https://github.com/user-attachments/assets/2f01db4a-718a-482b-89c0-e841d37a63b4 +https://github.com/user-attachments/assets/956ec4c4-5ef1-4391-abea-3a51fa771809 ## Features diff --git a/lua/cp/ui/edit.lua b/lua/cp/ui/edit.lua index ada41bb..a041ad4 100644 --- a/lua/cp/ui/edit.lua +++ b/lua/cp/ui/edit.lua @@ -90,7 +90,7 @@ local function delete_current_test() return end if #edit_state.test_buffers == 1 then - logger.log('Cannot have 0 problem tests.', vim.log.levels.ERROR) + logger.log('Problems must have at least one test case.', vim.log.levels.ERROR) return end @@ -217,6 +217,32 @@ setup_keybindings = function(buf) { buffer = buf, silent = true, desc = 'Add test' } ) end + + local augroup = vim.api.nvim_create_augroup('cp_edit_guard', { clear = false }) + vim.api.nvim_create_autocmd({ 'BufDelete', 'BufWipeout' }, { + group = augroup, + buffer = buf, + callback = function() + vim.schedule(function() + if not edit_state then + return + end + + local is_tracked = false + for _, pair in ipairs(edit_state.test_buffers) do + if pair.input_buf == buf or pair.expected_buf == buf then + is_tracked = true + break + end + end + + if is_tracked then + logger.log('Test buffer closed unexpectedly. Exiting editor.', vim.log.levels.WARN) + M.toggle_edit() + end + end) + end, + }) end local function save_all_tests() @@ -279,6 +305,8 @@ function M.toggle_edit(test_index) save_all_tests() edit_state = nil + pcall(vim.api.nvim_clear_autocmds, { group = 'cp_edit_guard' }) + local saved = state.get_saved_session() if saved then vim.fn.delete(saved) From 2fda5a74ca9d560b68f10765a842c01147f99afe Mon Sep 17 00:00:00 2001 From: Barrett Ruth <barrett.ruth@ramp.com> Date: Sat, 25 Oct 2025 00:26:33 -0400 Subject: [PATCH 073/187] feat: codechef --- .busted | 13 - .github/workflows/test.yaml | 15 - README.md | 3 +- lua/cp/constants.lua | 3 +- pyproject.toml | 1 + scrapers/codechef.py | 280 + spec/execute_spec.lua | 11 - tests/conftest.py | 52 +- tests/fixtures/codechef_P1209.html | 4343 ++++++++++++ tests/fixtures/codechef_P2209.html | 5754 ++++++++++++++++ tests/fixtures/codechef_P3209.html | 5101 +++++++++++++++ tests/fixtures/codechef_P4209.html | 5940 +++++++++++++++++ tests/fixtures/codechef_P5209.html | 6175 ++++++++++++++++++ tests/fixtures/codechef_START209D.json | 202 + tests/fixtures/codechef_START209D_P1209.json | 99 + tests/fixtures/codechef_START209D_P2209.json | 85 + tests/fixtures/codechef_START209D_P3209.json | 85 + tests/fixtures/codechef_START209D_P4209.json | 85 + tests/fixtures/codechef_START209D_P5209.json | 85 + tests/fixtures/codechef_contests.json | 330 + tests/test_scrapers.py | 5 + uv.lock | 30 +- 22 files changed, 28652 insertions(+), 45 deletions(-) delete mode 100644 .busted create mode 100644 scrapers/codechef.py delete mode 100644 spec/execute_spec.lua create mode 100644 tests/fixtures/codechef_P1209.html create mode 100644 tests/fixtures/codechef_P2209.html create mode 100644 tests/fixtures/codechef_P3209.html create mode 100644 tests/fixtures/codechef_P4209.html create mode 100644 tests/fixtures/codechef_P5209.html create mode 100644 tests/fixtures/codechef_START209D.json create mode 100644 tests/fixtures/codechef_START209D_P1209.json create mode 100644 tests/fixtures/codechef_START209D_P2209.json create mode 100644 tests/fixtures/codechef_START209D_P3209.json create mode 100644 tests/fixtures/codechef_START209D_P4209.json create mode 100644 tests/fixtures/codechef_START209D_P5209.json create mode 100644 tests/fixtures/codechef_contests.json diff --git a/.busted b/.busted deleted file mode 100644 index f4945a0..0000000 --- a/.busted +++ /dev/null @@ -1,13 +0,0 @@ -return { - _all = { - coverage = false, - lpath = 'lua/?.lua;lua/?/init.lua', - lua = 'nlua', - }, - default = { - verbose = true, - }, - tests = { - verbose = true, - }, -} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 731ad4f..4c1cc1f 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -35,21 +35,6 @@ jobs: - 'pyproject.toml' - 'uv.lock' - lua-test: - name: Lua Tests (${{ matrix.neovim_version }}) - runs-on: ubuntu-latest - needs: changes - if: ${{ needs.changes.outputs.lua == 'true' }} - strategy: - matrix: - neovim_version: ['stable', 'nightly'] - steps: - - uses: actions/checkout@v4 - - name: Run Lua tests - uses: nvim-neorocks/nvim-busted-action@v1 - with: - nvim_version: ${{ matrix.neovim_version }} - python-test: name: Python Tests runs-on: ubuntu-latest diff --git a/README.md b/README.md index 5d6088c..a0dd3ce 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,7 @@ https://github.com/user-attachments/assets/956ec4c4-5ef1-4391-abea-3a51fa771809 ## Features -- **Multi-platform support**: AtCoder, Codeforces, CSES with consistent - interface +- **Multi-platform support**: AtCoder, CodeChef, Codeforces, and CSES - **Automatic problem setup**: Scrape test cases and metadata in seconds - **Dual view modes**: Lightweight I/O view for quick feedback, full panel for detailed analysis diff --git a/lua/cp/constants.lua b/lua/cp/constants.lua index 9d1f0cc..7bdaa16 100644 --- a/lua/cp/constants.lua +++ b/lua/cp/constants.lua @@ -1,10 +1,11 @@ local M = {} -M.PLATFORMS = { 'atcoder', 'codeforces', 'cses' } +M.PLATFORMS = { 'atcoder', 'codechef', 'codeforces', 'cses' } M.ACTIONS = { 'run', 'panel', 'next', 'prev', 'pick', 'cache', 'interact', 'edit' } M.PLATFORM_DISPLAY_NAMES = { atcoder = 'AtCoder', + codechef = 'CodeChef', codeforces = 'CodeForces', cses = 'CSES', } diff --git a/pyproject.toml b/pyproject.toml index b114d87..1e09ca4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ dev = [ "pytest-mock>=3.12.0", "pre-commit>=4.3.0", "basedpyright>=1.31.6", + "ruff>=0.14.2", ] [tool.pytest.ini_options] diff --git a/scrapers/codechef.py b/scrapers/codechef.py new file mode 100644 index 0000000..96d4cac --- /dev/null +++ b/scrapers/codechef.py @@ -0,0 +1,280 @@ +#!/usr/bin/env python3 + +import asyncio +import json +import re +import sys +from typing import Any + +import httpx +from scrapling.fetchers import StealthyFetcher + +from .base import BaseScraper +from .models import ( + ContestListResult, + ContestSummary, + MetadataResult, + ProblemSummary, + TestCase, + TestsResult, +) + +BASE_URL = "https://www.codechef.com" +API_CONTESTS_ALL = "/api/list/contests/all" +API_CONTEST = "/api/contests/{contest_id}" +API_PROBLEM = "/api/contests/{contest_id}/problems/{problem_id}" +PROBLEM_URL = "https://www.codechef.com/problems/{problem_id}" + +HEADERS = { + "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" +} +TIMEOUT_S = 15.0 +CONNECTIONS = 8 + +MEMORY_LIMIT_RE = re.compile(r"Memory\s+[Ll]imit[:\s]+([0-9.]+)\s*MB", re.IGNORECASE) + + +async def fetch_json(client: httpx.AsyncClient, path: str) -> dict: + r = await client.get(BASE_URL + path, headers=HEADERS, timeout=TIMEOUT_S) + r.raise_for_status() + return r.json() + + +def _extract_memory_limit(html: str) -> float: + m = MEMORY_LIMIT_RE.search(html) + return float(m.group(1)) if m else 256.0 + + +def _fetch_html_sync(url: str) -> str: + response = StealthyFetcher.fetch(url, headless=True, network_idle=True) + return str(response.body) + + +def get_div4_contest_id(contest_id: str) -> str: + return f"{contest_id}D" + + +class CodeChefScraper(BaseScraper): + @property + def platform_name(self) -> str: + return "codechef" + + async def scrape_contest_metadata(self, contest_id: str) -> MetadataResult: + div4_id = get_div4_contest_id(contest_id) + async with httpx.AsyncClient() as client: + try: + data = await fetch_json(client, API_CONTEST.format(contest_id=div4_id)) + except httpx.HTTPStatusError as e: + return self._create_metadata_error( + f"Failed to fetch contest {contest_id}: {e}", contest_id + ) + + if not data.get("problems"): + return self._create_metadata_error( + f"No problems found for contest {contest_id}", contest_id + ) + + problems = [] + for problem_code, problem_data in data["problems"].items(): + problems.append( + ProblemSummary( + id=problem_code, + name=problem_data.get("name", problem_code), + ) + ) + + return MetadataResult( + success=True, + error="", + contest_id=contest_id, + problems=problems, + url=f"{BASE_URL}/{contest_id}", + ) + + async def scrape_contest_list(self) -> ContestListResult: + async with httpx.AsyncClient() as client: + try: + data = await fetch_json(client, API_CONTESTS_ALL) + except httpx.HTTPStatusError as e: + return self._create_contests_error(f"Failed to fetch contests: {e}") + + all_contests = data.get("future_contests", []) + data.get("past_contests", []) + + max_num = 0 + contest_names = {} + + for contest in all_contests: + contest_code = contest.get("contest_code", "") + if contest_code.startswith("START"): + match = re.match(r"START(\d+)", contest_code) + if match: + num = int(match.group(1)) + max_num = max(max_num, num) + contest_names[contest_code] = contest.get( + "contest_name", contest_code + ) + + if max_num == 0: + return self._create_contests_error("No Starters contests found") + + contests = [] + for i in range(1, max_num + 1): + contest_id = f"START{i}" + name = contest_names.get(contest_id, f"Starters {i}") + contests.append( + ContestSummary( + id=contest_id, + name=name, + display_name=name, + ) + ) + + return ContestListResult(success=True, error="", contests=contests) + + async def stream_tests_for_category_async(self, contest_id: str) -> None: + div4_id = get_div4_contest_id(contest_id) + + async with httpx.AsyncClient( + limits=httpx.Limits(max_connections=CONNECTIONS) + ) as client: + try: + contest_data = await fetch_json( + client, API_CONTEST.format(contest_id=div4_id) + ) + except Exception: + return + + problems = contest_data.get("problems", {}) + if not problems: + return + + sem = asyncio.Semaphore(CONNECTIONS) + + async def run_one(problem_code: str) -> dict[str, Any]: + async with sem: + try: + problem_data = await fetch_json( + client, + API_PROBLEM.format( + contest_id=div4_id, problem_id=problem_code + ), + ) + + sample_tests = ( + problem_data.get("problemComponents", {}).get( + "sampleTestCases", [] + ) + or [] + ) + tests = [ + TestCase( + input=t.get("input", "").strip(), + expected=t.get("output", "").strip(), + ) + for t in sample_tests + if not t.get("isDeleted", False) + ] + + time_limit_str = problem_data.get("max_timelimit", "1") + timeout_ms = int(float(time_limit_str) * 1000) + + problem_url = PROBLEM_URL.format(problem_id=problem_code) + loop = asyncio.get_event_loop() + html = await loop.run_in_executor( + None, _fetch_html_sync, problem_url + ) + memory_mb = _extract_memory_limit(html) + + interactive = False + + except Exception: + tests = [] + timeout_ms = 1000 + memory_mb = 256.0 + interactive = False + + return { + "problem_id": problem_code, + "tests": [ + {"input": t.input, "expected": t.expected} for t in tests + ], + "timeout_ms": timeout_ms, + "memory_mb": memory_mb, + "interactive": interactive, + } + + tasks = [run_one(problem_code) for problem_code in problems.keys()] + for coro in asyncio.as_completed(tasks): + payload = await coro + print(json.dumps(payload), flush=True) + + +async def main_async() -> int: + if len(sys.argv) < 2: + result = MetadataResult( + success=False, + error="Usage: codechef.py metadata <contest_id> OR codechef.py tests <contest_id> OR codechef.py contests", + url="", + ) + print(result.model_dump_json()) + return 1 + + mode: str = sys.argv[1] + scraper = CodeChefScraper() + + if mode == "metadata": + if len(sys.argv) != 3: + result = MetadataResult( + success=False, + error="Usage: codechef.py metadata <contest_id>", + url="", + ) + print(result.model_dump_json()) + return 1 + contest_id = sys.argv[2] + result = await scraper.scrape_contest_metadata(contest_id) + print(result.model_dump_json()) + return 0 if result.success else 1 + + if mode == "tests": + if len(sys.argv) != 3: + tests_result = TestsResult( + success=False, + error="Usage: codechef.py tests <contest_id>", + problem_id="", + tests=[], + timeout_ms=0, + memory_mb=0, + ) + print(tests_result.model_dump_json()) + return 1 + contest_id = sys.argv[2] + await scraper.stream_tests_for_category_async(contest_id) + return 0 + + if mode == "contests": + if len(sys.argv) != 2: + contest_result = ContestListResult( + success=False, error="Usage: codechef.py contests" + ) + print(contest_result.model_dump_json()) + return 1 + contest_result = await scraper.scrape_contest_list() + print(contest_result.model_dump_json()) + return 0 if contest_result.success else 1 + + result = MetadataResult( + success=False, + error=f"Unknown mode: {mode}. Use 'metadata <contest_id>', 'tests <contest_id>', or 'contests'", + url="", + ) + print(result.model_dump_json()) + return 1 + + +def main() -> None: + sys.exit(asyncio.run(main_async())) + + +if __name__ == "__main__": + main() diff --git a/spec/execute_spec.lua b/spec/execute_spec.lua deleted file mode 100644 index 12d85d2..0000000 --- a/spec/execute_spec.lua +++ /dev/null @@ -1,11 +0,0 @@ -describe('run module', function() - local run = require('cp.runner.run') - - describe('basic functionality', function() - it('can get panel state', function() - local state = run.get_panel_state() - assert.is_table(state) - assert.is_table(state.test_cases) - end) - end) -end) diff --git a/tests/conftest.py b/tests/conftest.py index dfd8e7c..5970960 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -136,12 +136,12 @@ def run_scraper_offline(fixture_text): case "codeforces": - class MockPage: + class MockCodeForcesPage: def __init__(self, html: str): self.html_content = html def _mock_stealthy_fetch(url: str, **kwargs): - return MockPage(_router_codeforces(url=url)) + return MockCodeForcesPage(_router_codeforces(url=url)) def _mock_requests_get(url: str, **kwargs): if "api/contest.list" in url: @@ -176,6 +176,51 @@ def run_scraper_offline(fixture_text): "requests.get": _mock_requests_get, } + case "codechef": + + class MockResponse: + def __init__(self, json_data): + self._json_data = json_data + self.status_code = 200 + + def json(self): + return self._json_data + + def raise_for_status(self): + pass + + async def __offline_get_async(client, url: str, **kwargs): + if "/api/list/contests/all" in url: + data = json.loads(fixture_text("codechef_contests.json")) + return MockResponse(data) + if "/api/contests/START209D" in url and "/problems/" not in url: + data = json.loads(fixture_text("codechef_START209D.json")) + return MockResponse(data) + if "/api/contests/START209D/problems/" in url: + problem_id = url.rstrip("/").split("/")[-1] + data = json.loads( + fixture_text(f"codechef_START209D_{problem_id}.json") + ) + return MockResponse(data) + raise AssertionError(f"No fixture for CodeChef url={url!r}") + + class MockCodeChefPage: + def __init__(self, html: str): + self.body = html + self.status = 200 + + def _mock_stealthy_fetch(url: str, **kwargs): + if "/problems/" in url: + problem_id = url.rstrip("/").split("/")[-1] + html = fixture_text(f"codechef_{problem_id}.html") + return MockCodeChefPage(html) + raise AssertionError(f"No fixture for CodeChef url={url!r}") + + return { + "__offline_get_async": __offline_get_async, + "StealthyFetcher.fetch": _mock_stealthy_fetch, + } + case _: raise AssertionError(f"Unknown scraper: {scraper_name}") @@ -192,6 +237,9 @@ def run_scraper_offline(fixture_text): ns._get_async = offline_fetches["_get_async"] elif scraper_name == "cses": httpx.AsyncClient.get = offline_fetches["__offline_fetch_text"] # type: ignore[assignment] + elif scraper_name == "codechef": + httpx.AsyncClient.get = offline_fetches["__offline_get_async"] # type: ignore[assignment] + fetchers.StealthyFetcher.fetch = offline_fetches["StealthyFetcher.fetch"] # type: ignore[assignment] main_async = getattr(ns, "main_async") assert callable(main_async), f"main_async not found in {scraper_name}" diff --git a/tests/fixtures/codechef_P1209.html b/tests/fixtures/codechef_P1209.html new file mode 100644 index 0000000..2ab7eb3 --- /dev/null +++ b/tests/fixtures/codechef_P1209.html @@ -0,0 +1,4343 @@ +<!doctype html> +<html lang="en"> + <head> + <style id="ace-tomorrow-night"> + .ace-tomorrow-night .ace_gutter { + background: #25282c; + color: #c5c8c6; + } + .ace-tomorrow-night .ace_print-margin { + width: 1px; + background: #25282c; + } + .ace-tomorrow-night { + background-color: #1d1f21; + color: #c5c8c6; + } + .ace-tomorrow-night .ace_cursor { + color: #aeafad; + } + .ace-tomorrow-night .ace_marker-layer .ace_selection { + background: #373b41; + } + .ace-tomorrow-night.ace_multiselect .ace_selection.ace_start { + box-shadow: 0 0 3px 0px #1d1f21; + } + .ace-tomorrow-night .ace_marker-layer .ace_step { + background: rgb(102, 82, 0); + } + .ace-tomorrow-night .ace_marker-layer .ace_bracket { + margin: -1px 0 0 -1px; + border: 1px solid #4b4e55; + } + .ace-tomorrow-night .ace_marker-layer .ace_active-line { + background: #282a2e; + } + .ace-tomorrow-night .ace_gutter-active-line { + background-color: #282a2e; + } + .ace-tomorrow-night .ace_marker-layer .ace_selected-word { + border: 1px solid #373b41; + } + .ace-tomorrow-night .ace_invisible { + color: #4b4e55; + } + .ace-tomorrow-night .ace_keyword, + .ace-tomorrow-night .ace_meta, + .ace-tomorrow-night .ace_storage, + .ace-tomorrow-night .ace_storage.ace_type, + .ace-tomorrow-night .ace_support.ace_type { + color: #b294bb; + } + .ace-tomorrow-night .ace_keyword.ace_operator { + color: #8abeb7; + } + .ace-tomorrow-night .ace_constant.ace_character, + .ace-tomorrow-night .ace_constant.ace_language, + .ace-tomorrow-night .ace_constant.ace_numeric, + .ace-tomorrow-night .ace_keyword.ace_other.ace_unit, + .ace-tomorrow-night .ace_support.ace_constant, + .ace-tomorrow-night .ace_variable.ace_parameter { + color: #de935f; + } + .ace-tomorrow-night .ace_constant.ace_other { + color: #ced1cf; + } + .ace-tomorrow-night .ace_invalid { + color: #ced2cf; + background-color: #df5f5f; + } + .ace-tomorrow-night .ace_invalid.ace_deprecated { + color: #ced2cf; + background-color: #b798bf; + } + .ace-tomorrow-night .ace_fold { + background-color: #81a2be; + border-color: #c5c8c6; + } + .ace-tomorrow-night .ace_entity.ace_name.ace_function, + .ace-tomorrow-night .ace_support.ace_function, + .ace-tomorrow-night .ace_variable { + color: #81a2be; + } + .ace-tomorrow-night .ace_support.ace_class, + .ace-tomorrow-night .ace_support.ace_type { + color: #f0c674; + } + .ace-tomorrow-night .ace_heading, + .ace-tomorrow-night .ace_markup.ace_heading, + .ace-tomorrow-night .ace_string { + color: #b5bd68; + } + .ace-tomorrow-night .ace_entity.ace_name.ace_tag, + .ace-tomorrow-night .ace_entity.ace_other.ace_attribute-name, + .ace-tomorrow-night .ace_meta.ace_tag, + .ace-tomorrow-night .ace_string.ace_regexp, + .ace-tomorrow-night .ace_variable { + color: #cc6666; + } + .ace-tomorrow-night .ace_comment { + color: #969896; + } + .ace-tomorrow-night .ace_indent-guide { + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYHB3d/8PAAOIAdULw8qMAAAAAElFTkSuQmCC) + right repeat-y; + } + /*# sourceURL=ace/css/ace-tomorrow-night */ + </style> + <style id="autocompletion.css"> + .ace_editor.ace_autocomplete .ace_marker-layer .ace_active-line { + background-color: #cad6fa; + z-index: 1; + } + .ace_dark.ace_editor.ace_autocomplete .ace_marker-layer .ace_active-line { + background-color: #3a674e; + } + .ace_editor.ace_autocomplete .ace_line-hover { + border: 1px solid #abbffe; + margin-top: -1px; + background: rgba(233, 233, 253, 0.4); + position: absolute; + z-index: 2; + } + .ace_dark.ace_editor.ace_autocomplete .ace_line-hover { + border: 1px solid rgba(109, 150, 13, 0.8); + background: rgba(58, 103, 78, 0.62); + } + .ace_completion-meta { + opacity: 0.5; + margin-left: 0.9em; + } + .ace_completion-message { + margin-left: 0.9em; + color: blue; + } + .ace_editor.ace_autocomplete .ace_completion-highlight { + color: #2d69c7; + } + .ace_dark.ace_editor.ace_autocomplete .ace_completion-highlight { + color: #93ca12; + } + .ace_editor.ace_autocomplete { + width: 300px; + z-index: 200000; + border: 1px lightgray solid; + position: fixed; + box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2); + line-height: 1.4; + background: #fefefe; + color: #111; + } + .ace_dark.ace_editor.ace_autocomplete { + border: 1px #484747 solid; + box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.51); + line-height: 1.4; + background: #25282c; + color: #c1c1c1; + } + .ace_autocomplete .ace_text-layer { + width: calc(100% - 8px); + } + .ace_autocomplete .ace_line { + display: flex; + align-items: center; + } + .ace_autocomplete .ace_line > * { + min-width: 0; + flex: 0 0 auto; + } + .ace_autocomplete .ace_line .ace_ { + flex: 0 1 auto; + overflow: hidden; + text-overflow: ellipsis; + } + .ace_autocomplete .ace_completion-spacer { + flex: 1; + } + .ace_autocomplete.ace_loading:after { + content: ''; + position: absolute; + top: 0px; + height: 2px; + width: 8%; + background: blue; + z-index: 100; + animation: ace_progress 3s infinite linear; + animation-delay: 300ms; + transform: translateX(-100%) scaleX(1); + } + @keyframes ace_progress { + 0% { + transform: translateX(-100%) scaleX(1); + } + 50% { + transform: translateX(625%) scaleX(2); + } + 100% { + transform: translateX(1500%) scaleX(3); + } + } + @media (prefers-reduced-motion) { + .ace_autocomplete.ace_loading:after { + transform: translateX(625%) scaleX(2); + animation: none; + } + } + + /*# sourceURL=ace/css/autocompletion.css */ + </style> + <style id="snippets.css"> + .ace_snippet-marker { + -moz-box-sizing: border-box; + box-sizing: border-box; + background: rgba(194, 193, 208, 0.09); + border: 1px dotted rgba(211, 208, 235, 0.62); + position: absolute; + } + /*# sourceURL=ace/css/snippets.css */ + </style> + <style id="error_marker.css"> + .error_widget_wrapper { + background: inherit; + color: inherit; + border: none; + } + .error_widget { + border-top: solid 2px; + border-bottom: solid 2px; + margin: 5px 0; + padding: 10px 40px; + white-space: pre-wrap; + } + .error_widget.ace_error, + .error_widget_arrow.ace_error { + border-color: #ff5a5a; + } + .error_widget.ace_warning, + .error_widget_arrow.ace_warning { + border-color: #f1d817; + } + .error_widget.ace_info, + .error_widget_arrow.ace_info { + border-color: #5a5a5a; + } + .error_widget.ace_ok, + .error_widget_arrow.ace_ok { + border-color: #5aaa5a; + } + .error_widget_arrow { + position: absolute; + border: solid 5px; + border-top-color: transparent !important; + border-right-color: transparent !important; + border-left-color: transparent !important; + top: -5px; + } + + /*# sourceURL=ace/css/error_marker.css */ + </style> + <style id="ace-tm"> + .ace-tm .ace_gutter { + background: #f0f0f0; + color: #333; + } + + .ace-tm .ace_print-margin { + width: 1px; + background: #e8e8e8; + } + + .ace-tm .ace_fold { + background-color: #6b72e6; + } + + .ace-tm { + background-color: #ffffff; + color: black; + } + + .ace-tm .ace_cursor { + color: black; + } + + .ace-tm .ace_invisible { + color: rgb(191, 191, 191); + } + + .ace-tm .ace_storage, + .ace-tm .ace_keyword { + color: blue; + } + + .ace-tm .ace_constant { + color: rgb(197, 6, 11); + } + + .ace-tm .ace_constant.ace_buildin { + color: rgb(88, 72, 246); + } + + .ace-tm .ace_constant.ace_language { + color: rgb(88, 92, 246); + } + + .ace-tm .ace_constant.ace_library { + color: rgb(6, 150, 14); + } + + .ace-tm .ace_invalid { + background-color: rgba(255, 0, 0, 0.1); + color: red; + } + + .ace-tm .ace_support.ace_function { + color: rgb(60, 76, 114); + } + + .ace-tm .ace_support.ace_constant { + color: rgb(6, 150, 14); + } + + .ace-tm .ace_support.ace_type, + .ace-tm .ace_support.ace_class { + color: rgb(109, 121, 222); + } + + .ace-tm .ace_keyword.ace_operator { + color: rgb(104, 118, 135); + } + + .ace-tm .ace_string { + color: rgb(3, 106, 7); + } + + .ace-tm .ace_comment { + color: rgb(76, 136, 107); + } + + .ace-tm .ace_comment.ace_doc { + color: rgb(0, 102, 255); + } + + .ace-tm .ace_comment.ace_doc.ace_tag { + color: rgb(128, 159, 191); + } + + .ace-tm .ace_constant.ace_numeric { + color: rgb(0, 0, 205); + } + + .ace-tm .ace_variable { + color: rgb(49, 132, 149); + } + + .ace-tm .ace_xml-pe { + color: rgb(104, 104, 91); + } + + .ace-tm .ace_entity.ace_name.ace_function { + color: #0000a2; + } + + .ace-tm .ace_heading { + color: rgb(12, 7, 255); + } + + .ace-tm .ace_list { + color: rgb(185, 6, 144); + } + + .ace-tm .ace_meta.ace_tag { + color: rgb(0, 22, 142); + } + + .ace-tm .ace_string.ace_regex { + color: rgb(255, 0, 0); + } + + .ace-tm .ace_marker-layer .ace_selection { + background: rgb(181, 213, 255); + } + .ace-tm.ace_multiselect .ace_selection.ace_start { + box-shadow: 0 0 3px 0px white; + } + .ace-tm .ace_marker-layer .ace_step { + background: rgb(252, 255, 0); + } + + .ace-tm .ace_marker-layer .ace_stack { + background: rgb(164, 229, 101); + } + + .ace-tm .ace_marker-layer .ace_bracket { + margin: -1px 0 0 -1px; + border: 1px solid rgb(192, 192, 192); + } + + .ace-tm .ace_marker-layer .ace_active-line { + background: rgba(0, 0, 0, 0.07); + } + + .ace-tm .ace_gutter-active-line { + background-color: #dcdcdc; + } + + .ace-tm .ace_marker-layer .ace_selected-word { + background: rgb(250, 250, 255); + border: 1px solid rgb(200, 200, 250); + } + + .ace-tm .ace_indent-guide { + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==') + right repeat-y; + } + + .ace-tm .ace_indent-guide-active { + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC') + right repeat-y; + } + + /*# sourceURL=ace/css/ace-tm */ + </style> + <style id="ace_editor.css"> + .ace_br1 { + border-top-left-radius: 3px; + } + .ace_br2 { + border-top-right-radius: 3px; + } + .ace_br3 { + border-top-left-radius: 3px; + border-top-right-radius: 3px; + } + .ace_br4 { + border-bottom-right-radius: 3px; + } + .ace_br5 { + border-top-left-radius: 3px; + border-bottom-right-radius: 3px; + } + .ace_br6 { + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + } + .ace_br7 { + border-top-left-radius: 3px; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + } + .ace_br8 { + border-bottom-left-radius: 3px; + } + .ace_br9 { + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; + } + .ace_br10 { + border-top-right-radius: 3px; + border-bottom-left-radius: 3px; + } + .ace_br11 { + border-top-left-radius: 3px; + border-top-right-radius: 3px; + border-bottom-left-radius: 3px; + } + .ace_br12 { + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; + } + .ace_br13 { + border-top-left-radius: 3px; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; + } + .ace_br14 { + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; + } + .ace_br15 { + border-top-left-radius: 3px; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; + } + + .ace_editor { + position: relative; + overflow: hidden; + padding: 0; + font: + 12px / normal 'Monaco', + 'Menlo', + 'Ubuntu Mono', + 'Consolas', + 'Source Code Pro', + 'source-code-pro', + monospace; + direction: ltr; + text-align: left; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + forced-color-adjust: none; + } + + .ace_scroller { + position: absolute; + overflow: hidden; + top: 0; + bottom: 0; + background-color: inherit; + -ms-user-select: none; + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; + cursor: text; + } + + .ace_content { + position: absolute; + box-sizing: border-box; + min-width: 100%; + contain: style size layout; + font-variant-ligatures: no-common-ligatures; + } + .ace_invisible { + font-variant-ligatures: none; + } + + .ace_keyboard-focus:focus { + box-shadow: inset 0 0 0 2px #5e9ed6; + outline: none; + } + + .ace_dragging .ace_scroller:before { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + content: ''; + background: rgba(250, 250, 250, 0.01); + z-index: 1000; + } + .ace_dragging.ace_dark .ace_scroller:before { + background: rgba(0, 0, 0, 0.01); + } + + .ace_gutter { + position: absolute; + overflow: hidden; + width: auto; + top: 0; + bottom: 0; + left: 0; + cursor: default; + z-index: 4; + -ms-user-select: none; + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; + contain: style size layout; + } + + .ace_gutter-active-line { + position: absolute; + left: 0; + right: 0; + } + + .ace_scroller.ace_scroll-left:after { + content: ''; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset; + pointer-events: none; + } + + .ace_gutter-cell, + .ace_gutter-cell_svg-icons { + position: absolute; + top: 0; + left: 0; + right: 0; + padding-left: 19px; + padding-right: 6px; + background-repeat: no-repeat; + } + + .ace_gutter-cell_svg-icons .ace_gutter_annotation { + margin-left: -14px; + float: left; + } + + .ace_gutter-cell .ace_gutter_annotation { + margin-left: -19px; + float: left; + } + + .ace_gutter-cell.ace_error, + .ace_icon.ace_error, + .ace_icon.ace_error_fold, + .ace_gutter-cell.ace_security, + .ace_icon.ace_security, + .ace_icon.ace_security_fold { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABOFBMVEX/////////QRswFAb/Ui4wFAYwFAYwFAaWGAfDRymzOSH/PxswFAb/SiUwFAYwFAbUPRvjQiDllog5HhHdRybsTi3/Tyv9Tir+Syj/UC3////XurebMBIwFAb/RSHbPx/gUzfdwL3kzMivKBAwFAbbvbnhPx66NhowFAYwFAaZJg8wFAaxKBDZurf/RB6mMxb/SCMwFAYwFAbxQB3+RB4wFAb/Qhy4Oh+4QifbNRcwFAYwFAYwFAb/QRzdNhgwFAYwFAbav7v/Uy7oaE68MBK5LxLewr/r2NXewLswFAaxJw4wFAbkPRy2PyYwFAaxKhLm1tMwFAazPiQwFAaUGAb/QBrfOx3bvrv/VC/maE4wFAbRPBq6MRO8Qynew8Dp2tjfwb0wFAbx6eju5+by6uns4uH9/f36+vr/GkHjAAAAYnRSTlMAGt+64rnWu/bo8eAA4InH3+DwoN7j4eLi4xP99Nfg4+b+/u9B/eDs1MD1mO7+4PHg2MXa347g7vDizMLN4eG+Pv7i5evs/v79yu7S3/DV7/498Yv24eH+4ufQ3Ozu/v7+y13sRqwAAADLSURBVHjaZc/XDsFgGIBhtDrshlitmk2IrbHFqL2pvXf/+78DPokj7+Fz9qpU/9UXJIlhmPaTaQ6QPaz0mm+5gwkgovcV6GZzd5JtCQwgsxoHOvJO15kleRLAnMgHFIESUEPmawB9ngmelTtipwwfASilxOLyiV5UVUyVAfbG0cCPHig+GBkzAENHS0AstVF6bacZIOzgLmxsHbt2OecNgJC83JERmePUYq8ARGkJx6XtFsdddBQgZE2nPR6CICZhawjA4Fb/chv+399kfR+MMMDGOQAAAABJRU5ErkJggg=='); + background-repeat: no-repeat; + background-position: 2px center; + } + + .ace_gutter-cell.ace_warning, + .ace_icon.ace_warning, + .ace_icon.ace_warning_fold { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAmVBMVEX///8AAAD///8AAAAAAABPSzb/5sAAAAB/blH/73z/ulkAAAAAAAD85pkAAAAAAAACAgP/vGz/rkDerGbGrV7/pkQICAf////e0IsAAAD/oED/qTvhrnUAAAD/yHD/njcAAADuv2r/nz//oTj/p064oGf/zHAAAAA9Nir/tFIAAAD/tlTiuWf/tkIAAACynXEAAAAAAAAtIRW7zBpBAAAAM3RSTlMAABR1m7RXO8Ln31Z36zT+neXe5OzooRDfn+TZ4p3h2hTf4t3k3ucyrN1K5+Xaks52Sfs9CXgrAAAAjklEQVR42o3PbQ+CIBQFYEwboPhSYgoYunIqqLn6/z8uYdH8Vmdnu9vz4WwXgN/xTPRD2+sgOcZjsge/whXZgUaYYvT8QnuJaUrjrHUQreGczuEafQCO/SJTufTbroWsPgsllVhq3wJEk2jUSzX3CUEDJC84707djRc5MTAQxoLgupWRwW6UB5fS++NV8AbOZgnsC7BpEAAAAABJRU5ErkJggg=='); + background-repeat: no-repeat; + background-position: 2px center; + } + + .ace_gutter-cell.ace_info, + .ace_icon.ace_info, + .ace_gutter-cell.ace_hint, + .ace_icon.ace_hint { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAJ0Uk5TAAB2k804AAAAPklEQVQY02NgIB68QuO3tiLznjAwpKTgNyDbMegwisCHZUETUZV0ZqOquBpXj2rtnpSJT1AEnnRmL2OgGgAAIKkRQap2htgAAAAASUVORK5CYII='); + background-repeat: no-repeat; + background-position: 2px center; + } + + .ace_dark .ace_gutter-cell.ace_info, + .ace_dark .ace_icon.ace_info, + .ace_dark .ace_gutter-cell.ace_hint, + .ace_dark .ace_icon.ace_hint { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAChoaGAgIAqKiq+vr6tra1ZWVmUlJSbm5s8PDxubm56enrdgzg3AAAAAXRSTlMAQObYZgAAAClJREFUeNpjYMAPdsMYHegyJZFQBlsUlMFVCWUYKkAZMxZAGdxlDMQBAG+TBP4B6RyJAAAAAElFTkSuQmCC'); + } + + .ace_icon_svg.ace_error { + -webkit-mask-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMCAxNiI+CjxnIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSJyZWQiIHNoYXBlLXJlbmRlcmluZz0iZ2VvbWV0cmljUHJlY2lzaW9uIj4KPGNpcmNsZSBmaWxsPSJub25lIiBjeD0iOCIgY3k9IjgiIHI9IjciIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPGxpbmUgeDE9IjExIiB5MT0iNSIgeDI9IjUiIHkyPSIxMSIvPgo8bGluZSB4MT0iMTEiIHkxPSIxMSIgeDI9IjUiIHkyPSI1Ii8+CjwvZz4KPC9zdmc+'); + background-color: crimson; + } + .ace_icon_svg.ace_security { + -webkit-mask-image: url('data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjAgMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgICA8ZyBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZT0iZGFya29yYW5nZSIgZmlsbD0ibm9uZSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iPgogICAgICAgIDxwYXRoIGNsYXNzPSJzdHJva2UtbGluZWpvaW4tcm91bmQiIGQ9Ik04IDE0LjgzMDdDOCAxNC44MzA3IDIgMTIuOTA0NyAyIDguMDg5OTJWMy4yNjU0OEM1LjMxIDMuMjY1NDggNy45ODk5OSAxLjM0OTE4IDcuOTg5OTkgMS4zNDkxOEM3Ljk4OTk5IDEuMzQ5MTggMTAuNjkgMy4yNjU0OCAxNCAzLjI2NTQ4VjguMDg5OTJDMTQgMTIuOTA0NyA4IDE0LjgzMDcgOCAxNC44MzA3WiIvPgogICAgICAgIDxwYXRoIGQ9Ik0yIDguMDg5OTJWMy4yNjU0OEM1LjMxIDMuMjY1NDggNy45ODk5OSAxLjM0OTE4IDcuOTg5OTkgMS4zNDkxOCIvPgogICAgICAgIDxwYXRoIGQ9Ik0xMy45OSA4LjA4OTkyVjMuMjY1NDhDMTAuNjggMy4yNjU0OCA4IDEuMzQ5MTggOCAxLjM0OTE4Ii8+CiAgICAgICAgPHBhdGggY2xhc3M9InN0cm9rZS1saW5lam9pbi1yb3VuZCIgZD0iTTggNFY5Ii8+CiAgICAgICAgPHBhdGggY2xhc3M9InN0cm9rZS1saW5lam9pbi1yb3VuZCIgZD0iTTggMTBWMTIiLz4KICAgIDwvZz4KPC9zdmc+'); + background-color: crimson; + } + .ace_icon_svg.ace_warning { + -webkit-mask-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMCAxNiI+CjxnIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSJkYXJrb3JhbmdlIiBzaGFwZS1yZW5kZXJpbmc9Imdlb21ldHJpY1ByZWNpc2lvbiI+Cjxwb2x5Z29uIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGZpbGw9Im5vbmUiIHBvaW50cz0iOCAxIDE1IDE1IDEgMTUgOCAxIi8+CjxyZWN0IHg9IjgiIHk9IjEyIiB3aWR0aD0iMC4wMSIgaGVpZ2h0PSIwLjAxIi8+CjxsaW5lIHgxPSI4IiB5MT0iNiIgeDI9IjgiIHkyPSIxMCIvPgo8L2c+Cjwvc3ZnPg=='); + background-color: darkorange; + } + .ace_icon_svg.ace_info { + -webkit-mask-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMCAxNiI+CjxnIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSJibHVlIiBzaGFwZS1yZW5kZXJpbmc9Imdlb21ldHJpY1ByZWNpc2lvbiI+CjxjaXJjbGUgZmlsbD0ibm9uZSIgY3g9IjgiIGN5PSI4IiByPSI3IiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+Cjxwb2x5bGluZSBwb2ludHM9IjggMTEgOCA4Ii8+Cjxwb2x5bGluZSBwb2ludHM9IjkgOCA2IDgiLz4KPGxpbmUgeDE9IjEwIiB5MT0iMTEiIHgyPSI2IiB5Mj0iMTEiLz4KPHJlY3QgeD0iOCIgeT0iNSIgd2lkdGg9IjAuMDEiIGhlaWdodD0iMC4wMSIvPgo8L2c+Cjwvc3ZnPg=='); + background-color: royalblue; + } + .ace_icon_svg.ace_hint { + -webkit-mask-image: url('data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjAgMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgICA8ZyBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZT0ic2lsdmVyIiBmaWxsPSJub25lIiBzaGFwZS1yZW5kZXJpbmc9Imdlb21ldHJpY1ByZWNpc2lvbiI+CiAgICAgICAgPHBhdGggY2xhc3M9InN0cm9rZS1saW5lam9pbi1yb3VuZCIgZD0iTTYgMTRIMTAiLz4KICAgICAgICA8cGF0aCBkPSJNOCAxMUg5QzkgOS40NzAwMiAxMiA4LjU0MDAyIDEyIDUuNzYwMDJDMTIuMDIgNC40MDAwMiAxMS4zOSAzLjM2MDAyIDEwLjQzIDIuNjcwMDJDOSAxLjY0MDAyIDcuMDAwMDEgMS42NDAwMiA1LjU3MDAxIDIuNjcwMDJDNC42MTAwMSAzLjM2MDAyIDMuOTggNC40MDAwMiA0IDUuNzYwMDJDNCA4LjU0MDAyIDcuMDAwMDEgOS40NzAwMiA3LjAwMDAxIDExSDhaIi8+CiAgICA8L2c+Cjwvc3ZnPg=='); + background-color: silver; + } + + .ace_icon_svg.ace_error_fold { + -webkit-mask-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMCAxNiIgZmlsbD0ibm9uZSI+CiAgPHBhdGggZD0ibSAxOC45Mjk4NTEsNy44Mjk4MDc2IGMgMC4xNDYzNTMsNi4zMzc0NjA0IC02LjMyMzE0Nyw3Ljc3Nzg0NDQgLTcuNDc3OTEyLDcuNzc3ODQ0NCAtMi4xMDcyNzI2LC0wLjEyODc1IDUuMTE3Njc4LDAuMzU2MjQ5IDUuMDUxNjk4LC03Ljg3MDA2MTggLTAuNjA0NjcyLC04LjAwMzk3MzQ5IC03LjA3NzI3MDYsLTcuNTYzMTE4OSAtNC44NTczLC03LjQzMDM5NTU2IDEuNjA2LC0wLjExNTE0MjI1IDYuODk3NDg1LDEuMjYyNTQ1OTYgNy4yODM1MTQsNy41MjI2MTI5NiB6IiBmaWxsPSJjcmltc29uIiBzdHJva2Utd2lkdGg9IjIiLz4KICA8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0ibSA4LjExNDc1NjIsMi4wNTI5ODI4IGMgMy4zNDkxNjk4LDAgNi4wNjQxMzI4LDIuNjc2ODYyNyA2LjA2NDEzMjgsNS45Nzg5NTMgMCwzLjMwMjExMjIgLTIuNzE0OTYzLDUuOTc4OTIwMiAtNi4wNjQxMzI4LDUuOTc4OTIwMiAtMy4zNDkxNDczLDAgLTYuMDY0MTc3MiwtMi42NzY4MDggLTYuMDY0MTc3MiwtNS45Nzg5MjAyIDAuMDA1MzksLTMuMjk5ODg2MSAyLjcxNzI2NTYsLTUuOTczNjQwOCA2LjA2NDE3NzIsLTUuOTc4OTUzIHogbSAwLC0xLjczNTgyNzE5IGMgLTQuMzIxNDgzNiwwIC03LjgyNDc0MDM4LDMuNDU0MDE4NDkgLTcuODI0NzQwMzgsNy43MTQ3ODAxOSAwLDQuMjYwNzI4MiAzLjUwMzI1Njc4LDcuNzE0NzQ1MiA3LjgyNDc0MDM4LDcuNzE0NzQ1MiA0LjMyMTQ0OTgsMCA3LjgyNDY5OTgsLTMuNDU0MDE3IDcuODI0Njk5OCwtNy43MTQ3NDUyIDAsLTIuMDQ2MDkxNCAtMC44MjQzOTIsLTQuMDA4MzY3MiAtMi4yOTE3NTYsLTUuNDU1MTc0NiBDIDEyLjE4MDIyNSwxLjEyOTk2NDggMTAuMTkwMDEzLDAuMzE3MTU1NjEgOC4xMTQ3NTYyLDAuMzE3MTU1NjEgWiBNIDYuOTM3NDU2Myw4LjI0MDU5ODUgNC42NzE4Njg1LDEwLjQ4NTg1MiA2LjAwODY4MTQsMTEuODc2NzI4IDguMzE3MDAzNSw5LjYwMDc5MTEgMTAuNjI1MzM3LDExLjg3NjcyOCAxMS45NjIxMzgsMTAuNDg1ODUyIDkuNjk2NTUwOCw4LjI0MDU5ODUgMTEuOTYyMTM4LDYuMDA2ODA2NiAxMC41NzMyNDYsNC42Mzc0MzM1IDguMzE3MDAzNSw2Ljg3MzQyOTcgNi4wNjA3NjA3LDQuNjM3NDMzNSA0LjY3MTg2ODUsNi4wMDY4MDY2IFoiIGZpbGw9ImNyaW1zb24iIHN0cm9rZS13aWR0aD0iMiIvPgo8L3N2Zz4='); + background-color: crimson; + } + .ace_icon_svg.ace_security_fold { + -webkit-mask-image: url('data:image/svg+xml;base64,CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTcgMTQiIGZpbGw9Im5vbmUiPgogICAgPHBhdGggZD0iTTEwLjAwMDEgMTMuNjk5MkMxMC4wMDAxIDEzLjY5OTIgMTEuOTI0MSAxMy40NzYzIDEzIDEyLjY5OTJDMTQuNDEzOSAxMS42NzgxIDE2IDEwLjUgMTYuMTI1MSA2LjgxMTI2VjIuNTg5ODdDMTYuMTI1MSAyLjU0NzY4IDE2LjEyMjEgMi41MDYxOSAxNi4xMTY0IDIuNDY1NTlWMS43MTQ4NUgxNS4yNDE0TDE1LjIzMDcgMS43MTQ4NEwxNC42MjUxIDEuNjk5MjJWNi44MTEyM0MxNC42MjUxIDguNTEwNjEgMTQuNjI1MSA5LjQ2NDYxIDEyLjc4MjQgMTEuNzIxQzEyLjE1ODYgMTIuNDg0OCAxMC4wMDAxIDEzLjY5OTIgMTAuMDAwMSAxMy42OTkyWiIgZmlsbD0iY3JpbXNvbiIgc3Ryb2tlLXdpZHRoPSIyIi8+CiAgICA8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTcuMzM2MDkgMC4zNjc0NzVDNy4wMzIxNCAwLjE1MjY1MiA2LjYyNTQ4IDAuMTUzNjE0IDYuMzIyNTMgMC4zNjk5OTdMNi4zMDg2OSAwLjM3OTU1NEM2LjI5NTUzIDAuMzg4NTg4IDYuMjczODggMC40MDMyNjYgNi4yNDQxNyAwLjQyMjc4OUM2LjE4NDcxIDAuNDYxODYgNi4wOTMyMSAwLjUyMDE3MSA1Ljk3MzEzIDAuNTkxMzczQzUuNzMyNTEgMC43MzQwNTkgNS4zNzk5IDAuOTI2ODY0IDQuOTQyNzkgMS4xMjAwOUM0LjA2MTQ0IDEuNTA5NyAyLjg3NTQxIDEuODgzNzcgMS41ODk4NCAxLjg4Mzc3SDAuNzE0ODQ0VjIuNzU4NzdWNi45ODAxNUMwLjcxNDg0NCA5LjQ5Mzc0IDIuMjg4NjYgMTEuMTk3MyAzLjcwMjU0IDEyLjIxODVDNC40MTg0NSAxMi43MzU1IDUuMTI4NzQgMTMuMTA1MyA1LjY1NzMzIDEzLjM0NTdDNS45MjI4NCAxMy40NjY0IDYuMTQ1NjYgMTMuNTU1OSA2LjMwNDY1IDEzLjYxNjFDNi4zODQyMyAxMy42NDYyIDYuNDQ4MDUgMTMuNjY5IDYuNDkzNDkgMTMuNjg0OEM2LjUxNjIyIDEzLjY5MjcgNi41MzQzOCAxMy42OTg5IDYuNTQ3NjQgMTMuNzAzM0w2LjU2MzgyIDEzLjcwODdMNi41NjkwOCAxMy43MTA0TDYuNTcwOTkgMTMuNzExTDYuODM5ODQgMTMuNzUzM0w2LjU3MjQyIDEzLjcxMTVDNi43NDYzMyAxMy43NjczIDYuOTMzMzUgMTMuNzY3MyA3LjEwNzI3IDEzLjcxMTVMNy4xMDg3IDEzLjcxMUw3LjExMDYxIDEzLjcxMDRMNy4xMTU4NyAxMy43MDg3TDcuMTMyMDUgMTMuNzAzM0M3LjE0NTMxIDEzLjY5ODkgNy4xNjM0NiAxMy42OTI3IDcuMTg2MTkgMTMuNjg0OEM3LjIzMTY0IDEzLjY2OSA3LjI5NTQ2IDEzLjY0NjIgNy4zNzUwMyAxMy42MTYxQzcuNTM0MDMgMTMuNTU1OSA3Ljc1Njg1IDEzLjQ2NjQgOC4wMjIzNiAxMy4zNDU3QzguNTUwOTUgMTMuMTA1MyA5LjI2MTIzIDEyLjczNTUgOS45NzcxNSAxMi4yMTg1QzExLjM5MSAxMS4xOTczIDEyLjk2NDggOS40OTM3NyAxMi45NjQ4IDYuOTgwMThWMi43NTg4QzEyLjk2NDggMi43MTY2IDEyLjk2MTkgMi42NzUxMSAxMi45NTYxIDIuNjM0NTFWMS44ODM3N0gxMi4wODExQzEyLjA3NzUgMS44ODM3NyAxMi4wNzQgMS44ODM3NyAxMi4wNzA0IDEuODgzNzdDMTAuNzk3OSAxLjg4MDA0IDkuNjE5NjIgMS41MTEwMiA4LjczODk0IDEuMTI0ODZDOC43MzUzNCAxLjEyMzI3IDguNzMxNzQgMS4xMjE2OCA4LjcyODE0IDEuMTIwMDlDOC4yOTEwMyAwLjkyNjg2NCA3LjkzODQyIDAuNzM0MDU5IDcuNjk3NzkgMC41OTEzNzNDNy41Nzc3MiAwLjUyMDE3MSA3LjQ4NjIyIDAuNDYxODYgNy40MjY3NiAwLjQyMjc4OUM3LjM5NzA1IDAuNDAzMjY2IDcuMzc1MzkgMC4zODg1ODggNy4zNjIyNCAwLjM3OTU1NEw3LjM0ODk2IDAuMzcwMzVDNy4zNDg5NiAwLjM3MDM1IDcuMzQ4NDcgMC4zNzAwMiA3LjM0NTYzIDAuMzc0MDU0TDcuMzM3NzkgMC4zNjg2NTlMNy4zMzYwOSAwLjM2NzQ3NVpNOC4wMzQ3MSAyLjcyNjkxQzguODYwNCAzLjA5MDYzIDkuOTYwNjYgMy40NjMwOSAxMS4yMDYxIDMuNTg5MDdWNi45ODAxNUgxMS4yMTQ4QzExLjIxNDggOC42Nzk1MyAxMC4xNjM3IDkuOTI1MDcgOC45NTI1NCAxMC43OTk4QzguMzU1OTUgMTEuMjMwNiA3Ljc1Mzc0IDExLjU0NTQgNy4yOTc5NiAxMS43NTI3QzcuMTE2NzEgMTEuODM1MSA2Ljk2MDYyIDExLjg5OTYgNi44Mzk4NCAxMS45NDY5QzYuNzE5MDYgMTEuODk5NiA2LjU2Mjk3IDExLjgzNTEgNi4zODE3MyAxMS43NTI3QzUuOTI1OTUgMTEuNTQ1NCA1LjMyMzczIDExLjIzMDYgNC43MjcxNSAxMC43OTk4QzMuNTE2MDMgOS45MjUwNyAyLjQ2NDg0IDguNjc5NTUgMi40NjQ4NCA2Ljk4MDE4VjMuNTg5MDlDMy43MTczOCAzLjQ2MjM5IDQuODIzMDggMy4wODYzOSA1LjY1MDMzIDIuNzIwNzFDNi4xNDIyOCAyLjUwMzI0IDYuNTQ0ODUgMi4yODUzNyA2LjgzMjU0IDIuMTE2MjRDNy4xMjE4MSAyLjI4NTM1IDcuNTI3IDIuNTAzNTIgOC4wMjE5NiAyLjcyMTMxQzguMDI2MiAyLjcyMzE3IDguMDMwNDUgMi43MjUwNCA4LjAzNDcxIDIuNzI2OTFaTTUuOTY0ODQgMy40MDE0N1Y3Ljc3NjQ3SDcuNzE0ODRWMy40MDE0N0g1Ljk2NDg0Wk01Ljk2NDg0IDEwLjQwMTVWOC42NTE0N0g3LjcxNDg0VjEwLjQwMTVINS45NjQ4NFoiIGZpbGw9ImNyaW1zb24iIHN0cm9rZS13aWR0aD0iMiIvPgo8L3N2Zz4='); + background-color: crimson; + } + .ace_icon_svg.ace_warning_fold { + -webkit-mask-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAyMCAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xNC43NzY5IDE0LjczMzdMOC42NTE5MiAyLjQ4MzY5QzguMzI5NDYgMS44Mzg3NyA3LjQwOTEzIDEuODM4NzcgNy4wODY2NyAyLjQ4MzY5TDAuOTYxNjY5IDE0LjczMzdDMC42NzA3NzUgMTUuMzE1NSAxLjA5MzgzIDE2IDEuNzQ0MjkgMTZIMTMuOTk0M0MxNC42NDQ4IDE2IDE1LjA2NzggMTUuMzE1NSAxNC43NzY5IDE0LjczMzdaTTMuMTYwMDcgMTQuMjVMNy44NjkyOSA0LjgzMTU2TDEyLjU3ODUgMTQuMjVIMy4xNjAwN1pNOC43NDQyOSAxMS42MjVWMTMuMzc1SDYuOTk0MjlWMTEuNjI1SDguNzQ0MjlaTTYuOTk0MjkgMTAuNzVWNy4yNUg4Ljc0NDI5VjEwLjc1SDYuOTk0MjlaIiBmaWxsPSIjRUM3MjExIi8+CjxwYXRoIGQ9Ik0xMS4xOTkxIDIuOTUyMzhDMTAuODgwOSAyLjMxNDY3IDEwLjM1MzcgMS44MDUyNiA5LjcwNTUgMS41MDlMMTEuMDQxIDEuMDY5NzhDMTEuNjg4MyAwLjk0OTgxNCAxMi4zMzcgMS4yNzI2MyAxMi42MzE3IDEuODYxNDFMMTcuNjEzNiAxMS44MTYxQzE4LjM1MjcgMTMuMjkyOSAxNy41OTM4IDE1LjA4MDQgMTYuMDE4IDE1LjU3NDVDMTYuNDA0NCAxNC40NTA3IDE2LjMyMzEgMTMuMjE4OCAxNS43OTI0IDEyLjE1NTVMMTEuMTk5MSAyLjk1MjM4WiIgZmlsbD0iI0VDNzIxMSIvPgo8L3N2Zz4='); + background-color: darkorange; + } + + .ace_scrollbar { + contain: strict; + position: absolute; + right: 0; + bottom: 0; + z-index: 6; + } + + .ace_scrollbar-inner { + position: absolute; + cursor: text; + left: 0; + top: 0; + } + + .ace_scrollbar-v { + overflow-x: hidden; + overflow-y: scroll; + top: 0; + } + + .ace_scrollbar-h { + overflow-x: scroll; + overflow-y: hidden; + left: 0; + } + + .ace_print-margin { + position: absolute; + height: 100%; + } + + .ace_text-input { + position: absolute; + z-index: 0; + width: 0.5em; + height: 1em; + opacity: 0; + background: transparent; + -moz-appearance: none; + appearance: none; + border: none; + resize: none; + outline: none; + overflow: hidden; + font: inherit; + padding: 0 1px; + margin: 0 -1px; + contain: strict; + -ms-user-select: text; + -moz-user-select: text; + -webkit-user-select: text; + user-select: text; + /*with `pre-line` chrome inserts   instead of space*/ + white-space: pre !important; + } + .ace_text-input.ace_composition { + background: transparent; + color: inherit; + z-index: 1000; + opacity: 1; + } + .ace_composition_placeholder { + color: transparent; + } + .ace_composition_marker { + border-bottom: 1px solid; + position: absolute; + border-radius: 0; + margin-top: 1px; + } + + [ace_nocontext='true'] { + transform: none !important; + filter: none !important; + clip-path: none !important; + mask: none !important; + contain: none !important; + perspective: none !important; + mix-blend-mode: initial !important; + z-index: auto; + } + + .ace_layer { + z-index: 1; + position: absolute; + overflow: hidden; + /* workaround for chrome bug https://github.com/ajaxorg/ace/issues/2312*/ + word-wrap: normal; + white-space: pre; + height: 100%; + width: 100%; + box-sizing: border-box; + /* setting pointer-events: auto; on node under the mouse, which changes + during scroll, will break mouse wheel scrolling in Safari */ + pointer-events: none; + } + + .ace_gutter-layer { + position: relative; + width: auto; + text-align: right; + pointer-events: auto; + height: 1000000px; + contain: style size layout; + } + + .ace_text-layer { + font: inherit !important; + position: absolute; + height: 1000000px; + width: 1000000px; + contain: style size layout; + } + + .ace_text-layer > .ace_line, + .ace_text-layer > .ace_line_group { + contain: style size layout; + position: absolute; + top: 0; + left: 0; + right: 0; + } + + .ace_hidpi .ace_text-layer, + .ace_hidpi .ace_gutter-layer, + .ace_hidpi .ace_content, + .ace_hidpi .ace_gutter { + contain: strict; + } + .ace_hidpi .ace_text-layer > .ace_line, + .ace_hidpi .ace_text-layer > .ace_line_group { + contain: strict; + } + + .ace_cjk { + display: inline-block; + text-align: center; + } + + .ace_cursor-layer { + z-index: 4; + } + + .ace_cursor { + z-index: 4; + position: absolute; + box-sizing: border-box; + border-left: 2px solid; + /* workaround for smooth cursor repaintng whole screen in chrome */ + transform: translatez(0); + } + + .ace_multiselect .ace_cursor { + border-left-width: 1px; + } + + .ace_slim-cursors .ace_cursor { + border-left-width: 1px; + } + + .ace_overwrite-cursors .ace_cursor { + border-left-width: 0; + border-bottom: 1px solid; + } + + .ace_hidden-cursors .ace_cursor { + opacity: 0.2; + } + + .ace_hasPlaceholder .ace_hidden-cursors .ace_cursor { + opacity: 0; + } + + .ace_smooth-blinking .ace_cursor { + transition: opacity 0.18s; + } + + .ace_animate-blinking .ace_cursor { + animation-duration: 1000ms; + animation-timing-function: step-end; + animation-name: blink-ace-animate; + animation-iteration-count: infinite; + } + + .ace_animate-blinking.ace_smooth-blinking .ace_cursor { + animation-duration: 1000ms; + animation-timing-function: ease-in-out; + animation-name: blink-ace-animate-smooth; + } + + @keyframes blink-ace-animate { + from, + to { + opacity: 1; + } + 60% { + opacity: 0; + } + } + + @keyframes blink-ace-animate-smooth { + from, + to { + opacity: 1; + } + 45% { + opacity: 1; + } + 60% { + opacity: 0; + } + 85% { + opacity: 0; + } + } + + .ace_marker-layer .ace_step, + .ace_marker-layer .ace_stack { + position: absolute; + z-index: 3; + } + + .ace_marker-layer .ace_selection { + position: absolute; + z-index: 5; + } + + .ace_marker-layer .ace_bracket { + position: absolute; + z-index: 6; + } + + .ace_marker-layer .ace_error_bracket { + position: absolute; + border-bottom: 1px solid #de5555; + border-radius: 0; + } + + .ace_marker-layer .ace_active-line { + position: absolute; + z-index: 2; + } + + .ace_marker-layer .ace_selected-word { + position: absolute; + z-index: 4; + box-sizing: border-box; + } + + .ace_line .ace_fold { + box-sizing: border-box; + + display: inline-block; + height: 11px; + margin-top: -2px; + vertical-align: middle; + + background-image: + url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII='), + url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACJJREFUeNpi+P//fxgTAwPDBxDxD078RSX+YeEyDFMCIMAAI3INmXiwf2YAAAAASUVORK5CYII='); + background-repeat: no-repeat, repeat-x; + background-position: + center center, + top left; + color: transparent; + + border: 1px solid black; + border-radius: 2px; + + cursor: pointer; + pointer-events: auto; + } + + .ace_dark .ace_fold { + } + + .ace_fold:hover { + background-image: + url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII='), + url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACBJREFUeNpi+P//fz4TAwPDZxDxD5X4i5fLMEwJgAADAEPVDbjNw87ZAAAAAElFTkSuQmCC'); + } + + .ace_tooltip { + background-color: #f5f5f5; + border: 1px solid gray; + border-radius: 1px; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); + color: black; + padding: 3px 4px; + position: fixed; + z-index: 999999; + box-sizing: border-box; + cursor: default; + white-space: pre-wrap; + word-wrap: break-word; + line-height: normal; + font-style: normal; + font-weight: normal; + letter-spacing: normal; + pointer-events: none; + overflow: auto; + max-width: min(33em, 66vw); + overscroll-behavior: contain; + } + .ace_tooltip pre { + white-space: pre-wrap; + } + + .ace_tooltip.ace_dark { + background-color: #636363; + color: #fff; + } + + .ace_tooltip:focus { + outline: 1px solid #5e9ed6; + } + + .ace_icon { + display: inline-block; + width: 18px; + vertical-align: top; + } + + .ace_icon_svg { + display: inline-block; + width: 12px; + vertical-align: top; + -webkit-mask-repeat: no-repeat; + -webkit-mask-size: 12px; + -webkit-mask-position: center; + } + + .ace_folding-enabled > .ace_gutter-cell, + .ace_folding-enabled > .ace_gutter-cell_svg-icons { + padding-right: 13px; + } + + .ace_fold-widget, + .ace_custom-widget { + box-sizing: border-box; + + margin: 0 -12px 0 1px; + display: none; + width: 11px; + vertical-align: top; + + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42mWKsQ0AMAzC8ixLlrzQjzmBiEjp0A6WwBCSPgKAXoLkqSot7nN3yMwR7pZ32NzpKkVoDBUxKAAAAABJRU5ErkJggg=='); + background-repeat: no-repeat; + background-position: center; + + border-radius: 3px; + + border: 1px solid transparent; + cursor: pointer; + pointer-events: auto; + } + + .ace_custom-widget { + background: none; + } + + .ace_folding-enabled .ace_fold-widget { + display: inline-block; + } + + .ace_fold-widget.ace_end { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42m3HwQkAMAhD0YzsRchFKI7sAikeWkrxwScEB0nh5e7KTPWimZki4tYfVbX+MNl4pyZXejUO1QAAAABJRU5ErkJggg=='); + } + + .ace_fold-widget.ace_closed { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAGCAYAAAAG5SQMAAAAOUlEQVR42jXKwQkAMAgDwKwqKD4EwQ26sSOkVWjgIIHAzPiCgaqiqnJHZnKICBERHN194O5b9vbLuAVRL+l0YWnZAAAAAElFTkSuQmCCXA=='); + } + + .ace_fold-widget:hover { + border: 1px solid rgba(0, 0, 0, 0.3); + background-color: rgba(255, 255, 255, 0.2); + box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7); + } + + .ace_fold-widget:active { + border: 1px solid rgba(0, 0, 0, 0.4); + background-color: rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8); + } + /** + * Dark version for fold widgets + */ + .ace_dark .ace_fold-widget { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHklEQVQIW2P4//8/AzoGEQ7oGCaLLAhWiSwB146BAQCSTPYocqT0AAAAAElFTkSuQmCC'); + } + .ace_dark .ace_fold-widget.ace_end { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg=='); + } + .ace_dark .ace_fold-widget.ace_closed { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAHElEQVQIW2P4//+/AxAzgDADlOOAznHAKgPWAwARji8UIDTfQQAAAABJRU5ErkJggg=='); + } + .ace_dark .ace_fold-widget:hover { + box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2); + background-color: rgba(255, 255, 255, 0.1); + } + .ace_dark .ace_fold-widget:active { + box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2); + } + + .ace_inline_button { + border: 1px solid lightgray; + display: inline-block; + margin: -1px 8px; + padding: 0 5px; + pointer-events: auto; + cursor: pointer; + } + .ace_inline_button:hover { + border-color: gray; + background: rgba(200, 200, 200, 0.2); + display: inline-block; + pointer-events: auto; + } + + .ace_fold-widget.ace_invalid { + background-color: #ffb4b4; + border-color: #de5555; + } + + .ace_fade-fold-widgets .ace_fold-widget { + transition: opacity 0.4s ease 0.05s; + opacity: 0; + } + + .ace_fade-fold-widgets:hover .ace_fold-widget { + transition: opacity 0.05s ease 0.05s; + opacity: 1; + } + + .ace_underline { + text-decoration: underline; + } + + .ace_bold { + font-weight: bold; + } + + .ace_nobold .ace_bold { + font-weight: normal; + } + + .ace_italic { + font-style: italic; + } + + .ace_error-marker { + background-color: rgba(255, 0, 0, 0.2); + position: absolute; + z-index: 9; + } + + .ace_highlight-marker { + background-color: rgba(255, 255, 0, 0.2); + position: absolute; + z-index: 8; + } + + .ace_mobile-menu { + position: absolute; + line-height: 1.5; + border-radius: 4px; + -ms-user-select: none; + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; + background: white; + box-shadow: 1px 3px 2px grey; + border: 1px solid #dcdcdc; + color: black; + } + .ace_dark > .ace_mobile-menu { + background: #333; + color: #ccc; + box-shadow: 1px 3px 2px grey; + border: 1px solid #444; + } + .ace_mobile-button { + padding: 2px; + cursor: pointer; + overflow: hidden; + } + .ace_mobile-button:hover { + background-color: #eee; + opacity: 1; + } + .ace_mobile-button:active { + background-color: #ddd; + } + + .ace_placeholder { + position: relative; + font-family: arial; + transform: scale(0.9); + transform-origin: left; + white-space: pre; + opacity: 0.7; + margin: 0 10px; + z-index: 1; + } + + .ace_ghost_text { + opacity: 0.5; + font-style: italic; + } + + .ace_ghost_text_container > div { + white-space: pre; + } + + .ghost_text_line_wrapped::after { + content: '↩'; + position: absolute; + } + + .ace_lineWidgetContainer.ace_ghost_text { + margin: 0px 4px; + } + + .ace_screenreader-only { + position: absolute; + left: -10000px; + top: auto; + width: 1px; + height: 1px; + overflow: hidden; + } + + .ace_hidden_token { + display: none; + } + /*# sourceURL=ace/css/ace_editor.css */ + </style> + <style id="ace_scrollbar.css"> + .ace_editor > .ace_sb-v div, + .ace_editor > .ace_sb-h div { + position: absolute; + background: rgba(128, 128, 128, 0.6); + -moz-box-sizing: border-box; + box-sizing: border-box; + border: 1px solid #bbb; + border-radius: 2px; + z-index: 8; + } + .ace_editor > .ace_sb-v, + .ace_editor > .ace_sb-h { + position: absolute; + z-index: 6; + background: none; + overflow: hidden !important; + } + .ace_editor > .ace_sb-v { + z-index: 6; + right: 0; + top: 0; + width: 12px; + } + .ace_editor > .ace_sb-v div { + z-index: 8; + right: 0; + width: 100%; + } + .ace_editor > .ace_sb-h { + bottom: 0; + left: 0; + height: 12px; + } + .ace_editor > .ace_sb-h div { + bottom: 0; + height: 100%; + } + .ace_editor > .ace_sb_grabbed { + z-index: 8; + background: #000; + } + /*# sourceURL=ace/css/ace_scrollbar.css */ + </style> + <style data-emotion="css-global" data-s=""></style> + <meta name="emotion-insertion-point" content="" /> + <style data-emotion="css" data-s=""></style> + <link + rel="icon" + href="https://www.codechef.com/favicon.ico" + type="image/x-icon" + /> + <title>Bitcoin Market Practice Coding Problem + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    + Learn the building blocks of programming + languages +
    +
    +
    + Take our free programming courses and learn to + solve problems like these. +
    + Start Learning +
    +
    +

    Bitcoin Market

    +

    + Chef has recently started investing in + Bitcoin.
    + He assigns a + market risk level + RR + (from + 11 + to + 1010), where: +

    +
      +
    • + 11 + means the market is very safe, +
    • +
    • + 1010 + means the market is very risky. +
    • +
    +

    + Chef will buy Bitcoin only if + the risk level is + 44 + or less. +

    +

    + Given the current risk level + RR, determine whether Chef should buy Bitcoin. +

    +

    + Print "YES" if Chef should + buy, otherwise print "NO". +

    +
    +

    Input Format

    +
      +
    • + The first and only line of input contains + a single integer + RR + — the current market risk level. +
    • +
    +
    +
    +

    Output Format

    +

    + Print YES if Chef should buy + Bitcoin, Otherwise, print NO. +

    +

    + You may print each character of the string + in uppercase or lowercase (for example, the + strings YES, yEs, + yes, and yeS will + all be treated as identical). +

    +
    +

    Constraints

    +
    +
      +
    • + 1R101 \leq R \leq 10 +
    • +
    +
    +

    Sample 1:

    +
    +
    +
    + Input +
    + +
    +
    +
    + Output +
    + +
    +
    +
    +
    +
    +
    2
    +
    +
    +
    YES
    +
    +
    +
    +

    Explanation:

    +
    +

    + The current market risk is + 22.
    + Since + 22 + is not larger than + 44, the risk is small enough, and Chef will + buy Bitcoin. +

    +
    +

    Sample 2:

    +
    +
    +
    + Input +
    + +
    +
    +
    + Output +
    + +
    +
    +
    +
    +
    +
    4
    +
    +
    +
    YES
    +
    +
    +
    +

    Explanation:

    +
    +

    + The current market risk is + 44.
    + Since + 44 + is not larger than + 44, the risk is small enough, and Chef will + buy Bitcoin. +

    +
    +

    Sample 3:

    +
    +
    +
    + Input +
    + +
    +
    +
    + Output +
    + +
    +
    +
    +
    +
    +
    5
    +
    +
    +
    NO
    +
    +
    +
    +

    Explanation:

    +
    +

    + The current market risk is + 55.
    + Since + 55 + is larger than + 44, the risk is too much, and Chef will + not buy Bitcoin. +

    +
    +
    +
    +
    +
    +
    +
    +
    + More Info +
    +
    +
    + Time limit1 secs +
    +
    + Memory limit1.5 GB +
    +
    + Source Limit50000 Bytes +
    +
    +
    +
    +
    +
    +
    +

    + +

    +
    +
    +
    +
    +
    +
    + Author(s) + +
    +
    + Tester(s) +
    + kingmessi +
    +
    +
    + Editorialist(s) + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + +
    +
    +
    +
      +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    +
    +
    + +
    + + +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    + #include + <bits/stdc++.h> +
    +
    +
    +
    + using + namespace + std; +
    +
    +
    +
    +
    +
    +
    + int + main() + { +
    +
    +
    +
    + // your code goes here +
    +
    +
    +
    +
    +
    +
    + } +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +   +
    +
    +
    +
    +   +
    +
    +
    +
    + הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה +
    +
    + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +

    + +

    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + Visualize Code +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + + + + + +
    + + +
    +
    + +
    + + diff --git a/tests/fixtures/codechef_P2209.html b/tests/fixtures/codechef_P2209.html new file mode 100644 index 0000000..97d86ac --- /dev/null +++ b/tests/fixtures/codechef_P2209.html @@ -0,0 +1,5754 @@ + + + + + + + + + + + + + + + Divisible Duel Practice Coding Problem + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    + Difficulty:628 +
    +
    + +
    +
    + Expand +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    + Learn the building blocks of programming + languages +
    +
    +
    + Take our free programming courses and learn to + solve problems like these. +
    + Start Learning +
    +
    +

    Divisible Duel

    +

    + Alice loves working with numbers. One day, she + takes two integers + XX + and + YY + (YXY \ge X) and becomes curious about the numbers + between them. +

    +

    + She looks at all integers between + XX + and + YY + (inclusive) that are divisible by + XX.
    + Among these numbers, she separates them into + even and odd numbers. +

    +

    + Let the sum of all even numbers Alice has be + SevenS_{even}, and the sum of all odd numbers she has be + SoddS_{odd}. +

    +

    + If + SevenSoddS_{even} \ge S_{odd}, Alice will be happy; otherwise, she will be + sad.
    + Alice wants to know whether she will be happy + or not. +

    +
    +

    Input Format

    +
      +
    • + The first line contains a single integer + TT + — the number of test cases. +
    • +
    • + Each of the next + TT + lines contains two integers + XX + and + YY, representing the lower and upper bound + of integers Alice looked at. +
    • +
    +
    +
    +

    Output Format

    +

    + For each test case, print the answer on a + new line: YES if Alice will be + happy, otherwise NO. +

    +

    + You may print each character of the answer + in uppercase either or lowercase (for + example, the strings YES, + yEs, yes, and + yeS will all be treated as + identical). +

    +
    +

    Constraints

    +
    +
      +
    • + 1T1041 \leq T \leq + 10^4 +
    • +
    • + 1X,Y1001 \leq X,Y \leq + 100 +
    • +
    +
    +

    Sample 1:

    +
    +
    +
    + Input +
    + +
    +
    +
    + Output +
    + +
    +
    +
    +
    +
    +
    +3
    +1 4
    +3 9
    +4 100
    +
    +
    +
    +
    +YES
    +NO
    +YES
    +
    +
    +
    +

    Explanation:

    +
    +

    + Test case + 11: + Alice has + X=1X = 1 + and + Y=4Y = 4.
    + The multiples of + XX + in this range are + 1,2,3,41, 2, 3, 4.
    + So, + Seven=2+4=6S_{even} = 2+4 = 6, and + Sodd=1+3=4S_{odd} = 1+3 = 4.
    + Since + SevenSoddS_{even} \ge + S_{odd}, Alice is happy. +

    +

    + Test case + 22: + Alice has + X=3X = 3 + and + Y=9Y = 9.
    + The multiples of + XX + in this range are + 3,6,93, 6, 9. So, + Seven=6S_{even} = 6, and + Sodd=3+9=12S_{odd} = 3+9 = 12.
    + Since + Seven<SoddS_{even} \lt + S_{odd}, Alice is not happy. +

    +
    +
    +
    +
    +
    +
    +
    +
    + More Info +
    +
    +
    + Time limit1 secs +
    +
    + Memory limit1.5 GB +
    +
    + Source Limit50000 Bytes +
    +
    +
    +
    +
    +
    +
    +

    + +

    +
    +
    +
    +
    +
    +
    + Author(s) + +
    +
    + Tester(s) +
    + kingmessi +
    +
    +
    + Editorialist(s) + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + +
    +
    +
    +
      +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    +
    +
    + +
    + + +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    + #include + <bits/stdc++.h> +
    +
    +
    +
    + using + namespace + std; +
    +
    +
    +
    +
    +
    +
    + int + main() + { +
    +
    +
    +
    + // your code goes here +
    +
    +
    +
    +
    +
    +
    + } +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +   +
    +
    +
    +
    +   +
    +
    +
    +
    + הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה +
    +
    + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +

    + +

    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + Visualize Code +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + + + + + +
    + + +
    +
    + +
    + + diff --git a/tests/fixtures/codechef_P3209.html b/tests/fixtures/codechef_P3209.html new file mode 100644 index 0000000..15fb3a4 --- /dev/null +++ b/tests/fixtures/codechef_P3209.html @@ -0,0 +1,5101 @@ + + + + + + + + + + + + + + + Small GCD Sort Practice Coding Problem + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    + Difficulty:1039 +
    +
    + +
    +
    + Expand +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    + Learn the building blocks of programming + languages +
    +
    +
    + Take our free programming courses and learn to + solve problems like these. +
    + Start Learning +
    +
    +

    Small GCD Sort

    +

    + There are + NN + players, numbered from + 11 + to + NN. +

    +

    + Player + ii's score is defined to be + gcd(i,N)\gcd(i, N).
    + Here, + gcd(i,N)\gcd(i, N) + refers to the largest positive integer that + divides both + ii + and + NN. +

    +

    + Your task is to find an ordering of the + players, from left to right, that satisfies + the following conditions: +

    +
      +
    • + Between two players with different scores, + the one with a higher score must appear + somewhere to the left of the one with a + lower score. +
    • +
    • + Between two players with the same score, the + player with a smaller number must appear + somewhere to the left of the one with a + lower score. +
    • +
    +

    + It can be proved that these rules uniquely + define an ordering of the + NN + people.
    + Your task is to find this ordering. +

    +
    +

    Input Format

    +
      +
    • + The first line contains a single integer + TT + — the number of test cases. +
    • +
    • + Each of the next + TT + lines contains a single integer + NN + — the number of players. +
    • +
    +
    +
    +

    Output Format

    +

    + For each test case, print + NN + space-separated integers on a new line — the + player numbers in the required preference + order. +

    +
    +

    Constraints

    +
    +
      +
    • + 1T1001 \leq T \leq 100 +
    • +
    • + 1N1001 \leq N \leq 100 +
    • +
    +
    +

    Sample 1:

    +
    +
    +
    + Input +
    + +
    +
    +
    + Output +
    + +
    +
    +
    +
    +
    +
    +5
    +1
    +2
    +3
    +4
    +5
    +
    +
    +
    +1
    +2 1
    +3 1 2
    +4 2 1 3
    +5 1 2 3 4
    +
    +
    +
    +

    Explanation:

    +
    +

    + Test case + 11: + There is only one player. +

    +

    + Test case + 22: + There are two players.
    + Player + 11 + has a score of + gcd(1,2)=1\gcd(1, 2) = 1, while player + 22 + has a score of + gcd(2,2)=2\gcd(2, 2) = 2.
    + Player + 22 + has a higher score, and so appears to the + left of player + 11, making the only possible order + [2,1][2, 1]. +

    +

    + Test case + 44: + There are four players. It can be verified + that players + 11 + and + 33 + have a score of + 11, player + 22 + has a score of + 22, and player + 44 + has a score of + 44.
    + So, +

    +
      +
    • + Player + 44 + has the highest score, and so must be + placed first. +
    • +
    • + Player + 22 + has the second highest score, and so must + be placed second. +
    • +
    • + Players + 11 + and + 33 + have the same score.
      + Among them, + 11 + has the smaller number, and so must be + placed ahead of + 33. +
    • +
    +

    + Thus, the final order is + [4,2,1,3][4, 2, 1, 3]. +

    +
    +
    +
    +
    +
    +
    +
    +
    + More Info +
    +
    +
    + Time limit1 secs +
    +
    + Memory limit1.5 GB +
    +
    + Source Limit50000 Bytes +
    +
    +
    +
    +
    +
    +
    +

    + +

    +
    +
    +
    +
    +
    +
    + Author(s) + +
    +
    + Tester(s) +
    + kingmessi +
    +
    +
    + Editorialist(s) + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + +
    +
    +
    +
      +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    +
    +
    + +
    + + +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    + #include + <bits/stdc++.h> +
    +
    +
    +
    + using + namespace + std; +
    +
    +
    +
    +
    +
    +
    + int + main() + { +
    +
    +
    +
    + // your code goes here +
    +
    +
    +
    +
    +
    +
    + } +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +   +
    +
    +
    +
    +   +
    +
    +
    +
    + הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה +
    +
    + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +

    + +

    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + Visualize Code +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + + + + + +
    + +
    + +
    + +
    + + diff --git a/tests/fixtures/codechef_P4209.html b/tests/fixtures/codechef_P4209.html new file mode 100644 index 0000000..554a3c3 --- /dev/null +++ b/tests/fixtures/codechef_P4209.html @@ -0,0 +1,5940 @@ + + + + + + + + + + + + + + + Tactical Conversion Practice Coding Problem + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    + Difficulty:1626 +
    +
    + +
    +
    + Expand +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    + Learn the building blocks of programming + languages +
    +
    +
    + Take our free programming courses and learn to + solve problems like these. +
    + Start Learning +
    +
    +

    Tactical Conversion

    +

    + You are given a binary string + SS + of length + NN, i.e. each character of + SS + is either + 00 + or + 11. +

    +

    + You would like to convert every character of + SS + into + 00.
    + To achieve this, you can perform the following + operation: +

    +
      +
    • + Choose an index + ii + (1iN)(1 \le i \le N) + such that + Si=1S_i = 1, and change + SiS_i + to + 00. +
    • +
    +

    + However, there is one restriction:
    + You cannot perform two consecutive operations + on adjacent indices.
    + That is, if you operate on the sequence of + indices + i1,i2,,iki_1, i_2, \ldots, i_k, then for each + 1j<k1 \le j \lt k + the condition + ijij+1>1|i_j - i_{j+1}| \gt 1 + must hold. +

    +

    + Determine whether it is possible to make the + entire string consist of only zeros under + these conditions. +

    +
    +

    Input Format

    +
      +
    • + The first line of input contains a single + integer + TT, denoting the number of test cases. +
    • +
    • + Each test case consists of two lines of + input: +
        +
      • + The first line contains a single + integer + NN + — the length of the binary string. +
      • +
      • + The second line contains the binary + string + SS + of length + NN, consisting only of characters + 0 and 1. +
      • +
      +
    • +
    +
    +
    +

    Output Format

    +

    + For each test case, output a single string + on a new line — YES if it is + possible to convert the entire string to all + zeros under the given rule, or + NO otherwise. +

    +

    + You may print each character of the string + in uppercase or lowercase (for example, the + strings YES, yEs, + yes, and yeS will + all be treated as identical). +

    +
    +

    Constraints

    +
    +
      +
    • + 1T21051 \leq T \leq 2\cdot + 10^5 +
    • +
    • + 1N21051 \leq N \leq 2\cdot + 10^5 +
    • +
    • + SS + is a binary string. +
    • +
    • + The sum of + NN + over all test cases won't exceed + 21052\cdot 10^5. +
    • +
    +
    +

    Sample 1:

    +
    +
    +
    + Input +
    + +
    +
    +
    + Output +
    + +
    +
    +
    +
    +
    +
    +5
    +2
    +00
    +3
    +001
    +3
    +101
    +3
    +111
    +2
    +11
    +
    +
    +
    +
    +Yes
    +Yes
    +Yes
    +No
    +No
    +
    +
    +
    +

    Explanation:

    +
    +

    + Test case + 11: + No operations are needed. +

    +

    + Test case + 22: + There is a single + 11 + at position + 33.
    + Simply perform one operation with + i=3i = 3, and the string becomes + 000000 + as desired. +

    +

    + Test case + 33: + There are two + 11's, at positions + 11 + and + 33.
    + Perform one operation with + i=1i = 1, and the next operation with + i=3i = 3, and we're done. +

    +

    + Test case + 44: + There are three ones, at positions + 1,2,31, 2, 3.
    + It's not possible to operate on all of them, + because: +

    +
      +
    • + If our first operation is on index + 11, the second operation cannot be index + 22 + and so must be index + 33.
      + But then after index + 33 + we cannot operate on index + 22 + anyway, so that index will continue to + contain a + 11. +
    • +
    • + Similarly, the first operation being on + index + 33 + will leave us unable to operate on index + 22. +
    • +
    • + Finally, if the first operation is on + index + 22, then the second operation cannot be on + either index + 11 + or index + 33 + since they're both adjacent to it. +
    • +
    +

    + Thus, there's no way to make everything + 00. +

    +
    +
    +
    +
    +
    +
    +
    +
    + More Info +
    +
    +
    + Time limit1 secs +
    +
    + Memory limit1.5 GB +
    +
    + Source Limit50000 Bytes +
    +
    +
    +
    +
    +
    +
    +

    + +

    +
    +
    +
    +
    +
    +
    + Author(s) + +
    +
    + Tester(s) +
    + kingmessi +
    +
    +
    + Editorialist(s) + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + +
    +
    +
    +
      +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    +
    +
    + +
    + + +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    + #include + <bits/stdc++.h> +
    +
    +
    +
    + using + namespace + std; +
    +
    +
    +
    +
    +
    +
    + int + main() + { +
    +
    +
    +
    + // your code goes here +
    +
    +
    +
    +
    +
    +
    + } +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +   +
    +
    +
    +
    +   +
    +
    +
    +
    + הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה +
    +
    + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +

    + +

    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + Visualize Code +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + + + + + +
    + + +
    +
    + +
    + + diff --git a/tests/fixtures/codechef_P5209.html b/tests/fixtures/codechef_P5209.html new file mode 100644 index 0000000..a7b7aa9 --- /dev/null +++ b/tests/fixtures/codechef_P5209.html @@ -0,0 +1,6175 @@ + + + + + + + + + + + + + + + Binary Love Practice Coding Problem + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    + Difficulty:1536 +
    +
    + +
    +
    + Expand +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    + Learn the building blocks of programming + languages +
    +
    +
    + Take our free programming courses and learn to + solve problems like these. +
    + Start Learning +
    +
    +

    Binary Love

    +

    + Alice and Bob are playing a game on a binary + string + SS + of length + NN. +

    +

    + Alice wants to make the number of substrings + 01 and 10 equal, and + both counts must be non-zero.
    + Formally, let + c01c_{01} + denote the number of indices + ii + (1i<N1 \le i \lt N) such that + Si=0S_i = 0 + and + Si+1=1S_{i+1} = 1, and similarly let + c10c_{10} + denote the number of indices + ii + (1i<N1 \le i \lt N) such that + Si=1S_i = 1 + and + Si+1=0S_{i+1} = 0.
    + Alice would like for + c01=c10c_{01} = c_{10} + and + c01>0c_{01} \gt 0 + to both hold. +

    +

    + Bob, on the other hand, wants to prevent Alice + from achieving this condition. +

    +

    + The players take turns alternately, with Alice + going first.
    + In each turn, the current player can remove + exactly one character from either the + beginning or the end of the string. +

    +

    + The game ends immediately when the string + becomes empty or when Alice's desired + condition (c01=c10>0c_{01} = c_{10} \gt 0) is satisfied. +

    +

    + If Alice can make the number of + 01 and 10 substrings + equal (and both non-zero), she wins.
    + Otherwise, if Bob can prevent this condition + until the string becomes empty, Bob wins.
    + In particular, if the initial string satisfies + the required condition, Alice wins + immediately, without even having to make a + move. +

    +

    + Determine the winner of the game if both + players play optimally. +

    +
    +

    Input Format

    +
      +
    • + The first line of input contains a single + integer + TT, denoting the number of test cases. +
    • +
    • + Each test case consists of two lines of + input: +
        +
      • + The first line contains a single + integer + NN + — the length of the binary string. +
      • +
      • + The second line contains the binary + string + SS + of length + NN, consisting only of characters + 0 and 1. +
      • +
      +
    • +
    +
    +
    +

    Output Format

    +

    + For each test case, output a single string — + Alice if Alice wins the game, + or Bob if Bob wins the game. +

    +

    + You may print each character of the string + in uppercase or lowercase (for example, the + strings BOB, bOb, + bob, and boB will + all be treated as identical). +

    +
    +

    Constraints

    +
    +
      +
    • + 1T21051 \leq T \leq 2\cdot + 10^5 +
    • +
    • + 1N21051 \leq N \leq 2\cdot + 10^5 +
    • +
    • + Si{0,1}S_i \in \{0, 1\} +
    • +
    • + The sum of + NN + over all test cases won't exceed + 21052\cdot10^5. +
    • +
    +
    +

    Sample 1:

    +
    +
    +
    + Input +
    + +
    +
    +
    + Output +
    + +
    +
    +
    +
    +
    +
    +4
    +3
    +000
    +3
    +010
    +4
    +0001
    +4
    +0101
    +
    +
    +
    +Bob
    +Alice
    +Bob
    +Alice
    +
    +
    +
    +

    Explanation:

    +
    +

    + Test case + 11: + We have + c01=c10=0c_{01} = c_{10} = 0 + for the initial string.
    + No matter what the players do in terms of + deleting characters, this won't change.
    + Alice wants + c01>0c_{01} \gt 0, so she cannot win here. +

    +

    + Test case + 22: + We have + c01=c10=1c_{01} = c_{10} = 1 + initially.
    + Alice's condition is already satisfied, so + she wins immediately. +

    +

    + Test case + 44: + We have + S=0101S = 0101, for which + c01=2c_{01} = 2 + and + c10=1c_{10} = 1.
    + Alice must make a move; she can delete the + last character to make + S=010S = 010 + which as seen earlier satisfies Alice's + condition; so Alice wins. +

    +
    +
    +
    +
    +
    +
    +
    +
    + More Info +
    +
    +
    + Time limit1 secs +
    +
    + Memory limit1.5 GB +
    +
    + Source Limit50000 Bytes +
    +
    +
    +
    +
    +
    +
    +

    + +

    +
    +
    +
    +
    +
    +
    + Author(s) + +
    +
    + Tester(s) +
    + kingmessi +
    +
    +
    + Editorialist(s) + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + +
    +
    +
    +
      +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    +
    +
    + +
    + + +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    + #include + <bits/stdc++.h> +
    +
    +
    +
    + using + namespace + std; +
    +
    +
    +
    +
    +
    +
    + int + main() + { +
    +
    +
    +
    + // your code goes here +
    +
    +
    +
    +
    +
    +
    + } +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +   +
    +
    +
    +
    +   +
    +
    +
    +
    + הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה +
    +
    + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +

    + +

    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + Visualize Code +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + + + + + +
    + +
    + +
    + +
    + + diff --git a/tests/fixtures/codechef_START209D.json b/tests/fixtures/codechef_START209D.json new file mode 100644 index 0000000..bad4c78 --- /dev/null +++ b/tests/fixtures/codechef_START209D.json @@ -0,0 +1,202 @@ +{ + "status": "success", + "user": { "username": null }, + "code": "START209D", + "isRatedContest": "1", + "isParentContestRated": "1", + "name": "Starters 209 (Rated)", + "problems": { + "P1209": { + "code": "P1209", + "name": "Bitcoin Market", + "type": "3", + "successful_submissions": "25131", + "allow_submission": false, + "accuracy": 85.680000000000007, + "problem_url": "\/problems\/P1209", + "submit_url": "\/problems\/P1209", + "status_url": "\/status\/P1209", + "is_added_to_practice": true, + "total_submissions": "33093", + "category_name": "main", + "is_direct_submittable": false + }, + "P2209": { + "code": "P2209", + "name": "Divisible Duel", + "type": "3", + "successful_submissions": "21888", + "allow_submission": false, + "accuracy": 64.159999999999997, + "problem_url": "\/problems\/P2209", + "submit_url": "\/problems\/P2209", + "status_url": "\/status\/P2209", + "is_added_to_practice": true, + "total_submissions": "37437", + "category_name": "main", + "is_direct_submittable": false + }, + "P3209": { + "code": "P3209", + "name": "Small GCD Sort", + "type": "3", + "successful_submissions": "13450", + "allow_submission": false, + "accuracy": 76.239999999999995, + "problem_url": "\/problems\/P3209", + "submit_url": "\/problems\/P3209", + "status_url": "\/status\/P3209", + "is_added_to_practice": true, + "total_submissions": "19164", + "category_name": "main", + "is_direct_submittable": false + }, + "P4209": { + "code": "P4209", + "name": "Tactical Conversion", + "type": "3", + "successful_submissions": "1567", + "allow_submission": false, + "accuracy": 8.4499999999999993, + "problem_url": "\/problems\/P4209", + "submit_url": "\/problems\/P4209", + "status_url": "\/status\/P4209", + "is_added_to_practice": true, + "total_submissions": "20535", + "category_name": "main", + "is_direct_submittable": false + }, + "P5209": { + "code": "P5209", + "name": "Binary Love", + "type": "3", + "successful_submissions": "3271", + "allow_submission": false, + "accuracy": 33.530000000000001, + "problem_url": "\/problems\/P5209", + "submit_url": "\/problems\/P5209", + "status_url": "\/status\/P5209", + "is_added_to_practice": true, + "total_submissions": "11128", + "category_name": "main", + "is_direct_submittable": false + }, + "P6209E": { + "code": "P6209E", + "name": "High Score (Easy Version)", + "type": "3", + "successful_submissions": "285", + "allow_submission": false, + "accuracy": 7.2800000000000002, + "problem_url": "\/problems\/P6209E", + "submit_url": "\/problems\/P6209E", + "status_url": "\/status\/P6209E", + "is_added_to_practice": true, + "total_submissions": "4535", + "category_name": "main", + "is_direct_submittable": false + }, + "P6209": { + "code": "P6209", + "name": "High Score (Hard Version)", + "type": "3", + "successful_submissions": "34", + "allow_submission": false, + "accuracy": 3.1899999999999999, + "problem_url": "\/problems\/P6209", + "submit_url": "\/problems\/P6209", + "status_url": "\/status\/P6209", + "is_added_to_practice": true, + "total_submissions": "1159", + "category_name": "main", + "is_direct_submittable": false + }, + "P7209": { + "code": "P7209", + "name": "Easy Grid Game", + "type": "3", + "successful_submissions": "80", + "allow_submission": false, + "accuracy": 5.1100000000000003, + "problem_url": "\/problems\/P7209", + "submit_url": "\/problems\/P7209", + "status_url": "\/status\/P7209", + "is_added_to_practice": true, + "total_submissions": "1740", + "category_name": "main", + "is_direct_submittable": false + }, + "P8209": { + "code": "P8209", + "name": "Counting Is Fun", + "type": "3", + "successful_submissions": "22", + "allow_submission": false, + "accuracy": 1.8200000000000001, + "problem_url": "\/problems\/P8209", + "submit_url": "\/problems\/P8209", + "status_url": "\/status\/P8209", + "is_added_to_practice": true, + "total_submissions": "1261", + "category_name": "main", + "is_direct_submittable": false + } + }, + "banner": "https:\/\/cdn.codechef.com\/download\/small-banner\/START209D\/1760933097.png", + "rules": "

    CodeChef: A Platform for Aspiring Programmers<\/h4>\n

    CodeChef was created as a platform to help programmers make it big in the world of algorithms, computer programming, and programming contests. At CodeChef, our dedicated efforts are aimed at reviving the inner geek within you, as we proudly host a thrilling programming (coding) contest every Wednesday.<\/p>\n

    About CodeChef Starters:<\/h4>\n

    CodeChef Starters is a short programming contest which takes place on every Wednesday\u00a0<\/p>\n

    Contest Details:<\/h4>\n