diff --git a/backend/src/kf_oj/contracts/export.py b/backend/src/kf_oj/contracts/export.py index 6102016..f9b0aad 100644 --- a/backend/src/kf_oj/contracts/export.py +++ b/backend/src/kf_oj/contracts/export.py @@ -6,6 +6,7 @@ from pathlib import Path from kf_oj.api.app import create_app from kf_oj.contracts.judge import JudgeTaskNotification +from kf_oj.contracts.judging import WIRE_MODELS from kf_oj.core.settings import Settings @@ -23,6 +24,15 @@ def main() -> None: Settings(_env_file=None, environment="test") ).openapi(), } + for name, model in WIRE_MODELS.items(): + document = model.model_json_schema() + document["$schema"] = "https://json-schema.org/draft/2020-12/schema" + document["$id"] = f"urn:kf-oj:{name}:v1" + document["$comment"] = ( + "Structural schema; also run versioned model validation for cross-field " + "budgets, result consistency, UUID canonical form and UTF-8 byte limits." + ) + outputs[root / f"contracts/schemas/{name}.v1.schema.json"] = document stale = [] for path, document in outputs.items(): content = json.dumps(document, indent=2, sort_keys=True, ensure_ascii=False) + "\n" diff --git a/backend/src/kf_oj/contracts/judge.py b/backend/src/kf_oj/contracts/judge.py index 07b1149..5d31ee7 100644 --- a/backend/src/kf_oj/contracts/judge.py +++ b/backend/src/kf_oj/contracts/judge.py @@ -1,7 +1,9 @@ -from typing import Literal +from typing import Annotated, Literal from uuid import UUID -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, BeforeValidator, ConfigDict + +from kf_oj.contracts.judging import integer_version class JudgeTaskNotification(BaseModel): @@ -9,6 +11,6 @@ class JudgeTaskNotification(BaseModel): model_config = ConfigDict(extra="forbid", frozen=True) - schema_version: Literal[1] + schema_version: Annotated[Literal[1], BeforeValidator(integer_version)] kind: Literal["judge.evaluation"] evaluation_id: UUID diff --git a/backend/src/kf_oj/contracts/judge_state.py b/backend/src/kf_oj/contracts/judge_state.py new file mode 100644 index 0000000..ae04200 --- /dev/null +++ b/backend/src/kf_oj/contracts/judge_state.py @@ -0,0 +1,48 @@ +"""Pure transition/fencing rules; callers still need a locked database transaction.""" + +from enum import StrEnum + +from kf_oj.contracts.judging import LeaseBinding + + +class EvaluationState(StrEnum): + QUEUED = "queued" + CLAIMED = "claimed" + COMPILING = "compiling" + RUNNING = "running" + CANCELLING = "cancelling" + FINISHED = "finished" + CANCELLED = "cancelled" + FAILED = "failed" + + def allows(self, target: "EvaluationState") -> bool: + transitions = { + self.QUEUED: {self.CLAIMED, self.CANCELLED}, + self.CLAIMED: {self.COMPILING, self.CANCELLING, self.FAILED, self.QUEUED}, + self.COMPILING: { + self.RUNNING, + self.FINISHED, + self.CANCELLING, + self.FAILED, + self.QUEUED, + }, + self.RUNNING: {self.FINISHED, self.CANCELLING, self.FAILED, self.QUEUED}, + self.CANCELLING: {self.CANCELLED, self.FAILED}, + } + return target in transitions.get(self, set()) + + +def require_current_lease( + expected: LeaseBinding, + supplied: LeaseBinding, + expires_at_unix_ms: int, + now_unix_ms: int, +) -> None: + """Identity/version equality and a strict deadline; never trust client time.""" + if expected != supplied or now_unix_ms < 0 or now_unix_ms >= expires_at_unix_ms: + raise ValueError("stale or foreign execution authority") + + +def require_transition(current: EvaluationState, target: EvaluationState) -> None: + if not current.allows(target): + raise ValueError("invalid evaluation transition") diff --git a/backend/src/kf_oj/contracts/judging.py b/backend/src/kf_oj/contracts/judging.py new file mode 100644 index 0000000..0f3d62b --- /dev/null +++ b/backend/src/kf_oj/contracts/judging.py @@ -0,0 +1,378 @@ +"""Versioned judge wire models. Authorization and persistence belong to services.""" + +import json +from enum import StrEnum +from typing import Annotated, Literal, Self +from uuid import UUID + +from pydantic import ( + BaseModel, + BeforeValidator, + ConfigDict, + Field, + StrictBool, + model_validator, +) + +MIB = 1024 * 1024 +I64_MAX = (1 << 63) - 1 +MAX_SOURCE_BYTES = 256 * 1024 +MAX_PACKAGE_BYTES = 64 * MIB +MAX_CASES = 256 +MAX_JOB_WALL_US = 3_600_000_000 +MAX_WIRE_BYTES = 256 * 1024 + + +def integer_version(value: object) -> object: + if type(value) is not int: + raise ValueError("schema version must be an integer") + return value + + +def canonical_id(value: object) -> UUID: + try: + parsed = UUID(str(value)) + except (ValueError, TypeError, AttributeError) as error: + raise ValueError("invalid identifier") from error + if parsed.int == 0 or str(value) != str(parsed): + raise ValueError("identifier must be non-nil and canonical") + return parsed + + +Version = Annotated[Literal[1], BeforeValidator(integer_version)] +Identifier = Annotated[UUID, BeforeValidator(canonical_id)] +Digest = Annotated[str, Field(strict=True, min_length=64, max_length=64, pattern=r"^[0-9a-f]{64}$")] +Label = Annotated[str, Field(strict=True, pattern=r"^[a-z0-9][a-z0-9_-]{0,63}$")] +Counter = Annotated[int, Field(strict=True, ge=1, le=I64_MAX)] +Measurement = Annotated[int, Field(strict=True, ge=0, le=I64_MAX)] + + +class WireModel(BaseModel): + model_config = ConfigDict(extra="forbid", frozen=True) + + +class Language(StrEnum): + C17 = "c17" + CPP20 = "cpp20" + + +class Verdict(StrEnum): + ACCEPTED = "accepted" + WRONG_ANSWER = "wrong_answer" + COMPILATION_ERROR = "compilation_error" + RUNTIME_ERROR = "runtime_error" + TIME_LIMIT = "time_limit_exceeded" + MEMORY_LIMIT = "memory_limit_exceeded" + OUTPUT_LIMIT = "output_limit_exceeded" + CANCELLED = "cancelled" + SYSTEM_ERROR = "system_error" + + +class CompilationStatus(StrEnum): + SUCCEEDED = "succeeded" + COMPILATION_ERROR = "compilation_error" + COMPILATION_LIMIT = "compilation_limit" + CANCELLED = "cancelled" + SYSTEM_ERROR = "system_error" + + +class FailureCode(StrEnum): + ARTIFACT_UNAVAILABLE = "artifact_unavailable" + SANDBOX_UNAVAILABLE = "sandbox_unavailable" + CLEANUP_FAILED = "cleanup_failed" + LEASE_LOST = "lease_lost" + JOB_DEADLINE = "job_deadline" + + +class ArtifactReference(WireModel): + digest: Digest + bytes: Annotated[int, Field(strict=True, ge=0, le=MAX_PACKAGE_BYTES)] + + +class Toolchain(WireModel): + toolchain_id: Label + image_kind: Literal["linux_gnu_cxx_x86_64_v1"] + image_revision: Annotated[int, Field(strict=True, ge=1, le=(1 << 32) - 1)] + + +class RunLimits(WireModel): + cpu_time_us: Annotated[int, Field(strict=True, ge=1000, le=60_000_000)] + wall_time_us: Annotated[int, Field(strict=True, ge=1000, le=120_000_000)] + memory_bytes: Annotated[int, Field(strict=True, ge=1, le=2048 * MIB)] + stack_bytes: Annotated[int, Field(strict=True, ge=1, le=256 * MIB)] + processes: Annotated[int, Field(strict=True, ge=1, le=128)] + open_files: Annotated[int, Field(strict=True, ge=3, le=1024)] + stdout_bytes: Annotated[int, Field(strict=True, ge=1, le=16 * MIB)] + stderr_bytes: Annotated[int, Field(strict=True, ge=1, le=16 * MIB)] + file_bytes: Annotated[int, Field(strict=True, ge=1, le=64 * MIB)] + workdir_bytes: Annotated[int, Field(strict=True, ge=1, le=256 * MIB)] + + @model_validator(mode="after") + def consistent(self) -> Self: + if self.stack_bytes > self.memory_bytes or self.file_bytes > self.workdir_bytes: + raise ValueError("inconsistent resource limits") + return self + + def fits(self, ceiling: "RunLimits") -> bool: + return all( + getattr(self, name) <= getattr(ceiling, name) for name in type(self).model_fields + ) + + +class TestCase(WireModel): + case_id: Identifier + input: ArtifactReference + expected: ArtifactReference + + +class JobManifest(WireModel): + schema_version: Version + kind: Literal["judge.manifest"] + evaluation_id: Identifier + submission_id: Identifier + problem_version_id: Identifier + language: Language + toolchain: Toolchain + source: ArtifactReference + cases: Annotated[tuple[TestCase, ...], Field(min_length=1, max_length=MAX_CASES)] + comparison: Literal["exact_bytes"] + compile_limits: RunLimits + run_limits: RunLimits + job_wall_time_us: Annotated[int, Field(strict=True, ge=1000, le=MAX_JOB_WALL_US)] + + def package_bytes(self) -> int: + # Count references, including duplicates: this bounds actual staged/read bytes. + return self.source.bytes + sum(c.input.bytes + c.expected.bytes for c in self.cases) + + @model_validator(mode="after") + def consistent(self) -> Self: + if not 1 <= self.source.bytes <= MAX_SOURCE_BYTES: + raise ValueError("source size outside policy") + if len({c.case_id for c in self.cases}) != len(self.cases): + raise ValueError("duplicate testcase identifiers") + if self.package_bytes() > MAX_PACKAGE_BYTES: + raise ValueError("test package outside policy") + if any(c.expected.bytes > self.run_limits.stdout_bytes for c in self.cases): + raise ValueError("expected output exceeds output budget") + required_wall = ( + self.compile_limits.wall_time_us + len(self.cases) * self.run_limits.wall_time_us + ) + if required_wall > self.job_wall_time_us: + raise ValueError("job deadline cannot cover execution budgets") + return self + + +class LeaseBinding(WireModel): + evaluation_id: Identifier + attempt_id: Identifier + worker_id: Identifier + fencing_version: Counter + + +class LeaseGrant(WireModel): + schema_version: Version + kind: Literal["judge.lease"] + binding: LeaseBinding + lease_token: Digest = Field(repr=False) + attempt_number: Annotated[int, Field(strict=True, ge=1, le=5)] + expires_at_unix_ms: Counter + manifest_digest: Digest + + +class StageReport(WireModel): + schema_version: Version + kind: Literal["judge.stage"] + binding: LeaseBinding + sequence: Counter + stage: Literal["compiling", "running"] + case_index: Annotated[int, Field(strict=True, ge=0, lt=MAX_CASES)] | None + + @model_validator(mode="after") + def consistent(self) -> Self: + if (self.stage == "running") != (self.case_index is not None): + raise ValueError("testcase index only belongs to running phase") + return self + + +class CompilationReport(WireModel): + status: CompilationStatus + program: ArtifactReference | None + diagnostics: Annotated[str, Field(strict=True, max_length=65536)] = Field(repr=False) + diagnostics_truncated: StrictBool + cpu_time_us: Measurement | None + memory_peak_bytes: Measurement | None + + @model_validator(mode="after") + def consistent(self) -> Self: + if len(self.diagnostics.encode("utf-8")) > 65536: + raise ValueError("compiler diagnostics exceed byte budget") + if (self.status == CompilationStatus.SUCCEEDED) != (self.program is not None): + raise ValueError("compiled artifact only belongs to successful compilation") + if self.program is not None and self.program.bytes == 0: + raise ValueError("compiled artifact cannot be empty") + return self + + +class CaseReport(WireModel): + case_id: Identifier + verdict: Verdict + cpu_time_us: Measurement | None + memory_peak_bytes: Measurement | None + + @model_validator(mode="after") + def consistent(self) -> Self: + if self.verdict == Verdict.COMPILATION_ERROR: + raise ValueError("compilation failure is not a testcase outcome") + return self + + +class JudgementReport(WireModel): + schema_version: Version + kind: Literal["judge.result"] + binding: LeaseBinding + manifest_digest: Digest + compilation: CompilationReport + cases: Annotated[tuple[CaseReport, ...], Field(max_length=MAX_CASES)] + verdict: Verdict + cleanup_complete: StrictBool + failure_code: FailureCode | None + run_cpu_time_us: Measurement | None + run_memory_peak_bytes: Measurement | None + + @model_validator(mode="after") + def consistent(self) -> Self: + if len({c.case_id for c in self.cases}) != len(self.cases): + raise ValueError("duplicate testcase results") + if not self.cleanup_complete and self.failure_code != FailureCode.CLEANUP_FAILED: + raise ValueError("incomplete cleanup requires its own failure evidence") + if self.cleanup_complete and self.failure_code == FailureCode.CLEANUP_FAILED: + raise ValueError("cleanup failure cannot claim completed cleanup") + if (self.verdict == Verdict.SYSTEM_ERROR) != (self.failure_code is not None): + raise ValueError("infrastructure failure and verdict must agree") + terminal = next( + ( + i + for i, c in enumerate(self.cases) + if c.verdict in (Verdict.SYSTEM_ERROR, Verdict.CANCELLED) + ), + None, + ) + if terminal is not None and terminal != len(self.cases) - 1: + raise ValueError("results after fatal testcase outcome") + if self.compilation.status != CompilationStatus.SUCCEEDED: + mapped = { + CompilationStatus.COMPILATION_ERROR: Verdict.COMPILATION_ERROR, + CompilationStatus.COMPILATION_LIMIT: Verdict.COMPILATION_ERROR, + CompilationStatus.CANCELLED: Verdict.CANCELLED, + CompilationStatus.SYSTEM_ERROR: Verdict.SYSTEM_ERROR, + }[self.compilation.status] + if self.cases or self.verdict != mapped: + raise ValueError("failed compilation cannot have runtime results") + elif self.failure_code is None: + if any(c.verdict == Verdict.SYSTEM_ERROR for c in self.cases): + raise ValueError("infrastructure failure requires failure code") + if not self.cases and self.verdict != Verdict.CANCELLED: + raise ValueError("missing testcase results cannot be a completed judgement") + if self.cases and self.verdict != Verdict.CANCELLED: + failures = (Verdict.SYSTEM_ERROR, Verdict.CANCELLED) + summary = next( + (c.verdict for c in self.cases if c.verdict in failures), + next( + (c.verdict for c in self.cases if c.verdict != Verdict.ACCEPTED), + Verdict.ACCEPTED, + ), + ) + if self.verdict != summary: + raise ValueError("testcase summary disagrees") + cpu = ( + sum(c.cpu_time_us for c in self.cases if c.cpu_time_us is not None) + if self.cases and all(c.cpu_time_us is not None for c in self.cases) + else None + ) + memory = ( + max(c.memory_peak_bytes for c in self.cases if c.memory_peak_bytes is not None) + if self.cases and all(c.memory_peak_bytes is not None for c in self.cases) + else None + ) + if self.run_cpu_time_us != cpu or self.run_memory_peak_bytes != memory: + raise ValueError("runtime measurement summary disagrees") + return self + + def validate_for_manifest(self, manifest: JobManifest, digest: str) -> None: + if self.binding.evaluation_id != manifest.evaluation_id or self.manifest_digest != digest: + raise ValueError("report does not belong to authorized manifest") + if [c.case_id for c in self.cases] != [ + c.case_id for c in manifest.cases[: len(self.cases)] + ]: + raise ValueError("testcase results differ from authorized order") + if self.verdict not in (Verdict.COMPILATION_ERROR, Verdict.CANCELLED, Verdict.SYSTEM_ERROR): + if len(self.cases) != len(manifest.cases): + raise ValueError("incomplete ordinary judgement") + + +class AdmissionPolicy(WireModel): + """Trusted node policy. A manifest never supplies or replaces this policy.""" + + max_concurrent_jobs: Annotated[int, Field(strict=True, ge=1, le=64)] = 1 + prefetch: Annotated[int, Field(strict=True, ge=1, le=64)] = 1 + max_retries: Annotated[int, Field(strict=True, ge=0, le=4)] = 2 + max_job_wall_time_us: Annotated[int, Field(strict=True, ge=1000, le=MAX_JOB_WALL_US)] + max_package_bytes: Annotated[int, Field(strict=True, ge=1, le=MAX_PACKAGE_BYTES)] + toolchain: Toolchain + compile_ceiling: RunLimits + run_ceiling: RunLimits + + @model_validator(mode="after") + def consistent(self) -> Self: + if self.prefetch > self.max_concurrent_jobs: + raise ValueError("prefetch exceeds available job slots") + return self + + def admit(self, manifest: JobManifest, attempt_number: int) -> None: + if type(attempt_number) is not int or not 1 <= attempt_number <= self.max_retries + 1: + raise ValueError("attempt retry budget exhausted") + if ( + manifest.toolchain != self.toolchain + or not manifest.compile_limits.fits(self.compile_ceiling) + or not manifest.run_limits.fits(self.run_ceiling) + or manifest.job_wall_time_us > self.max_job_wall_time_us + or manifest.package_bytes() > self.max_package_bytes + ): + raise ValueError("job exceeds trusted node budget") + + +WIRE_MODELS = { + "judge-manifest": JobManifest, + "judge-lease": LeaseGrant, + "judge-stage": StageReport, + "judge-result": JudgementReport, + "judge-admission": AdmissionPolicy, +} + + +def decode_wire[T: WireModel](model: type[T], payload: bytes) -> T: + """UTF-8, bounded size and no ambiguous duplicate members before model validation.""" + if len(payload) > MAX_WIRE_BYTES: + raise ValueError("wire payload exceeds byte budget") + + def unique_members(pairs: list[tuple[str, object]]) -> dict[str, object]: + result = {} + for key, value in pairs: + if key in result: + raise ValueError("duplicate JSON member") + result[key] = value + return result + + def invalid_constant(_: str) -> None: + raise ValueError("invalid JSON constant") + + try: + value = json.loads( + payload.decode("utf-8"), + object_pairs_hook=unique_members, + parse_constant=invalid_constant, + ) + return model.model_validate(value) + except (ValueError, TypeError): + # Errors at the transport boundary must not echo credentials or hidden inputs. + raise ValueError("invalid wire payload") from None diff --git a/backend/tests/test_contracts.py b/backend/tests/test_contracts.py index 250ab53..c0f7090 100644 --- a/backend/tests/test_contracts.py +++ b/backend/tests/test_contracts.py @@ -19,7 +19,11 @@ def test_shared_wire_examples(path: Path) -> None: if ".invalid-" in path.name: with pytest.raises(ValidationError): JudgeTaskNotification.model_validate(payload) - assert not validator.is_valid(payload) + if ".invalid-semantic-" in path.name: + # JSON Schema counts 1.0 as an integer; the wire decoder forbids coercion. + assert validator.is_valid(payload) + else: + assert not validator.is_valid(payload) else: notification = JudgeTaskNotification.model_validate(payload) validator.validate(payload) diff --git a/backend/tests/test_judging_contracts.py b/backend/tests/test_judging_contracts.py new file mode 100644 index 0000000..4aed0ba --- /dev/null +++ b/backend/tests/test_judging_contracts.py @@ -0,0 +1,143 @@ +import json +from pathlib import Path +from uuid import UUID + +import pytest +from jsonschema import Draft202012Validator, FormatChecker +from pydantic import ValidationError + +from kf_oj.contracts.judge_state import ( + EvaluationState, + require_current_lease, + require_transition, +) +from kf_oj.contracts.judging import ( + MAX_WIRE_BYTES, + WIRE_MODELS, + AdmissionPolicy, + JobManifest, + JudgementReport, + LeaseGrant, + decode_wire, +) + +ROOT = Path(__file__).resolve().parents[2] +FIXTURES = ROOT / "tests/fixtures/contracts" +PATHS = sorted(p for name in WIRE_MODELS for p in FIXTURES.glob(f"{name}.*.json")) + + +@pytest.mark.parametrize("path", PATHS, ids=lambda p: p.stem) +def test_shared_judging_examples(path: Path) -> None: + name = path.name.split(".")[0] + model = WIRE_MODELS[name] + payload = json.loads(path.read_text()) + schema = json.loads((ROOT / f"contracts/schemas/{name}.v1.schema.json").read_text()) + validator = Draft202012Validator(schema, format_checker=FormatChecker()) + if ".invalid-" in path.name: + with pytest.raises(ValueError): + decode_wire(model, path.read_bytes()) + if ".invalid-semantic-" in path.name: + assert validator.is_valid(payload) + else: + assert not validator.is_valid(payload) + else: + decoded = decode_wire(model, path.read_bytes()) + validator.validate(payload) + if name == "judge-admission" and "defaults" in path.name: + assert decoded.max_concurrent_jobs == decoded.prefetch == 1 + assert decoded.max_retries == 2 + else: + assert decoded.model_dump(mode="json") == payload + + +def fixture(name: str, model): + return decode_wire(model, (FIXTURES / f"{name}.valid.json").read_bytes()) + + +def test_every_state_transition_matches_shared_table() -> None: + transitions = json.loads((FIXTURES / "judge-state.transitions.json").read_text()) + assert set(transitions) == {s.value for s in EvaluationState} + for current in EvaluationState: + for target in EvaluationState: + allowed = target.value in transitions[current.value] + assert current.allows(target) == allowed + if allowed: + require_transition(current, target) + else: + with pytest.raises(ValueError): + require_transition(current, target) + + +def test_lease_fencing_identity_and_expiry_boundary() -> None: + grant = fixture("judge-lease", LeaseGrant) + binding = grant.binding + require_current_lease(binding, binding, grant.expires_at_unix_ms, grant.expires_at_unix_ms - 1) + for now in (grant.expires_at_unix_ms, grant.expires_at_unix_ms + 1, -1): + with pytest.raises(ValueError): + require_current_lease(binding, binding, grant.expires_at_unix_ms, now) + for field, value in ( + ("fencing_version", 2), + ("attempt_id", UUID("aaaaaaaa-aaaa-4aaa-8aaa-000000000009")), + ("worker_id", UUID("aaaaaaaa-aaaa-4aaa-8aaa-000000000009")), + ("evaluation_id", UUID("aaaaaaaa-aaaa-4aaa-8aaa-000000000009")), + ): + supplied = binding.model_copy(update={field: value}) + with pytest.raises(ValueError): + require_current_lease(binding, supplied, grant.expires_at_unix_ms, 1) + assert grant.lease_token not in repr(grant) + + +def test_node_admission_never_accepts_job_or_retry_above_trusted_policy() -> None: + manifest = fixture("judge-manifest", JobManifest) + policy = fixture("judge-admission", AdmissionPolicy) + for attempt in (1, 2, 3): + policy.admit(manifest, attempt) + for attempt in (0, 4, True): + with pytest.raises(ValueError): + policy.admit(manifest, attempt) + for field, value in (("max_package_bytes", 1), ("max_job_wall_time_us", 1000)): + with pytest.raises(ValueError): + policy.model_copy(update={field: value}).admit(manifest, 1) + lower = policy.run_ceiling.model_copy(update={"memory_bytes": 32 * 1024 * 1024}) + with pytest.raises(ValueError): + policy.model_copy(update={"run_ceiling": lower}).admit(manifest, 1) + other = manifest.model_copy( + update={"toolchain": manifest.toolchain.model_copy(update={"image_revision": 2})} + ) + with pytest.raises(ValueError): + policy.admit(other, 1) + + +def test_result_requires_authorized_manifest_and_complete_case_order() -> None: + manifest = fixture("judge-manifest", JobManifest) + result = fixture("judge-result", JudgementReport) + result.validate_for_manifest(manifest, result.manifest_digest) + with pytest.raises(ValueError): + result.validate_for_manifest(manifest, "f" * 64) + short = result.model_dump(mode="json") + short.update(cases=short["cases"][:1], run_cpu_time_us=100, run_memory_peak_bytes=256 * 1024) + valid_partial = JudgementReport.model_validate(short) + with pytest.raises(ValueError): + valid_partial.validate_for_manifest(manifest, result.manifest_digest) + wrong_order = result.model_dump(mode="json") + wrong_order["cases"].reverse() + with pytest.raises(ValueError): + JudgementReport.model_validate(wrong_order).validate_for_manifest( + manifest, result.manifest_digest + ) + + +def test_wire_decoding_bounds_ambiguity_and_private_error_output() -> None: + payload = (FIXTURES / "judge-lease.valid.json").read_bytes() + duplicate = payload.replace(b'"schema_version": 1', b'"schema_version": 1, "schema_version": 1') + for invalid in (duplicate, payload.decode().encode("utf-16"), b" " * (MAX_WIRE_BYTES + 1)): + with pytest.raises(ValueError): + decode_wire(LeaseGrant, invalid) + secret = "do-not-echo-private-token" + with pytest.raises(ValueError) as error: + decode_wire( + LeaseGrant, payload.replace(b'"0' + b"0" * 63 + b'"', json.dumps(secret).encode()) + ) + assert secret not in str(error.value) + with pytest.raises(ValidationError): + LeaseGrant.model_validate({}) diff --git a/contracts/README.md b/contracts/README.md index 054fe8d..0f62d94 100644 --- a/contracts/README.md +++ b/contracts/README.md @@ -9,6 +9,27 @@ `make contracts` 从 Python 模型生成 Schema/OpenAPI,并生成前端 API 类型。 `make check` 检查快照未过期及两种语言对样例的接受/拒绝一致。 -执行请求/报告、评测状态机、租约与结果提交契约在 JS-01/DR-01 中逐项补充。 +执行器私有规格与 FD 协议属于 Sandbox;平台不接收 argv、宿主路径或执行镜像路径。 + +普通题提交协议现有 `judge-manifest`、`judge-lease`、`judge-stage`、`judge-result` +和本地可信 `judge-admission` v1 模型。清单绑定源码、不可变题目版本、按序工件摘要、 +C17/C++20、固定 GNU 工具链版本及编译/运行预算;租约绑定 evaluation/attempt/Worker +与 fencing 版本。Root 权限、执行和 DB 状态转换接口仍由各自服务实现,解析清单或租约 +不授予执行权。 + +Python/Rust `decode_wire` 在解析前限制 256 KiB UTF-8 JSON,拒绝重复字段与非法数据, +传输边界错误不回显输入。令牌及编译诊断的默认调试输出隐藏内容。`serde_json` 的运行期 +直接依赖用于此有界解码,不引入 IO、网络或数据库。 + +Schema 描述结构;模型另外核对规范 UUID、严格整数(拒绝 `1.0`/布尔值)、工件总大小、 +重复测试点、预算相容、诊断 UTF-8 字节数、编译状态/产物、清理失败和实际结果汇总。 +JSON Schema 的 integer 按数值判断,允许 `1.0`;不能替代协议解码。共享样例中的 +`invalid-semantic-*` 结构合法但被两种语言模型拒绝,其他非法样例同时验证结构拒绝。 +样例全为合成元数据;其中令牌、摘要不是已签发凭证或实际隐藏测试数据。 + +Coordinator 必须在事务锁内核对当前租约及状态规则,并将结果和授权清单比较: +完整用例次序、数量和清单摘要不能只靠报告自身校验。已提交报告的幂等确认与过期租约 +拒绝分别处理,旧 attempt 无权改写结果。`cancelling` 在实际停止确认前不得转为 +`cancelled`;清理失败必须保留独立故障,缺失计量始终为 null。 生成器 `export.py` 是开发工具,允许读取 API 组合层;运行期的契约模型禁止依赖业务模块。 diff --git a/contracts/schemas/judge-admission.v1.schema.json b/contracts/schemas/judge-admission.v1.schema.json new file mode 100644 index 0000000..c0c12f8 --- /dev/null +++ b/contracts/schemas/judge-admission.v1.schema.json @@ -0,0 +1,169 @@ +{ + "$comment": "Structural schema; also run versioned model validation for cross-field budgets, result consistency, UUID canonical form and UTF-8 byte limits.", + "$defs": { + "RunLimits": { + "additionalProperties": false, + "properties": { + "cpu_time_us": { + "maximum": 60000000, + "minimum": 1000, + "title": "Cpu Time Us", + "type": "integer" + }, + "file_bytes": { + "maximum": 67108864, + "minimum": 1, + "title": "File Bytes", + "type": "integer" + }, + "memory_bytes": { + "maximum": 2147483648, + "minimum": 1, + "title": "Memory Bytes", + "type": "integer" + }, + "open_files": { + "maximum": 1024, + "minimum": 3, + "title": "Open Files", + "type": "integer" + }, + "processes": { + "maximum": 128, + "minimum": 1, + "title": "Processes", + "type": "integer" + }, + "stack_bytes": { + "maximum": 268435456, + "minimum": 1, + "title": "Stack Bytes", + "type": "integer" + }, + "stderr_bytes": { + "maximum": 16777216, + "minimum": 1, + "title": "Stderr Bytes", + "type": "integer" + }, + "stdout_bytes": { + "maximum": 16777216, + "minimum": 1, + "title": "Stdout Bytes", + "type": "integer" + }, + "wall_time_us": { + "maximum": 120000000, + "minimum": 1000, + "title": "Wall Time Us", + "type": "integer" + }, + "workdir_bytes": { + "maximum": 268435456, + "minimum": 1, + "title": "Workdir Bytes", + "type": "integer" + } + }, + "required": [ + "cpu_time_us", + "wall_time_us", + "memory_bytes", + "stack_bytes", + "processes", + "open_files", + "stdout_bytes", + "stderr_bytes", + "file_bytes", + "workdir_bytes" + ], + "title": "RunLimits", + "type": "object" + }, + "Toolchain": { + "additionalProperties": false, + "properties": { + "image_kind": { + "const": "linux_gnu_cxx_x86_64_v1", + "title": "Image Kind", + "type": "string" + }, + "image_revision": { + "maximum": 4294967295, + "minimum": 1, + "title": "Image Revision", + "type": "integer" + }, + "toolchain_id": { + "pattern": "^[a-z0-9][a-z0-9_-]{0,63}$", + "title": "Toolchain Id", + "type": "string" + } + }, + "required": [ + "toolchain_id", + "image_kind", + "image_revision" + ], + "title": "Toolchain", + "type": "object" + } + }, + "$id": "urn:kf-oj:judge-admission:v1", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "additionalProperties": false, + "description": "Trusted node policy. A manifest never supplies or replaces this policy.", + "properties": { + "compile_ceiling": { + "$ref": "#/$defs/RunLimits" + }, + "max_concurrent_jobs": { + "default": 1, + "maximum": 64, + "minimum": 1, + "title": "Max Concurrent Jobs", + "type": "integer" + }, + "max_job_wall_time_us": { + "maximum": 3600000000, + "minimum": 1000, + "title": "Max Job Wall Time Us", + "type": "integer" + }, + "max_package_bytes": { + "maximum": 67108864, + "minimum": 1, + "title": "Max Package Bytes", + "type": "integer" + }, + "max_retries": { + "default": 2, + "maximum": 4, + "minimum": 0, + "title": "Max Retries", + "type": "integer" + }, + "prefetch": { + "default": 1, + "maximum": 64, + "minimum": 1, + "title": "Prefetch", + "type": "integer" + }, + "run_ceiling": { + "$ref": "#/$defs/RunLimits" + }, + "toolchain": { + "$ref": "#/$defs/Toolchain" + } + }, + "required": [ + "max_job_wall_time_us", + "max_package_bytes", + "toolchain", + "compile_ceiling", + "run_ceiling" + ], + "title": "AdmissionPolicy", + "type": "object" +} diff --git a/contracts/schemas/judge-lease.v1.schema.json b/contracts/schemas/judge-lease.v1.schema.json new file mode 100644 index 0000000..e8bf75b --- /dev/null +++ b/contracts/schemas/judge-lease.v1.schema.json @@ -0,0 +1,94 @@ +{ + "$comment": "Structural schema; also run versioned model validation for cross-field budgets, result consistency, UUID canonical form and UTF-8 byte limits.", + "$defs": { + "LeaseBinding": { + "additionalProperties": false, + "properties": { + "attempt_id": { + "format": "uuid", + "title": "Attempt Id", + "type": "string" + }, + "evaluation_id": { + "format": "uuid", + "title": "Evaluation Id", + "type": "string" + }, + "fencing_version": { + "maximum": 9223372036854775807, + "minimum": 1, + "title": "Fencing Version", + "type": "integer" + }, + "worker_id": { + "format": "uuid", + "title": "Worker Id", + "type": "string" + } + }, + "required": [ + "evaluation_id", + "attempt_id", + "worker_id", + "fencing_version" + ], + "title": "LeaseBinding", + "type": "object" + } + }, + "$id": "urn:kf-oj:judge-lease:v1", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "additionalProperties": false, + "properties": { + "attempt_number": { + "maximum": 5, + "minimum": 1, + "title": "Attempt Number", + "type": "integer" + }, + "binding": { + "$ref": "#/$defs/LeaseBinding" + }, + "expires_at_unix_ms": { + "maximum": 9223372036854775807, + "minimum": 1, + "title": "Expires At Unix Ms", + "type": "integer" + }, + "kind": { + "const": "judge.lease", + "title": "Kind", + "type": "string" + }, + "lease_token": { + "maxLength": 64, + "minLength": 64, + "pattern": "^[0-9a-f]{64}$", + "title": "Lease Token", + "type": "string" + }, + "manifest_digest": { + "maxLength": 64, + "minLength": 64, + "pattern": "^[0-9a-f]{64}$", + "title": "Manifest Digest", + "type": "string" + }, + "schema_version": { + "const": 1, + "title": "Schema Version", + "type": "integer" + } + }, + "required": [ + "schema_version", + "kind", + "binding", + "lease_token", + "attempt_number", + "expires_at_unix_ms", + "manifest_digest" + ], + "title": "LeaseGrant", + "type": "object" +} diff --git a/contracts/schemas/judge-manifest.v1.schema.json b/contracts/schemas/judge-manifest.v1.schema.json new file mode 100644 index 0000000..48ad543 --- /dev/null +++ b/contracts/schemas/judge-manifest.v1.schema.json @@ -0,0 +1,249 @@ +{ + "$comment": "Structural schema; also run versioned model validation for cross-field budgets, result consistency, UUID canonical form and UTF-8 byte limits.", + "$defs": { + "ArtifactReference": { + "additionalProperties": false, + "properties": { + "bytes": { + "maximum": 67108864, + "minimum": 0, + "title": "Bytes", + "type": "integer" + }, + "digest": { + "maxLength": 64, + "minLength": 64, + "pattern": "^[0-9a-f]{64}$", + "title": "Digest", + "type": "string" + } + }, + "required": [ + "digest", + "bytes" + ], + "title": "ArtifactReference", + "type": "object" + }, + "Language": { + "enum": [ + "c17", + "cpp20" + ], + "title": "Language", + "type": "string" + }, + "RunLimits": { + "additionalProperties": false, + "properties": { + "cpu_time_us": { + "maximum": 60000000, + "minimum": 1000, + "title": "Cpu Time Us", + "type": "integer" + }, + "file_bytes": { + "maximum": 67108864, + "minimum": 1, + "title": "File Bytes", + "type": "integer" + }, + "memory_bytes": { + "maximum": 2147483648, + "minimum": 1, + "title": "Memory Bytes", + "type": "integer" + }, + "open_files": { + "maximum": 1024, + "minimum": 3, + "title": "Open Files", + "type": "integer" + }, + "processes": { + "maximum": 128, + "minimum": 1, + "title": "Processes", + "type": "integer" + }, + "stack_bytes": { + "maximum": 268435456, + "minimum": 1, + "title": "Stack Bytes", + "type": "integer" + }, + "stderr_bytes": { + "maximum": 16777216, + "minimum": 1, + "title": "Stderr Bytes", + "type": "integer" + }, + "stdout_bytes": { + "maximum": 16777216, + "minimum": 1, + "title": "Stdout Bytes", + "type": "integer" + }, + "wall_time_us": { + "maximum": 120000000, + "minimum": 1000, + "title": "Wall Time Us", + "type": "integer" + }, + "workdir_bytes": { + "maximum": 268435456, + "minimum": 1, + "title": "Workdir Bytes", + "type": "integer" + } + }, + "required": [ + "cpu_time_us", + "wall_time_us", + "memory_bytes", + "stack_bytes", + "processes", + "open_files", + "stdout_bytes", + "stderr_bytes", + "file_bytes", + "workdir_bytes" + ], + "title": "RunLimits", + "type": "object" + }, + "TestCase": { + "additionalProperties": false, + "properties": { + "case_id": { + "format": "uuid", + "title": "Case Id", + "type": "string" + }, + "expected": { + "$ref": "#/$defs/ArtifactReference" + }, + "input": { + "$ref": "#/$defs/ArtifactReference" + } + }, + "required": [ + "case_id", + "input", + "expected" + ], + "title": "TestCase", + "type": "object" + }, + "Toolchain": { + "additionalProperties": false, + "properties": { + "image_kind": { + "const": "linux_gnu_cxx_x86_64_v1", + "title": "Image Kind", + "type": "string" + }, + "image_revision": { + "maximum": 4294967295, + "minimum": 1, + "title": "Image Revision", + "type": "integer" + }, + "toolchain_id": { + "pattern": "^[a-z0-9][a-z0-9_-]{0,63}$", + "title": "Toolchain Id", + "type": "string" + } + }, + "required": [ + "toolchain_id", + "image_kind", + "image_revision" + ], + "title": "Toolchain", + "type": "object" + } + }, + "$id": "urn:kf-oj:judge-manifest:v1", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "additionalProperties": false, + "properties": { + "cases": { + "items": { + "$ref": "#/$defs/TestCase" + }, + "maxItems": 256, + "minItems": 1, + "title": "Cases", + "type": "array" + }, + "comparison": { + "const": "exact_bytes", + "title": "Comparison", + "type": "string" + }, + "compile_limits": { + "$ref": "#/$defs/RunLimits" + }, + "evaluation_id": { + "format": "uuid", + "title": "Evaluation Id", + "type": "string" + }, + "job_wall_time_us": { + "maximum": 3600000000, + "minimum": 1000, + "title": "Job Wall Time Us", + "type": "integer" + }, + "kind": { + "const": "judge.manifest", + "title": "Kind", + "type": "string" + }, + "language": { + "$ref": "#/$defs/Language" + }, + "problem_version_id": { + "format": "uuid", + "title": "Problem Version Id", + "type": "string" + }, + "run_limits": { + "$ref": "#/$defs/RunLimits" + }, + "schema_version": { + "const": 1, + "title": "Schema Version", + "type": "integer" + }, + "source": { + "$ref": "#/$defs/ArtifactReference" + }, + "submission_id": { + "format": "uuid", + "title": "Submission Id", + "type": "string" + }, + "toolchain": { + "$ref": "#/$defs/Toolchain" + } + }, + "required": [ + "schema_version", + "kind", + "evaluation_id", + "submission_id", + "problem_version_id", + "language", + "toolchain", + "source", + "cases", + "comparison", + "compile_limits", + "run_limits", + "job_wall_time_us" + ], + "title": "JobManifest", + "type": "object" +} diff --git a/contracts/schemas/judge-result.v1.schema.json b/contracts/schemas/judge-result.v1.schema.json new file mode 100644 index 0000000..9ef785e --- /dev/null +++ b/contracts/schemas/judge-result.v1.schema.json @@ -0,0 +1,304 @@ +{ + "$comment": "Structural schema; also run versioned model validation for cross-field budgets, result consistency, UUID canonical form and UTF-8 byte limits.", + "$defs": { + "ArtifactReference": { + "additionalProperties": false, + "properties": { + "bytes": { + "maximum": 67108864, + "minimum": 0, + "title": "Bytes", + "type": "integer" + }, + "digest": { + "maxLength": 64, + "minLength": 64, + "pattern": "^[0-9a-f]{64}$", + "title": "Digest", + "type": "string" + } + }, + "required": [ + "digest", + "bytes" + ], + "title": "ArtifactReference", + "type": "object" + }, + "CaseReport": { + "additionalProperties": false, + "properties": { + "case_id": { + "format": "uuid", + "title": "Case Id", + "type": "string" + }, + "cpu_time_us": { + "anyOf": [ + { + "maximum": 9223372036854775807, + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Cpu Time Us" + }, + "memory_peak_bytes": { + "anyOf": [ + { + "maximum": 9223372036854775807, + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Memory Peak Bytes" + }, + "verdict": { + "$ref": "#/$defs/Verdict" + } + }, + "required": [ + "case_id", + "verdict", + "cpu_time_us", + "memory_peak_bytes" + ], + "title": "CaseReport", + "type": "object" + }, + "CompilationReport": { + "additionalProperties": false, + "properties": { + "cpu_time_us": { + "anyOf": [ + { + "maximum": 9223372036854775807, + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Cpu Time Us" + }, + "diagnostics": { + "maxLength": 65536, + "title": "Diagnostics", + "type": "string" + }, + "diagnostics_truncated": { + "title": "Diagnostics Truncated", + "type": "boolean" + }, + "memory_peak_bytes": { + "anyOf": [ + { + "maximum": 9223372036854775807, + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Memory Peak Bytes" + }, + "program": { + "anyOf": [ + { + "$ref": "#/$defs/ArtifactReference" + }, + { + "type": "null" + } + ] + }, + "status": { + "$ref": "#/$defs/CompilationStatus" + } + }, + "required": [ + "status", + "program", + "diagnostics", + "diagnostics_truncated", + "cpu_time_us", + "memory_peak_bytes" + ], + "title": "CompilationReport", + "type": "object" + }, + "CompilationStatus": { + "enum": [ + "succeeded", + "compilation_error", + "compilation_limit", + "cancelled", + "system_error" + ], + "title": "CompilationStatus", + "type": "string" + }, + "FailureCode": { + "enum": [ + "artifact_unavailable", + "sandbox_unavailable", + "cleanup_failed", + "lease_lost", + "job_deadline" + ], + "title": "FailureCode", + "type": "string" + }, + "LeaseBinding": { + "additionalProperties": false, + "properties": { + "attempt_id": { + "format": "uuid", + "title": "Attempt Id", + "type": "string" + }, + "evaluation_id": { + "format": "uuid", + "title": "Evaluation Id", + "type": "string" + }, + "fencing_version": { + "maximum": 9223372036854775807, + "minimum": 1, + "title": "Fencing Version", + "type": "integer" + }, + "worker_id": { + "format": "uuid", + "title": "Worker Id", + "type": "string" + } + }, + "required": [ + "evaluation_id", + "attempt_id", + "worker_id", + "fencing_version" + ], + "title": "LeaseBinding", + "type": "object" + }, + "Verdict": { + "enum": [ + "accepted", + "wrong_answer", + "compilation_error", + "runtime_error", + "time_limit_exceeded", + "memory_limit_exceeded", + "output_limit_exceeded", + "cancelled", + "system_error" + ], + "title": "Verdict", + "type": "string" + } + }, + "$id": "urn:kf-oj:judge-result:v1", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "additionalProperties": false, + "properties": { + "binding": { + "$ref": "#/$defs/LeaseBinding" + }, + "cases": { + "items": { + "$ref": "#/$defs/CaseReport" + }, + "maxItems": 256, + "title": "Cases", + "type": "array" + }, + "cleanup_complete": { + "title": "Cleanup Complete", + "type": "boolean" + }, + "compilation": { + "$ref": "#/$defs/CompilationReport" + }, + "failure_code": { + "anyOf": [ + { + "$ref": "#/$defs/FailureCode" + }, + { + "type": "null" + } + ] + }, + "kind": { + "const": "judge.result", + "title": "Kind", + "type": "string" + }, + "manifest_digest": { + "maxLength": 64, + "minLength": 64, + "pattern": "^[0-9a-f]{64}$", + "title": "Manifest Digest", + "type": "string" + }, + "run_cpu_time_us": { + "anyOf": [ + { + "maximum": 9223372036854775807, + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Run Cpu Time Us" + }, + "run_memory_peak_bytes": { + "anyOf": [ + { + "maximum": 9223372036854775807, + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Run Memory Peak Bytes" + }, + "schema_version": { + "const": 1, + "title": "Schema Version", + "type": "integer" + }, + "verdict": { + "$ref": "#/$defs/Verdict" + } + }, + "required": [ + "schema_version", + "kind", + "binding", + "manifest_digest", + "compilation", + "cases", + "verdict", + "cleanup_complete", + "failure_code", + "run_cpu_time_us", + "run_memory_peak_bytes" + ], + "title": "JudgementReport", + "type": "object" +} diff --git a/contracts/schemas/judge-stage.v1.schema.json b/contracts/schemas/judge-stage.v1.schema.json new file mode 100644 index 0000000..087fd9e --- /dev/null +++ b/contracts/schemas/judge-stage.v1.schema.json @@ -0,0 +1,94 @@ +{ + "$comment": "Structural schema; also run versioned model validation for cross-field budgets, result consistency, UUID canonical form and UTF-8 byte limits.", + "$defs": { + "LeaseBinding": { + "additionalProperties": false, + "properties": { + "attempt_id": { + "format": "uuid", + "title": "Attempt Id", + "type": "string" + }, + "evaluation_id": { + "format": "uuid", + "title": "Evaluation Id", + "type": "string" + }, + "fencing_version": { + "maximum": 9223372036854775807, + "minimum": 1, + "title": "Fencing Version", + "type": "integer" + }, + "worker_id": { + "format": "uuid", + "title": "Worker Id", + "type": "string" + } + }, + "required": [ + "evaluation_id", + "attempt_id", + "worker_id", + "fencing_version" + ], + "title": "LeaseBinding", + "type": "object" + } + }, + "$id": "urn:kf-oj:judge-stage:v1", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "additionalProperties": false, + "properties": { + "binding": { + "$ref": "#/$defs/LeaseBinding" + }, + "case_index": { + "anyOf": [ + { + "exclusiveMaximum": 256, + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Case Index" + }, + "kind": { + "const": "judge.stage", + "title": "Kind", + "type": "string" + }, + "schema_version": { + "const": 1, + "title": "Schema Version", + "type": "integer" + }, + "sequence": { + "maximum": 9223372036854775807, + "minimum": 1, + "title": "Sequence", + "type": "integer" + }, + "stage": { + "enum": [ + "compiling", + "running" + ], + "title": "Stage", + "type": "string" + } + }, + "required": [ + "schema_version", + "kind", + "binding", + "sequence", + "stage", + "case_index" + ], + "title": "StageReport", + "type": "object" +} diff --git a/judge/crates/contracts/Cargo.toml b/judge/crates/contracts/Cargo.toml index 07b0e0b..190822b 100644 --- a/judge/crates/contracts/Cargo.toml +++ b/judge/crates/contracts/Cargo.toml @@ -7,6 +7,7 @@ license.workspace = true [dependencies] serde.workspace = true +serde_json.workspace = true uuid.workspace = true [dev-dependencies] diff --git a/judge/crates/contracts/src/judging.rs b/judge/crates/contracts/src/judging.rs new file mode 100644 index 0000000..5ebe8c7 --- /dev/null +++ b/judge/crates/contracts/src/judging.rs @@ -0,0 +1,597 @@ +//! Validated judge wire values. No execution, authorization service or storage. +use crate::SchemaVersion; +use serde::{Deserialize, Serialize, de::Error}; +use uuid::Uuid; + +pub const MIB: u64 = 1024 * 1024; +pub const I64_MAX: u64 = i64::MAX as u64; +pub const MAX_SOURCE_BYTES: u64 = 256 * 1024; +pub const MAX_PACKAGE_BYTES: u64 = 64 * MIB; +pub const MAX_CASES: usize = 256; +pub const MAX_JOB_WALL_US: u64 = 3_600_000_000; +pub const MAX_WIRE_BYTES: usize = 256 * 1024; +pub type Validation = Result<(), &'static str>; + +/// Bound before parsing; hide serde diagnostics because they can contain input values. +pub fn decode_wire(payload: &[u8]) -> Result { + if payload.len() > MAX_WIRE_BYTES { + return Err("wire payload exceeds byte budget"); + } + serde_json::from_slice(payload).map_err(|_| "invalid wire payload") +} + +fn bounded(value: u64, min: u64, max: u64) -> Validation { + if (min..=max).contains(&value) { + Ok(()) + } else { + Err("value outside policy") + } +} +fn measure(value: Option) -> Validation { + value.map_or(Ok(()), |v| bounded(v, 0, I64_MAX)) +} +fn required_option<'de, D, T>(deserializer: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, + T: Deserialize<'de>, +{ + Option::::deserialize(deserializer) +} + +// All decoded nested values validate before becoming public wire models. +macro_rules! validated_struct { + ($name:ident { $($(#[$attr:meta])* $field:ident: $ty:ty),* $(,)? }) => { + #[derive(Clone, Debug, PartialEq, Eq, Serialize)] + pub struct $name { $($(#[$attr])* pub $field: $ty),* } + impl<'de> Deserialize<'de> for $name { + fn deserialize>(d: D) -> Result { + #[derive(Deserialize)] + #[serde(deny_unknown_fields)] + struct Wire { $($(#[$attr])* $field: $ty),* } + let raw = Wire::deserialize(d)?; + let value = Self { $($field: raw.$field),* }; + value.validate().map_err(D::Error::custom)?; + Ok(value) + } + } + }; +} +macro_rules! kind { + ($name:ident, $wire:literal) => { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] + pub enum $name { + #[serde(rename = $wire)] + Value, + } + }; +} +kind!(ManifestKind, "judge.manifest"); +kind!(LeaseKind, "judge.lease"); +kind!(StageKind, "judge.stage"); +kind!(ResultKind, "judge.result"); +kind!(ImageKind, "linux_gnu_cxx_x86_64_v1"); +kind!(Comparison, "exact_bytes"); + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(try_from = "String")] +pub struct Identifier(Uuid); +impl TryFrom for Identifier { + type Error = &'static str; + fn try_from(value: String) -> Result { + let id = Uuid::parse_str(&value).map_err(|_| "invalid identifier")?; + if id.is_nil() || id.to_string() != value { + return Err("identifier must be non-nil and canonical"); + } + Ok(Self(id)) + } +} +impl Identifier { + pub fn as_uuid(self) -> Uuid { + self.0 + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(try_from = "String")] +pub struct Digest(String); +impl TryFrom for Digest { + type Error = &'static str; + fn try_from(value: String) -> Result { + if value.len() != 64 + || !value + .bytes() + .all(|b| b.is_ascii_digit() || (b'a'..=b'f').contains(&b)) + { + return Err("invalid digest"); + } + Ok(Self(value)) + } +} +impl Digest { + pub fn as_str(&self) -> &str { + &self.0 + } +} + +#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(transparent)] +pub struct LeaseToken(Digest); +impl std::fmt::Debug for LeaseToken { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("LeaseToken([redacted])") + } +} +impl LeaseToken { + pub fn expose_secret(&self) -> &str { + self.0.as_str() + } +} + +#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(try_from = "String")] +pub struct CompilerDiagnostics(String); +impl TryFrom for CompilerDiagnostics { + type Error = &'static str; + fn try_from(value: String) -> Result { + if value.len() > 65536 { + return Err("compiler diagnostics exceed byte budget"); + } + Ok(Self(value)) + } +} +impl std::fmt::Debug for CompilerDiagnostics { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("CompilerDiagnostics([redacted])") + } +} +impl CompilerDiagnostics { + pub fn as_str(&self) -> &str { + &self.0 + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(try_from = "String")] +pub struct Label(String); +impl TryFrom for Label { + type Error = &'static str; + fn try_from(value: String) -> Result { + let first = value + .bytes() + .next() + .is_some_and(|b| b.is_ascii_lowercase() || b.is_ascii_digit()); + if !first + || value.len() > 64 + || !value + .bytes() + .all(|b| b.is_ascii_lowercase() || b.is_ascii_digit() || b == b'-' || b == b'_') + { + return Err("invalid label"); + } + Ok(Self(value)) + } +} +impl Label { + pub fn as_str(&self) -> &str { + &self.0 + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum Language { + C17, + Cpp20, +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum Verdict { + Accepted, + WrongAnswer, + CompilationError, + RuntimeError, + TimeLimitExceeded, + MemoryLimitExceeded, + OutputLimitExceeded, + Cancelled, + SystemError, +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum CompilationStatus { + Succeeded, + CompilationError, + CompilationLimit, + Cancelled, + SystemError, +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum FailureCode { + ArtifactUnavailable, + SandboxUnavailable, + CleanupFailed, + LeaseLost, + JobDeadline, +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum Stage { + Compiling, + Running, +} + +validated_struct!(ArtifactReference { + digest: Digest, + bytes: u64 +}); +impl ArtifactReference { + pub fn validate(&self) -> Validation { + bounded(self.bytes, 0, MAX_PACKAGE_BYTES) + } +} +validated_struct!(Toolchain { + toolchain_id: Label, + image_kind: ImageKind, + image_revision: u32 +}); +impl Toolchain { + pub fn validate(&self) -> Validation { + bounded(u64::from(self.image_revision), 1, u64::from(u32::MAX)) + } +} +validated_struct!(RunLimits { + cpu_time_us: u64, + wall_time_us: u64, + memory_bytes: u64, + stack_bytes: u64, + processes: u32, + open_files: u32, + stdout_bytes: u64, + stderr_bytes: u64, + file_bytes: u64, + workdir_bytes: u64, +}); +impl RunLimits { + pub fn validate(&self) -> Validation { + for (value, min, max) in [ + (self.cpu_time_us, 1000, 60_000_000), + (self.wall_time_us, 1000, 120_000_000), + (self.memory_bytes, 1, 2048 * MIB), + (self.stack_bytes, 1, 256 * MIB), + (u64::from(self.processes), 1, 128), + (u64::from(self.open_files), 3, 1024), + (self.stdout_bytes, 1, 16 * MIB), + (self.stderr_bytes, 1, 16 * MIB), + (self.file_bytes, 1, 64 * MIB), + (self.workdir_bytes, 1, 256 * MIB), + ] { + bounded(value, min, max)?; + } + if self.stack_bytes > self.memory_bytes || self.file_bytes > self.workdir_bytes { + return Err("inconsistent resource limits"); + } + Ok(()) + } + pub fn fits(&self, ceiling: &Self) -> bool { + self.cpu_time_us <= ceiling.cpu_time_us + && self.wall_time_us <= ceiling.wall_time_us + && self.memory_bytes <= ceiling.memory_bytes + && self.stack_bytes <= ceiling.stack_bytes + && self.processes <= ceiling.processes + && self.open_files <= ceiling.open_files + && self.stdout_bytes <= ceiling.stdout_bytes + && self.stderr_bytes <= ceiling.stderr_bytes + && self.file_bytes <= ceiling.file_bytes + && self.workdir_bytes <= ceiling.workdir_bytes + } +} +validated_struct!(TestCase { + case_id: Identifier, + input: ArtifactReference, + expected: ArtifactReference +}); +impl TestCase { + pub fn validate(&self) -> Validation { + self.input.validate()?; + self.expected.validate() + } +} +validated_struct!(JobManifest { + schema_version: SchemaVersion, kind: ManifestKind, evaluation_id: Identifier, + submission_id: Identifier, problem_version_id: Identifier, language: Language, + toolchain: Toolchain, source: ArtifactReference, cases: Vec, + comparison: Comparison, compile_limits: RunLimits, run_limits: RunLimits, job_wall_time_us: u64, +}); +impl JobManifest { + pub fn package_bytes(&self) -> u64 { + self.source.bytes + + self + .cases + .iter() + .map(|c| c.input.bytes + c.expected.bytes) + .sum::() + } + pub fn validate(&self) -> Validation { + self.source.validate()?; + self.toolchain.validate()?; + self.compile_limits.validate()?; + self.run_limits.validate()?; + bounded(self.source.bytes, 1, MAX_SOURCE_BYTES)?; + bounded(self.job_wall_time_us, 1000, MAX_JOB_WALL_US)?; + if self.cases.is_empty() || self.cases.len() > MAX_CASES { + return Err("testcase count outside policy"); + } + let mut seen = std::collections::HashSet::new(); + for c in &self.cases { + c.validate()?; + if !seen.insert(c.case_id) { + return Err("duplicate testcase identifiers"); + } + if c.expected.bytes > self.run_limits.stdout_bytes { + return Err("expected output exceeds output budget"); + } + } + if self.package_bytes() > MAX_PACKAGE_BYTES { + return Err("test package outside policy"); + } + let required = self.compile_limits.wall_time_us + + self.cases.len() as u64 * self.run_limits.wall_time_us; + if required > self.job_wall_time_us { + return Err("job deadline cannot cover execution budgets"); + } + Ok(()) + } +} +validated_struct!(LeaseBinding { + evaluation_id: Identifier, + attempt_id: Identifier, + worker_id: Identifier, + fencing_version: u64 +}); +impl LeaseBinding { + pub fn validate(&self) -> Validation { + bounded(self.fencing_version, 1, I64_MAX) + } +} +validated_struct!(LeaseGrant { + schema_version: SchemaVersion, + kind: LeaseKind, + binding: LeaseBinding, + lease_token: LeaseToken, + attempt_number: u32, + expires_at_unix_ms: u64, + manifest_digest: Digest, +}); +impl LeaseGrant { + pub fn validate(&self) -> Validation { + self.binding.validate()?; + bounded(u64::from(self.attempt_number), 1, 5)?; + bounded(self.expires_at_unix_ms, 1, I64_MAX) + } +} +validated_struct!(StageReport { + schema_version: SchemaVersion, kind: StageKind, binding: LeaseBinding, sequence: u64, + stage: Stage, + #[serde(deserialize_with = "required_option")] case_index: Option, +}); +impl StageReport { + pub fn validate(&self) -> Validation { + self.binding.validate()?; + bounded(self.sequence, 1, I64_MAX)?; + if (self.stage == Stage::Running) != self.case_index.is_some() + || self.case_index.is_some_and(|i| usize::from(i) >= MAX_CASES) + { + return Err("testcase index only belongs to running phase"); + } + Ok(()) + } +} +validated_struct!(CompilationReport { + status: CompilationStatus, + #[serde(deserialize_with = "required_option")] program: Option, + diagnostics: CompilerDiagnostics, diagnostics_truncated: bool, + #[serde(deserialize_with = "required_option")] cpu_time_us: Option, + #[serde(deserialize_with = "required_option")] memory_peak_bytes: Option, +}); +impl CompilationReport { + pub fn validate(&self) -> Validation { + measure(self.cpu_time_us)?; + measure(self.memory_peak_bytes)?; + if self.diagnostics.as_str().len() > 65536 { + return Err("compiler diagnostics exceed byte budget"); + } + if (self.status == CompilationStatus::Succeeded) != self.program.is_some() { + return Err("compiled artifact only belongs to successful compilation"); + } + if let Some(program) = &self.program { + program.validate()?; + bounded(program.bytes, 1, MAX_PACKAGE_BYTES)?; + } + Ok(()) + } +} +validated_struct!(CaseReport { + case_id: Identifier, verdict: Verdict, + #[serde(deserialize_with = "required_option")] cpu_time_us: Option, + #[serde(deserialize_with = "required_option")] memory_peak_bytes: Option, +}); +impl CaseReport { + pub fn validate(&self) -> Validation { + measure(self.cpu_time_us)?; + measure(self.memory_peak_bytes)?; + if self.verdict == Verdict::CompilationError { + return Err("compilation failure is not a testcase outcome"); + } + Ok(()) + } +} +validated_struct!(JudgementReport { + schema_version: SchemaVersion, kind: ResultKind, binding: LeaseBinding, manifest_digest: Digest, + compilation: CompilationReport, cases: Vec, verdict: Verdict, cleanup_complete: bool, + #[serde(deserialize_with = "required_option")] failure_code: Option, + #[serde(deserialize_with = "required_option")] run_cpu_time_us: Option, + #[serde(deserialize_with = "required_option")] run_memory_peak_bytes: Option, +}); +impl JudgementReport { + pub fn validate(&self) -> Validation { + self.binding.validate()?; + self.compilation.validate()?; + measure(self.run_cpu_time_us)?; + measure(self.run_memory_peak_bytes)?; + if self.cases.len() > MAX_CASES { + return Err("testcase count outside policy"); + } + let mut seen = std::collections::HashSet::new(); + for (i, c) in self.cases.iter().enumerate() { + c.validate()?; + if !seen.insert(c.case_id) { + return Err("duplicate testcase results"); + } + if matches!(c.verdict, Verdict::SystemError | Verdict::Cancelled) + && i != self.cases.len() - 1 + { + return Err("results after fatal testcase outcome"); + } + } + if !self.cleanup_complete && self.failure_code != Some(FailureCode::CleanupFailed) { + return Err("incomplete cleanup requires its own failure evidence"); + } + if self.cleanup_complete && self.failure_code == Some(FailureCode::CleanupFailed) { + return Err("cleanup failure cannot claim completed cleanup"); + } + if (self.verdict == Verdict::SystemError) != self.failure_code.is_some() { + return Err("infrastructure failure and verdict must agree"); + } + if self.compilation.status != CompilationStatus::Succeeded { + let mapped = match self.compilation.status { + CompilationStatus::CompilationError | CompilationStatus::CompilationLimit => { + Verdict::CompilationError + } + CompilationStatus::Cancelled => Verdict::Cancelled, + CompilationStatus::SystemError => Verdict::SystemError, + CompilationStatus::Succeeded => unreachable!(), + }; + if !self.cases.is_empty() || self.verdict != mapped { + return Err("failed compilation cannot have runtime results"); + } + } else if self.failure_code.is_none() { + if self.cases.iter().any(|c| c.verdict == Verdict::SystemError) { + return Err("infrastructure failure requires failure code"); + } + if self.cases.is_empty() && self.verdict != Verdict::Cancelled { + return Err("missing testcase results cannot be a completed judgement"); + } + if self.verdict != Verdict::Cancelled && !self.cases.is_empty() { + let summary = self + .cases + .iter() + .find(|c| c.verdict == Verdict::Cancelled) + .or_else(|| self.cases.iter().find(|c| c.verdict != Verdict::Accepted)) + .map_or(Verdict::Accepted, |c| c.verdict); + if self.verdict != summary { + return Err("testcase summary disagrees"); + } + } + } + let cpu = if !self.cases.is_empty() && self.cases.iter().all(|c| c.cpu_time_us.is_some()) { + Some( + self.cases + .iter() + .try_fold(0_u64, |total, c| { + total.checked_add(c.cpu_time_us.unwrap_or(0)) + }) + .ok_or("measurement sum overflow")?, + ) + } else { + None + }; + let memory = + if !self.cases.is_empty() && self.cases.iter().all(|c| c.memory_peak_bytes.is_some()) { + self.cases.iter().filter_map(|c| c.memory_peak_bytes).max() + } else { + None + }; + if self.run_cpu_time_us != cpu || self.run_memory_peak_bytes != memory { + return Err("runtime measurement summary disagrees"); + } + Ok(()) + } + pub fn validate_for_manifest(&self, manifest: &JobManifest, digest: &Digest) -> Validation { + self.validate()?; + manifest.validate()?; + if self.binding.evaluation_id != manifest.evaluation_id || &self.manifest_digest != digest { + return Err("report does not belong to authorized manifest"); + } + if self.cases.len() > manifest.cases.len() + || !self + .cases + .iter() + .zip(&manifest.cases) + .all(|(a, b)| a.case_id == b.case_id) + { + return Err("testcase results differ from authorized order"); + } + if !matches!( + self.verdict, + Verdict::CompilationError | Verdict::Cancelled | Verdict::SystemError + ) && self.cases.len() != manifest.cases.len() + { + return Err("incomplete ordinary judgement"); + } + Ok(()) + } +} +validated_struct!(AdmissionPolicy { + #[serde(default = "one")] + max_concurrent_jobs: u32, + #[serde(default = "one")] + prefetch: u32, + #[serde(default = "two")] + max_retries: u32, + max_job_wall_time_us: u64, + max_package_bytes: u64, + toolchain: Toolchain, + compile_ceiling: RunLimits, + run_ceiling: RunLimits, +}); +fn one() -> u32 { + 1 +} +fn two() -> u32 { + 2 +} +impl AdmissionPolicy { + pub fn validate(&self) -> Validation { + self.compile_ceiling.validate()?; + self.run_ceiling.validate()?; + self.toolchain.validate()?; + bounded(u64::from(self.max_concurrent_jobs), 1, 64)?; + bounded(u64::from(self.prefetch), 1, 64)?; + bounded(u64::from(self.max_retries), 0, 4)?; + bounded(self.max_job_wall_time_us, 1000, MAX_JOB_WALL_US)?; + bounded(self.max_package_bytes, 1, MAX_PACKAGE_BYTES)?; + if self.prefetch > self.max_concurrent_jobs { + return Err("prefetch exceeds available job slots"); + } + Ok(()) + } + pub fn admit(&self, manifest: &JobManifest, attempt_number: u32) -> Validation { + self.validate()?; + manifest.validate()?; + bounded( + u64::from(attempt_number), + 1, + u64::from(self.max_retries) + 1, + )?; + if manifest.toolchain != self.toolchain + || !manifest.compile_limits.fits(&self.compile_ceiling) + || !manifest.run_limits.fits(&self.run_ceiling) + || manifest.job_wall_time_us > self.max_job_wall_time_us + || manifest.package_bytes() > self.max_package_bytes + { + return Err("job exceeds trusted node budget"); + } + Ok(()) + } +} diff --git a/judge/crates/contracts/src/lib.rs b/judge/crates/contracts/src/lib.rs index ff4bbcb..eb0bf40 100644 --- a/judge/crates/contracts/src/lib.rs +++ b/judge/crates/contracts/src/lib.rs @@ -3,6 +3,9 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; +pub mod judging; +pub mod state; + pub const SCHEMA_VERSION: u16 = 1; #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] diff --git a/judge/crates/contracts/src/state.rs b/judge/crates/contracts/src/state.rs new file mode 100644 index 0000000..776d27f --- /dev/null +++ b/judge/crates/contracts/src/state.rs @@ -0,0 +1,49 @@ +//! Pure transition and lease fencing; repositories must apply these under lock. +use crate::judging::{LeaseBinding, Validation}; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum EvaluationState { + Queued, + Claimed, + Compiling, + Running, + Cancelling, + Finished, + Cancelled, + Failed, +} +impl EvaluationState { + pub fn allows(self, target: Self) -> bool { + use EvaluationState::*; + matches!( + (self, target), + (Queued, Claimed | Cancelled) + | (Claimed, Compiling | Cancelling | Failed | Queued) + | (Compiling, Running | Finished | Cancelling | Failed | Queued) + | (Running, Finished | Cancelling | Failed | Queued) + | (Cancelling, Cancelled | Failed) + ) + } +} +pub fn require_current_lease( + expected: &LeaseBinding, + supplied: &LeaseBinding, + expires_at_unix_ms: u64, + now_unix_ms: u64, +) -> Validation { + expected.validate()?; + supplied.validate()?; + if expected != supplied || now_unix_ms >= expires_at_unix_ms { + return Err("stale or foreign execution authority"); + } + Ok(()) +} +pub fn require_transition(current: EvaluationState, target: EvaluationState) -> Validation { + if current.allows(target) { + Ok(()) + } else { + Err("invalid evaluation transition") + } +} diff --git a/judge/crates/contracts/tests/judging_examples.rs b/judge/crates/contracts/tests/judging_examples.rs new file mode 100644 index 0000000..14d786c --- /dev/null +++ b/judge/crates/contracts/tests/judging_examples.rs @@ -0,0 +1,189 @@ +use kf_contracts::{judging::*, state::*}; +use serde::de::DeserializeOwned; +use serde_json::Value; +use std::{fs, path::PathBuf}; + +fn fixtures() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../../tests/fixtures/contracts") +} +fn fixture(name: &str) -> T { + decode_wire(&fs::read(fixtures().join(format!("{name}.valid.json"))).unwrap()).unwrap() +} +fn roundtrip(bytes: &[u8], invalid: bool, name: &str) { + let result = decode_wire::(bytes); + if invalid { + assert!(result.is_err(), "must reject {name}"); + } else { + let decoded = + serde_json::to_value(result.unwrap_or_else(|e| panic!("{name}: {e}"))).unwrap(); + let mut original: Value = serde_json::from_slice(bytes).unwrap(); + if name.contains("admission") && name.contains("defaults") { + let object = original.as_object_mut().unwrap(); + object.insert("max_concurrent_jobs".into(), 1.into()); + object.insert("prefetch".into(), 1.into()); + object.insert("max_retries".into(), 2.into()); + } + assert_eq!(decoded, original, "roundtrip {name}"); + } +} +#[test] +fn shared_judging_examples_match_python() { + let mut count = 0; + for entry in fs::read_dir(fixtures()).unwrap() { + let path = entry.unwrap().path(); + let name = path.file_name().unwrap().to_string_lossy(); + let bytes = fs::read(&path).unwrap(); + let invalid = name.contains(".invalid-"); + if name.starts_with("judge-manifest.") { + roundtrip::(&bytes, invalid, &name); + } else if name.starts_with("judge-lease.") { + roundtrip::(&bytes, invalid, &name); + } else if name.starts_with("judge-stage.") { + roundtrip::(&bytes, invalid, &name); + } else if name.starts_with("judge-result.") { + roundtrip::(&bytes, invalid, &name); + } else if name.starts_with("judge-admission.") { + roundtrip::(&bytes, invalid, &name); + } else { + continue; + } + count += 1; + } + assert!( + count >= 50, + "judging acceptance/rejection cases must not disappear" + ); +} +#[test] +fn every_state_transition_matches_shared_table() { + let table: Value = + serde_json::from_slice(&fs::read(fixtures().join("judge-state.transitions.json")).unwrap()) + .unwrap(); + let states = [ + EvaluationState::Queued, + EvaluationState::Claimed, + EvaluationState::Compiling, + EvaluationState::Running, + EvaluationState::Cancelling, + EvaluationState::Finished, + EvaluationState::Cancelled, + EvaluationState::Failed, + ]; + assert_eq!(table.as_object().unwrap().len(), states.len()); + for current in states { + for target in states { + let name = serde_json::to_value(current).unwrap(); + let allowed = table[name.as_str().unwrap()] + .as_array() + .unwrap() + .contains(&serde_json::to_value(target).unwrap()); + assert_eq!(current.allows(target), allowed); + assert_eq!(require_transition(current, target).is_ok(), allowed); + } + } +} +#[test] +fn lease_fencing_identity_and_deadline_are_strict() { + let grant: LeaseGrant = fixture("judge-lease"); + let binding = &grant.binding; + assert!( + require_current_lease( + binding, + binding, + grant.expires_at_unix_ms, + grant.expires_at_unix_ms - 1 + ) + .is_ok() + ); + for now in [grant.expires_at_unix_ms, grant.expires_at_unix_ms + 1] { + assert!(require_current_lease(binding, binding, grant.expires_at_unix_ms, now).is_err()); + } + let foreign: Identifier = "aaaaaaaa-aaaa-4aaa-8aaa-000000000009" + .to_owned() + .try_into() + .unwrap(); + for i in 0..4 { + let mut supplied = binding.clone(); + match i { + 0 => supplied.fencing_version += 1, + 1 => supplied.attempt_id = foreign, + 2 => supplied.worker_id = foreign, + _ => supplied.evaluation_id = foreign, + } + assert!(require_current_lease(binding, &supplied, grant.expires_at_unix_ms, 1).is_err()); + } + assert!(!format!("{grant:?}").contains(grant.lease_token.expose_secret())); +} +#[test] +fn trusted_admission_caps_and_retry_limit_cannot_be_relaxed_by_job() { + let manifest: JobManifest = fixture("judge-manifest"); + let policy: AdmissionPolicy = fixture("judge-admission"); + for attempt in [1, 2, 3] { + assert!(policy.admit(&manifest, attempt).is_ok()); + } + for attempt in [0, 4] { + assert!(policy.admit(&manifest, attempt).is_err()); + } + let mut other = manifest.clone(); + other.toolchain.image_revision += 1; + assert!(policy.admit(&other, 1).is_err()); + let mut lower = policy.clone(); + lower.max_package_bytes = 1; + assert!(lower.admit(&manifest, 1).is_err()); + let mut lower = policy.clone(); + lower.max_job_wall_time_us = 1000; + assert!(lower.admit(&manifest, 1).is_err()); + let mut lower = policy; + lower.run_ceiling.memory_bytes = 32 * MIB; + assert!(lower.admit(&manifest, 1).is_err()); +} +#[test] +fn results_require_authorized_manifest_and_complete_case_order() { + let manifest: JobManifest = fixture("judge-manifest"); + let result: JudgementReport = fixture("judge-result"); + assert!( + result + .validate_for_manifest(&manifest, &result.manifest_digest) + .is_ok() + ); + assert!( + result + .validate_for_manifest(&manifest, &"f".repeat(64).try_into().unwrap()) + .is_err() + ); + let mut short = result.clone(); + short.cases.truncate(1); + short.run_cpu_time_us = Some(100); + short.run_memory_peak_bytes = Some(256 * 1024); + assert!(short.validate().is_ok()); + assert!( + short + .validate_for_manifest(&manifest, &result.manifest_digest) + .is_err() + ); + let mut wrong_order = result; + wrong_order.cases.reverse(); + assert!(wrong_order.validate().is_ok()); + assert!( + wrong_order + .validate_for_manifest(&manifest, &wrong_order.manifest_digest) + .is_err() + ); +} +#[test] +fn wire_decoder_bounds_ambiguity_and_private_diagnostics() { + let bytes = fs::read(fixtures().join("judge-lease.valid.json")).unwrap(); + let text = String::from_utf8(bytes).unwrap(); + let duplicate = text.replace( + "\"schema_version\": 1", + "\"schema_version\": 1, \"schema_version\": 1", + ); + assert!(decode_wire::(duplicate.as_bytes()).is_err()); + assert!(decode_wire::(&vec![b' '; MAX_WIRE_BYTES + 1]).is_err()); + let private = text.replace(&"0".repeat(64), "do-not-echo-private-token"); + let error = decode_wire::(private.as_bytes()).unwrap_err(); + assert!(!error.contains("do-not-echo")); + let ce: JudgementReport = + decode_wire(&fs::read(fixtures().join("judge-result.valid-ce.json")).unwrap()).unwrap(); + assert!(!format!("{ce:?}").contains(ce.compilation.diagnostics.as_str())); +} diff --git a/tests/fixtures/contracts/judge-admission.invalid-extra.json b/tests/fixtures/contracts/judge-admission.invalid-extra.json new file mode 100644 index 0000000..5f9beda --- /dev/null +++ b/tests/fixtures/contracts/judge-admission.invalid-extra.json @@ -0,0 +1,37 @@ +{ + "max_concurrent_jobs": 1, + "prefetch": 1, + "max_retries": 2, + "max_job_wall_time_us": 60000000, + "max_package_bytes": 67108864, + "compile_ceiling": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_ceiling": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "host_path": "/etc/passwd", + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + } +} diff --git a/tests/fixtures/contracts/judge-admission.invalid-semantic-prefetch.json b/tests/fixtures/contracts/judge-admission.invalid-semantic-prefetch.json new file mode 100644 index 0000000..10b62ef --- /dev/null +++ b/tests/fixtures/contracts/judge-admission.invalid-semantic-prefetch.json @@ -0,0 +1,36 @@ +{ + "max_concurrent_jobs": 1, + "prefetch": 2, + "max_retries": 2, + "max_job_wall_time_us": 60000000, + "max_package_bytes": 67108864, + "compile_ceiling": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_ceiling": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + } +} diff --git a/tests/fixtures/contracts/judge-admission.valid-defaults.json b/tests/fixtures/contracts/judge-admission.valid-defaults.json new file mode 100644 index 0000000..2873b39 --- /dev/null +++ b/tests/fixtures/contracts/judge-admission.valid-defaults.json @@ -0,0 +1,33 @@ +{ + "max_job_wall_time_us": 60000000, + "max_package_bytes": 67108864, + "compile_ceiling": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_ceiling": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + } +} diff --git a/tests/fixtures/contracts/judge-admission.valid.json b/tests/fixtures/contracts/judge-admission.valid.json new file mode 100644 index 0000000..fb3362b --- /dev/null +++ b/tests/fixtures/contracts/judge-admission.valid.json @@ -0,0 +1,36 @@ +{ + "max_concurrent_jobs": 1, + "prefetch": 1, + "max_retries": 2, + "max_job_wall_time_us": 60000000, + "max_package_bytes": 67108864, + "compile_ceiling": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_ceiling": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + } +} diff --git a/tests/fixtures/contracts/judge-lease.invalid-extra.json b/tests/fixtures/contracts/judge-lease.invalid-extra.json new file mode 100644 index 0000000..315e227 --- /dev/null +++ b/tests/fixtures/contracts/judge-lease.invalid-extra.json @@ -0,0 +1,15 @@ +{ + "schema_version": 1, + "kind": "judge.lease", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "lease_token": "0000000000000000000000000000000000000000000000000000000000000000", + "attempt_number": 1, + "expires_at_unix_ms": 1800000000000, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "host_path": "/etc/passwd" +} diff --git a/tests/fixtures/contracts/judge-lease.invalid-fencing-overflow.json b/tests/fixtures/contracts/judge-lease.invalid-fencing-overflow.json new file mode 100644 index 0000000..3d30dcd --- /dev/null +++ b/tests/fixtures/contracts/judge-lease.invalid-fencing-overflow.json @@ -0,0 +1,14 @@ +{ + "schema_version": 1, + "kind": "judge.lease", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 9223372036854775808 + }, + "lease_token": "0000000000000000000000000000000000000000000000000000000000000000", + "attempt_number": 1, + "expires_at_unix_ms": 1800000000000, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" +} diff --git a/tests/fixtures/contracts/judge-lease.invalid-zero-attempt.json b/tests/fixtures/contracts/judge-lease.invalid-zero-attempt.json new file mode 100644 index 0000000..1fdf58c --- /dev/null +++ b/tests/fixtures/contracts/judge-lease.invalid-zero-attempt.json @@ -0,0 +1,14 @@ +{ + "schema_version": 1, + "kind": "judge.lease", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "lease_token": "0000000000000000000000000000000000000000000000000000000000000000", + "attempt_number": 0, + "expires_at_unix_ms": 1800000000000, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" +} diff --git a/tests/fixtures/contracts/judge-lease.valid.json b/tests/fixtures/contracts/judge-lease.valid.json new file mode 100644 index 0000000..5a30fc8 --- /dev/null +++ b/tests/fixtures/contracts/judge-lease.valid.json @@ -0,0 +1,14 @@ +{ + "schema_version": 1, + "kind": "judge.lease", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "lease_token": "0000000000000000000000000000000000000000000000000000000000000000", + "attempt_number": 1, + "expires_at_unix_ms": 1800000000000, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" +} diff --git a/tests/fixtures/contracts/judge-manifest.invalid-bool-memory.json b/tests/fixtures/contracts/judge-manifest.invalid-bool-memory.json new file mode 100644 index 0000000..c677340 --- /dev/null +++ b/tests/fixtures/contracts/judge-manifest.invalid-bool-memory.json @@ -0,0 +1,78 @@ +{ + "schema_version": 1, + "kind": "judge.manifest", + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "submission_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000002", + "problem_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000003", + "language": "cpp20", + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + }, + "source": { + "digest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bytes": 124 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 1 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 1 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 2 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 2 + } + } + ], + "comparison": "exact_bytes", + "compile_limits": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_limits": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": true, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "job_wall_time_us": 60000000 +} diff --git a/tests/fixtures/contracts/judge-manifest.invalid-count.json b/tests/fixtures/contracts/judge-manifest.invalid-count.json new file mode 100644 index 0000000..dec6fe7 --- /dev/null +++ b/tests/fixtures/contracts/judge-manifest.invalid-count.json @@ -0,0 +1,2872 @@ +{ + "schema_version": 1, + "kind": "judge.manifest", + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "submission_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000002", + "problem_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000003", + "language": "cpp20", + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + }, + "source": { + "digest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bytes": 124 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + } + ], + "comparison": "exact_bytes", + "compile_limits": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_limits": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "job_wall_time_us": 60000000 +} diff --git a/tests/fixtures/contracts/judge-manifest.invalid-digest.json b/tests/fixtures/contracts/judge-manifest.invalid-digest.json new file mode 100644 index 0000000..8c15872 --- /dev/null +++ b/tests/fixtures/contracts/judge-manifest.invalid-digest.json @@ -0,0 +1,78 @@ +{ + "schema_version": 1, + "kind": "judge.manifest", + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "submission_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000002", + "problem_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000003", + "language": "cpp20", + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + }, + "source": { + "digest": "../../etc/passwd", + "bytes": 124 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 1 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 1 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 2 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 2 + } + } + ], + "comparison": "exact_bytes", + "compile_limits": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_limits": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "job_wall_time_us": 60000000 +} diff --git a/tests/fixtures/contracts/judge-manifest.invalid-empty-cases.json b/tests/fixtures/contracts/judge-manifest.invalid-empty-cases.json new file mode 100644 index 0000000..a93bd44 --- /dev/null +++ b/tests/fixtures/contracts/judge-manifest.invalid-empty-cases.json @@ -0,0 +1,44 @@ +{ + "schema_version": 1, + "kind": "judge.manifest", + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "submission_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000002", + "problem_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000003", + "language": "cpp20", + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + }, + "source": { + "digest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bytes": 124 + }, + "cases": [], + "comparison": "exact_bytes", + "compile_limits": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_limits": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "job_wall_time_us": 60000000 +} diff --git a/tests/fixtures/contracts/judge-manifest.invalid-extra.json b/tests/fixtures/contracts/judge-manifest.invalid-extra.json new file mode 100644 index 0000000..f189dbc --- /dev/null +++ b/tests/fixtures/contracts/judge-manifest.invalid-extra.json @@ -0,0 +1,79 @@ +{ + "schema_version": 1, + "kind": "judge.manifest", + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "submission_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000002", + "problem_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000003", + "language": "cpp20", + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + }, + "source": { + "digest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bytes": 124 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 1 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 1 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 2 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 2 + } + } + ], + "comparison": "exact_bytes", + "compile_limits": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_limits": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "job_wall_time_us": 60000000, + "host_path": "/etc/passwd" +} diff --git a/tests/fixtures/contracts/judge-manifest.invalid-language.json b/tests/fixtures/contracts/judge-manifest.invalid-language.json new file mode 100644 index 0000000..19266bc --- /dev/null +++ b/tests/fixtures/contracts/judge-manifest.invalid-language.json @@ -0,0 +1,78 @@ +{ + "schema_version": 1, + "kind": "judge.manifest", + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "submission_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000002", + "problem_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000003", + "language": "python", + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + }, + "source": { + "digest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bytes": 124 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 1 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 1 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 2 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 2 + } + } + ], + "comparison": "exact_bytes", + "compile_limits": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_limits": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "job_wall_time_us": 60000000 +} diff --git a/tests/fixtures/contracts/judge-manifest.invalid-semantic-duplicate-case.json b/tests/fixtures/contracts/judge-manifest.invalid-semantic-duplicate-case.json new file mode 100644 index 0000000..75bcfdb --- /dev/null +++ b/tests/fixtures/contracts/judge-manifest.invalid-semantic-duplicate-case.json @@ -0,0 +1,89 @@ +{ + "schema_version": 1, + "kind": "judge.manifest", + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "submission_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000002", + "problem_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000003", + "language": "cpp20", + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + }, + "source": { + "digest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bytes": 124 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 1 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 1 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 2 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 2 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + } + ], + "comparison": "exact_bytes", + "compile_limits": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_limits": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "job_wall_time_us": 60000000 +} diff --git a/tests/fixtures/contracts/judge-manifest.invalid-semantic-job-deadline.json b/tests/fixtures/contracts/judge-manifest.invalid-semantic-job-deadline.json new file mode 100644 index 0000000..2874c72 --- /dev/null +++ b/tests/fixtures/contracts/judge-manifest.invalid-semantic-job-deadline.json @@ -0,0 +1,78 @@ +{ + "schema_version": 1, + "kind": "judge.manifest", + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "submission_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000002", + "problem_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000003", + "language": "cpp20", + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + }, + "source": { + "digest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bytes": 124 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 1 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 1 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 2 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 2 + } + } + ], + "comparison": "exact_bytes", + "compile_limits": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_limits": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "job_wall_time_us": 1000 +} diff --git a/tests/fixtures/contracts/judge-manifest.invalid-semantic-nil-id.json b/tests/fixtures/contracts/judge-manifest.invalid-semantic-nil-id.json new file mode 100644 index 0000000..e470eda --- /dev/null +++ b/tests/fixtures/contracts/judge-manifest.invalid-semantic-nil-id.json @@ -0,0 +1,78 @@ +{ + "schema_version": 1, + "kind": "judge.manifest", + "evaluation_id": "00000000-0000-0000-0000-000000000000", + "submission_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000002", + "problem_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000003", + "language": "cpp20", + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + }, + "source": { + "digest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bytes": 124 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 1 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 1 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 2 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 2 + } + } + ], + "comparison": "exact_bytes", + "compile_limits": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_limits": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "job_wall_time_us": 60000000 +} diff --git a/tests/fixtures/contracts/judge-manifest.invalid-semantic-noncanonical-id.json b/tests/fixtures/contracts/judge-manifest.invalid-semantic-noncanonical-id.json new file mode 100644 index 0000000..166e8d8 --- /dev/null +++ b/tests/fixtures/contracts/judge-manifest.invalid-semantic-noncanonical-id.json @@ -0,0 +1,78 @@ +{ + "schema_version": 1, + "kind": "judge.manifest", + "evaluation_id": "AAAAAAAA-AAAA-4AAA-8AAA-000000000001", + "submission_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000002", + "problem_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000003", + "language": "cpp20", + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + }, + "source": { + "digest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bytes": 124 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 1 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 1 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 2 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 2 + } + } + ], + "comparison": "exact_bytes", + "compile_limits": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_limits": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "job_wall_time_us": 60000000 +} diff --git a/tests/fixtures/contracts/judge-manifest.invalid-semantic-output-budget.json b/tests/fixtures/contracts/judge-manifest.invalid-semantic-output-budget.json new file mode 100644 index 0000000..076be0e --- /dev/null +++ b/tests/fixtures/contracts/judge-manifest.invalid-semantic-output-budget.json @@ -0,0 +1,78 @@ +{ + "schema_version": 1, + "kind": "judge.manifest", + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "submission_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000002", + "problem_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000003", + "language": "cpp20", + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + }, + "source": { + "digest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bytes": 124 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 1 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 1 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 2 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 2 + } + } + ], + "comparison": "exact_bytes", + "compile_limits": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_limits": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "job_wall_time_us": 60000000 +} diff --git a/tests/fixtures/contracts/judge-manifest.invalid-semantic-package-size.json b/tests/fixtures/contracts/judge-manifest.invalid-semantic-package-size.json new file mode 100644 index 0000000..dbabec6 --- /dev/null +++ b/tests/fixtures/contracts/judge-manifest.invalid-semantic-package-size.json @@ -0,0 +1,78 @@ +{ + "schema_version": 1, + "kind": "judge.manifest", + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "submission_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000002", + "problem_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000003", + "language": "cpp20", + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + }, + "source": { + "digest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bytes": 124 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 67108864 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 1 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 1 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 2 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 2 + } + } + ], + "comparison": "exact_bytes", + "compile_limits": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_limits": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "job_wall_time_us": 60000000 +} diff --git a/tests/fixtures/contracts/judge-manifest.invalid-semantic-source-size.json b/tests/fixtures/contracts/judge-manifest.invalid-semantic-source-size.json new file mode 100644 index 0000000..c3a98f7 --- /dev/null +++ b/tests/fixtures/contracts/judge-manifest.invalid-semantic-source-size.json @@ -0,0 +1,78 @@ +{ + "schema_version": 1, + "kind": "judge.manifest", + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "submission_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000002", + "problem_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000003", + "language": "cpp20", + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + }, + "source": { + "digest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bytes": 262145 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 1 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 1 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 2 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 2 + } + } + ], + "comparison": "exact_bytes", + "compile_limits": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_limits": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "job_wall_time_us": 60000000 +} diff --git a/tests/fixtures/contracts/judge-manifest.invalid-semantic-stack.json b/tests/fixtures/contracts/judge-manifest.invalid-semantic-stack.json new file mode 100644 index 0000000..227f606 --- /dev/null +++ b/tests/fixtures/contracts/judge-manifest.invalid-semantic-stack.json @@ -0,0 +1,78 @@ +{ + "schema_version": 1, + "kind": "judge.manifest", + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "submission_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000002", + "problem_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000003", + "language": "cpp20", + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + }, + "source": { + "digest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bytes": 124 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 1 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 1 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 2 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 2 + } + } + ], + "comparison": "exact_bytes", + "compile_limits": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_limits": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 134217728, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "job_wall_time_us": 60000000 +} diff --git a/tests/fixtures/contracts/judge-manifest.invalid-semantic-version-float.json b/tests/fixtures/contracts/judge-manifest.invalid-semantic-version-float.json new file mode 100644 index 0000000..5370560 --- /dev/null +++ b/tests/fixtures/contracts/judge-manifest.invalid-semantic-version-float.json @@ -0,0 +1,78 @@ +{ + "schema_version": 1.0, + "kind": "judge.manifest", + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "submission_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000002", + "problem_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000003", + "language": "cpp20", + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + }, + "source": { + "digest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bytes": 124 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 1 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 1 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 2 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 2 + } + } + ], + "comparison": "exact_bytes", + "compile_limits": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_limits": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "job_wall_time_us": 60000000 +} diff --git a/tests/fixtures/contracts/judge-manifest.invalid-version-bool.json b/tests/fixtures/contracts/judge-manifest.invalid-version-bool.json new file mode 100644 index 0000000..784f24b --- /dev/null +++ b/tests/fixtures/contracts/judge-manifest.invalid-version-bool.json @@ -0,0 +1,78 @@ +{ + "schema_version": true, + "kind": "judge.manifest", + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "submission_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000002", + "problem_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000003", + "language": "cpp20", + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + }, + "source": { + "digest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bytes": 124 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 1 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 1 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 2 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 2 + } + } + ], + "comparison": "exact_bytes", + "compile_limits": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_limits": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "job_wall_time_us": 60000000 +} diff --git a/tests/fixtures/contracts/judge-manifest.invalid-zero-cpu.json b/tests/fixtures/contracts/judge-manifest.invalid-zero-cpu.json new file mode 100644 index 0000000..d957d5d --- /dev/null +++ b/tests/fixtures/contracts/judge-manifest.invalid-zero-cpu.json @@ -0,0 +1,78 @@ +{ + "schema_version": 1, + "kind": "judge.manifest", + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "submission_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000002", + "problem_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000003", + "language": "cpp20", + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + }, + "source": { + "digest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bytes": 124 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 1 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 1 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 2 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 2 + } + } + ], + "comparison": "exact_bytes", + "compile_limits": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_limits": { + "cpu_time_us": 0, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "job_wall_time_us": 60000000 +} diff --git a/tests/fixtures/contracts/judge-manifest.valid-c17.json b/tests/fixtures/contracts/judge-manifest.valid-c17.json new file mode 100644 index 0000000..84c3da4 --- /dev/null +++ b/tests/fixtures/contracts/judge-manifest.valid-c17.json @@ -0,0 +1,78 @@ +{ + "schema_version": 1, + "kind": "judge.manifest", + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "submission_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000002", + "problem_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000003", + "language": "c17", + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + }, + "source": { + "digest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bytes": 124 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 1 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 1 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 2 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 2 + } + } + ], + "comparison": "exact_bytes", + "compile_limits": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_limits": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "job_wall_time_us": 60000000 +} diff --git a/tests/fixtures/contracts/judge-manifest.valid.json b/tests/fixtures/contracts/judge-manifest.valid.json new file mode 100644 index 0000000..a25b746 --- /dev/null +++ b/tests/fixtures/contracts/judge-manifest.valid.json @@ -0,0 +1,78 @@ +{ + "schema_version": 1, + "kind": "judge.manifest", + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "submission_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000002", + "problem_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000003", + "language": "cpp20", + "toolchain": { + "toolchain_id": "gnu-cxx-v1", + "image_kind": "linux_gnu_cxx_x86_64_v1", + "image_revision": 1 + }, + "source": { + "digest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bytes": 124 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 0 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 0 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 1 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 1 + } + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "input": { + "digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "bytes": 2 + }, + "expected": { + "digest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "bytes": 2 + } + } + ], + "comparison": "exact_bytes", + "compile_limits": { + "cpu_time_us": 10000000, + "wall_time_us": 30000000, + "memory_bytes": 536870912, + "stack_bytes": 16777216, + "processes": 32, + "open_files": 128, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 67108864, + "workdir_bytes": 268435456 + }, + "run_limits": { + "cpu_time_us": 1000000, + "wall_time_us": 3000000, + "memory_bytes": 67108864, + "stack_bytes": 8388608, + "processes": 8, + "open_files": 64, + "stdout_bytes": 1048576, + "stderr_bytes": 1048576, + "file_bytes": 16777216, + "workdir_bytes": 67108864 + }, + "job_wall_time_us": 60000000 +} diff --git a/tests/fixtures/contracts/judge-result.invalid-extra.json b/tests/fixtures/contracts/judge-result.invalid-extra.json new file mode 100644 index 0000000..d886a5a --- /dev/null +++ b/tests/fixtures/contracts/judge-result.invalid-extra.json @@ -0,0 +1,48 @@ +{ + "schema_version": 1, + "kind": "judge.result", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "compilation": { + "status": "succeeded", + "program": { + "digest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "bytes": 4096 + }, + "diagnostics": "", + "diagnostics_truncated": false, + "cpu_time_us": 100000, + "memory_peak_bytes": 16777216 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "verdict": "accepted", + "cpu_time_us": 100, + "memory_peak_bytes": 262144 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "verdict": "accepted", + "cpu_time_us": 200, + "memory_peak_bytes": 524288 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "verdict": "accepted", + "cpu_time_us": 300, + "memory_peak_bytes": 524288 + } + ], + "verdict": "accepted", + "cleanup_complete": true, + "failure_code": null, + "run_cpu_time_us": 600, + "run_memory_peak_bytes": 524288, + "host_path": "/etc/passwd" +} diff --git a/tests/fixtures/contracts/judge-result.invalid-missing-metric.json b/tests/fixtures/contracts/judge-result.invalid-missing-metric.json new file mode 100644 index 0000000..74b1182 --- /dev/null +++ b/tests/fixtures/contracts/judge-result.invalid-missing-metric.json @@ -0,0 +1,46 @@ +{ + "schema_version": 1, + "kind": "judge.result", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "compilation": { + "status": "succeeded", + "program": { + "digest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "bytes": 4096 + }, + "diagnostics": "", + "diagnostics_truncated": false, + "cpu_time_us": 100000, + "memory_peak_bytes": 16777216 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "verdict": "accepted", + "memory_peak_bytes": 262144 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "verdict": "accepted", + "cpu_time_us": 200, + "memory_peak_bytes": 524288 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "verdict": "accepted", + "cpu_time_us": 300, + "memory_peak_bytes": 524288 + } + ], + "verdict": "accepted", + "cleanup_complete": true, + "failure_code": null, + "run_cpu_time_us": 600, + "run_memory_peak_bytes": 524288 +} diff --git a/tests/fixtures/contracts/judge-result.invalid-semantic-cleanup-success.json b/tests/fixtures/contracts/judge-result.invalid-semantic-cleanup-success.json new file mode 100644 index 0000000..8f48cac --- /dev/null +++ b/tests/fixtures/contracts/judge-result.invalid-semantic-cleanup-success.json @@ -0,0 +1,47 @@ +{ + "schema_version": 1, + "kind": "judge.result", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "compilation": { + "status": "succeeded", + "program": { + "digest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "bytes": 4096 + }, + "diagnostics": "", + "diagnostics_truncated": false, + "cpu_time_us": 100000, + "memory_peak_bytes": 16777216 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "verdict": "accepted", + "cpu_time_us": 100, + "memory_peak_bytes": 262144 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "verdict": "accepted", + "cpu_time_us": 200, + "memory_peak_bytes": 524288 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "verdict": "accepted", + "cpu_time_us": 300, + "memory_peak_bytes": 524288 + } + ], + "verdict": "accepted", + "cleanup_complete": false, + "failure_code": null, + "run_cpu_time_us": 600, + "run_memory_peak_bytes": 524288 +} diff --git a/tests/fixtures/contracts/judge-result.invalid-semantic-compile-output.json b/tests/fixtures/contracts/judge-result.invalid-semantic-compile-output.json new file mode 100644 index 0000000..3143875 --- /dev/null +++ b/tests/fixtures/contracts/judge-result.invalid-semantic-compile-output.json @@ -0,0 +1,47 @@ +{ + "schema_version": 1, + "kind": "judge.result", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "compilation": { + "status": "compilation_error", + "program": { + "digest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "bytes": 4096 + }, + "diagnostics": "", + "diagnostics_truncated": false, + "cpu_time_us": 100000, + "memory_peak_bytes": 16777216 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "verdict": "accepted", + "cpu_time_us": 100, + "memory_peak_bytes": 262144 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "verdict": "accepted", + "cpu_time_us": 200, + "memory_peak_bytes": 524288 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "verdict": "accepted", + "cpu_time_us": 300, + "memory_peak_bytes": 524288 + } + ], + "verdict": "accepted", + "cleanup_complete": true, + "failure_code": null, + "run_cpu_time_us": 600, + "run_memory_peak_bytes": 524288 +} diff --git a/tests/fixtures/contracts/judge-result.invalid-semantic-cpu-sum.json b/tests/fixtures/contracts/judge-result.invalid-semantic-cpu-sum.json new file mode 100644 index 0000000..6fbea52 --- /dev/null +++ b/tests/fixtures/contracts/judge-result.invalid-semantic-cpu-sum.json @@ -0,0 +1,47 @@ +{ + "schema_version": 1, + "kind": "judge.result", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "compilation": { + "status": "succeeded", + "program": { + "digest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "bytes": 4096 + }, + "diagnostics": "", + "diagnostics_truncated": false, + "cpu_time_us": 100000, + "memory_peak_bytes": 16777216 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "verdict": "accepted", + "cpu_time_us": 100, + "memory_peak_bytes": 262144 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "verdict": "accepted", + "cpu_time_us": 200, + "memory_peak_bytes": 524288 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "verdict": "accepted", + "cpu_time_us": 300, + "memory_peak_bytes": 524288 + } + ], + "verdict": "accepted", + "cleanup_complete": true, + "failure_code": null, + "run_cpu_time_us": 0, + "run_memory_peak_bytes": 524288 +} diff --git a/tests/fixtures/contracts/judge-result.invalid-semantic-diagnostics-bytes.json b/tests/fixtures/contracts/judge-result.invalid-semantic-diagnostics-bytes.json new file mode 100644 index 0000000..adf7e66 --- /dev/null +++ b/tests/fixtures/contracts/judge-result.invalid-semantic-diagnostics-bytes.json @@ -0,0 +1,47 @@ +{ + "schema_version": 1, + "kind": "judge.result", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "compilation": { + "status": "succeeded", + "program": { + "digest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "bytes": 4096 + }, + "diagnostics": "中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中中", + "diagnostics_truncated": false, + "cpu_time_us": 100000, + "memory_peak_bytes": 16777216 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "verdict": "accepted", + "cpu_time_us": 100, + "memory_peak_bytes": 262144 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "verdict": "accepted", + "cpu_time_us": 200, + "memory_peak_bytes": 524288 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "verdict": "accepted", + "cpu_time_us": 300, + "memory_peak_bytes": 524288 + } + ], + "verdict": "accepted", + "cleanup_complete": true, + "failure_code": null, + "run_cpu_time_us": 600, + "run_memory_peak_bytes": 524288 +} diff --git a/tests/fixtures/contracts/judge-result.invalid-semantic-empty-ac.json b/tests/fixtures/contracts/judge-result.invalid-semantic-empty-ac.json new file mode 100644 index 0000000..46bb39d --- /dev/null +++ b/tests/fixtures/contracts/judge-result.invalid-semantic-empty-ac.json @@ -0,0 +1,28 @@ +{ + "schema_version": 1, + "kind": "judge.result", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "compilation": { + "status": "succeeded", + "program": { + "digest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "bytes": 4096 + }, + "diagnostics": "", + "diagnostics_truncated": false, + "cpu_time_us": 100000, + "memory_peak_bytes": 16777216 + }, + "cases": [], + "verdict": "accepted", + "cleanup_complete": true, + "failure_code": null, + "run_cpu_time_us": null, + "run_memory_peak_bytes": null +} diff --git a/tests/fixtures/contracts/judge-result.invalid-semantic-fatal-followed-by-case.json b/tests/fixtures/contracts/judge-result.invalid-semantic-fatal-followed-by-case.json new file mode 100644 index 0000000..dbe8d05 --- /dev/null +++ b/tests/fixtures/contracts/judge-result.invalid-semantic-fatal-followed-by-case.json @@ -0,0 +1,47 @@ +{ + "schema_version": 1, + "kind": "judge.result", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "compilation": { + "status": "succeeded", + "program": { + "digest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "bytes": 4096 + }, + "diagnostics": "", + "diagnostics_truncated": false, + "cpu_time_us": 100000, + "memory_peak_bytes": 16777216 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "verdict": "system_error", + "cpu_time_us": 100, + "memory_peak_bytes": 262144 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "verdict": "accepted", + "cpu_time_us": 200, + "memory_peak_bytes": 524288 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "verdict": "accepted", + "cpu_time_us": 300, + "memory_peak_bytes": 524288 + } + ], + "verdict": "system_error", + "cleanup_complete": true, + "failure_code": "sandbox_unavailable", + "run_cpu_time_us": 600, + "run_memory_peak_bytes": 524288 +} diff --git a/tests/fixtures/contracts/judge-result.invalid-semantic-infrastructure-without-code.json b/tests/fixtures/contracts/judge-result.invalid-semantic-infrastructure-without-code.json new file mode 100644 index 0000000..898054b --- /dev/null +++ b/tests/fixtures/contracts/judge-result.invalid-semantic-infrastructure-without-code.json @@ -0,0 +1,47 @@ +{ + "schema_version": 1, + "kind": "judge.result", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "compilation": { + "status": "succeeded", + "program": { + "digest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "bytes": 4096 + }, + "diagnostics": "", + "diagnostics_truncated": false, + "cpu_time_us": 100000, + "memory_peak_bytes": 16777216 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "verdict": "accepted", + "cpu_time_us": 100, + "memory_peak_bytes": 262144 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "verdict": "accepted", + "cpu_time_us": 200, + "memory_peak_bytes": 524288 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "verdict": "accepted", + "cpu_time_us": 300, + "memory_peak_bytes": 524288 + } + ], + "verdict": "system_error", + "cleanup_complete": true, + "failure_code": null, + "run_cpu_time_us": 600, + "run_memory_peak_bytes": 524288 +} diff --git a/tests/fixtures/contracts/judge-result.invalid-semantic-runtime-ce.json b/tests/fixtures/contracts/judge-result.invalid-semantic-runtime-ce.json new file mode 100644 index 0000000..7493525 --- /dev/null +++ b/tests/fixtures/contracts/judge-result.invalid-semantic-runtime-ce.json @@ -0,0 +1,47 @@ +{ + "schema_version": 1, + "kind": "judge.result", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "compilation": { + "status": "succeeded", + "program": { + "digest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "bytes": 4096 + }, + "diagnostics": "", + "diagnostics_truncated": false, + "cpu_time_us": 100000, + "memory_peak_bytes": 16777216 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "verdict": "compilation_error", + "cpu_time_us": 100, + "memory_peak_bytes": 262144 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "verdict": "accepted", + "cpu_time_us": 200, + "memory_peak_bytes": 524288 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "verdict": "accepted", + "cpu_time_us": 300, + "memory_peak_bytes": 524288 + } + ], + "verdict": "accepted", + "cleanup_complete": true, + "failure_code": null, + "run_cpu_time_us": 600, + "run_memory_peak_bytes": 524288 +} diff --git a/tests/fixtures/contracts/judge-result.invalid-semantic-summary.json b/tests/fixtures/contracts/judge-result.invalid-semantic-summary.json new file mode 100644 index 0000000..0182487 --- /dev/null +++ b/tests/fixtures/contracts/judge-result.invalid-semantic-summary.json @@ -0,0 +1,47 @@ +{ + "schema_version": 1, + "kind": "judge.result", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "compilation": { + "status": "succeeded", + "program": { + "digest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "bytes": 4096 + }, + "diagnostics": "", + "diagnostics_truncated": false, + "cpu_time_us": 100000, + "memory_peak_bytes": 16777216 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "verdict": "wrong_answer", + "cpu_time_us": 100, + "memory_peak_bytes": 262144 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "verdict": "accepted", + "cpu_time_us": 200, + "memory_peak_bytes": 524288 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "verdict": "accepted", + "cpu_time_us": 300, + "memory_peak_bytes": 524288 + } + ], + "verdict": "accepted", + "cleanup_complete": true, + "failure_code": null, + "run_cpu_time_us": 600, + "run_memory_peak_bytes": 524288 +} diff --git a/tests/fixtures/contracts/judge-result.invalid-semantic-unknown-memory.json b/tests/fixtures/contracts/judge-result.invalid-semantic-unknown-memory.json new file mode 100644 index 0000000..a50f72a --- /dev/null +++ b/tests/fixtures/contracts/judge-result.invalid-semantic-unknown-memory.json @@ -0,0 +1,47 @@ +{ + "schema_version": 1, + "kind": "judge.result", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "compilation": { + "status": "succeeded", + "program": { + "digest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "bytes": 4096 + }, + "diagnostics": "", + "diagnostics_truncated": false, + "cpu_time_us": 100000, + "memory_peak_bytes": 16777216 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "verdict": "accepted", + "cpu_time_us": 100, + "memory_peak_bytes": null + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "verdict": "accepted", + "cpu_time_us": 200, + "memory_peak_bytes": 524288 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "verdict": "accepted", + "cpu_time_us": 300, + "memory_peak_bytes": 524288 + } + ], + "verdict": "accepted", + "cleanup_complete": true, + "failure_code": null, + "run_cpu_time_us": 600, + "run_memory_peak_bytes": 524288 +} diff --git a/tests/fixtures/contracts/judge-result.invalid-semantic-zero-program.json b/tests/fixtures/contracts/judge-result.invalid-semantic-zero-program.json new file mode 100644 index 0000000..fde2995 --- /dev/null +++ b/tests/fixtures/contracts/judge-result.invalid-semantic-zero-program.json @@ -0,0 +1,47 @@ +{ + "schema_version": 1, + "kind": "judge.result", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "compilation": { + "status": "succeeded", + "program": { + "digest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "bytes": 0 + }, + "diagnostics": "", + "diagnostics_truncated": false, + "cpu_time_us": 100000, + "memory_peak_bytes": 16777216 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "verdict": "accepted", + "cpu_time_us": 100, + "memory_peak_bytes": 262144 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "verdict": "accepted", + "cpu_time_us": 200, + "memory_peak_bytes": 524288 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "verdict": "accepted", + "cpu_time_us": 300, + "memory_peak_bytes": 524288 + } + ], + "verdict": "accepted", + "cleanup_complete": true, + "failure_code": null, + "run_cpu_time_us": 600, + "run_memory_peak_bytes": 524288 +} diff --git a/tests/fixtures/contracts/judge-result.valid-cancel-before-compile.json b/tests/fixtures/contracts/judge-result.valid-cancel-before-compile.json new file mode 100644 index 0000000..99f29a3 --- /dev/null +++ b/tests/fixtures/contracts/judge-result.valid-cancel-before-compile.json @@ -0,0 +1,25 @@ +{ + "schema_version": 1, + "kind": "judge.result", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "compilation": { + "status": "cancelled", + "program": null, + "diagnostics": "synthetic compiler diagnostic\n", + "diagnostics_truncated": false, + "cpu_time_us": 100000, + "memory_peak_bytes": 16777216 + }, + "cases": [], + "verdict": "cancelled", + "cleanup_complete": true, + "failure_code": null, + "run_cpu_time_us": null, + "run_memory_peak_bytes": null +} diff --git a/tests/fixtures/contracts/judge-result.valid-cancel-between-cases.json b/tests/fixtures/contracts/judge-result.valid-cancel-between-cases.json new file mode 100644 index 0000000..c47bacf --- /dev/null +++ b/tests/fixtures/contracts/judge-result.valid-cancel-between-cases.json @@ -0,0 +1,35 @@ +{ + "schema_version": 1, + "kind": "judge.result", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "compilation": { + "status": "succeeded", + "program": { + "digest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "bytes": 4096 + }, + "diagnostics": "", + "diagnostics_truncated": false, + "cpu_time_us": 100000, + "memory_peak_bytes": 16777216 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "verdict": "accepted", + "cpu_time_us": 100, + "memory_peak_bytes": 262144 + } + ], + "verdict": "cancelled", + "cleanup_complete": true, + "failure_code": null, + "run_cpu_time_us": 100, + "run_memory_peak_bytes": 262144 +} diff --git a/tests/fixtures/contracts/judge-result.valid-ce.json b/tests/fixtures/contracts/judge-result.valid-ce.json new file mode 100644 index 0000000..6ea8f51 --- /dev/null +++ b/tests/fixtures/contracts/judge-result.valid-ce.json @@ -0,0 +1,25 @@ +{ + "schema_version": 1, + "kind": "judge.result", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "compilation": { + "status": "compilation_error", + "program": null, + "diagnostics": "synthetic compiler diagnostic\n", + "diagnostics_truncated": false, + "cpu_time_us": 100000, + "memory_peak_bytes": 16777216 + }, + "cases": [], + "verdict": "compilation_error", + "cleanup_complete": true, + "failure_code": null, + "run_cpu_time_us": null, + "run_memory_peak_bytes": null +} diff --git a/tests/fixtures/contracts/judge-result.valid-cleanup-failure.json b/tests/fixtures/contracts/judge-result.valid-cleanup-failure.json new file mode 100644 index 0000000..f729dd3 --- /dev/null +++ b/tests/fixtures/contracts/judge-result.valid-cleanup-failure.json @@ -0,0 +1,47 @@ +{ + "schema_version": 1, + "kind": "judge.result", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "compilation": { + "status": "succeeded", + "program": { + "digest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "bytes": 4096 + }, + "diagnostics": "", + "diagnostics_truncated": false, + "cpu_time_us": 100000, + "memory_peak_bytes": 16777216 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "verdict": "accepted", + "cpu_time_us": 100, + "memory_peak_bytes": 262144 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "verdict": "accepted", + "cpu_time_us": 200, + "memory_peak_bytes": 524288 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "verdict": "accepted", + "cpu_time_us": 300, + "memory_peak_bytes": 524288 + } + ], + "verdict": "system_error", + "cleanup_complete": false, + "failure_code": "cleanup_failed", + "run_cpu_time_us": 600, + "run_memory_peak_bytes": 524288 +} diff --git a/tests/fixtures/contracts/judge-result.valid-compile-limit.json b/tests/fixtures/contracts/judge-result.valid-compile-limit.json new file mode 100644 index 0000000..5ff9c31 --- /dev/null +++ b/tests/fixtures/contracts/judge-result.valid-compile-limit.json @@ -0,0 +1,25 @@ +{ + "schema_version": 1, + "kind": "judge.result", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "compilation": { + "status": "compilation_limit", + "program": null, + "diagnostics": "synthetic compiler diagnostic\n", + "diagnostics_truncated": false, + "cpu_time_us": 100000, + "memory_peak_bytes": 16777216 + }, + "cases": [], + "verdict": "compilation_error", + "cleanup_complete": true, + "failure_code": null, + "run_cpu_time_us": null, + "run_memory_peak_bytes": null +} diff --git a/tests/fixtures/contracts/judge-result.valid-infrastructure-after-wa.json b/tests/fixtures/contracts/judge-result.valid-infrastructure-after-wa.json new file mode 100644 index 0000000..9c03544 --- /dev/null +++ b/tests/fixtures/contracts/judge-result.valid-infrastructure-after-wa.json @@ -0,0 +1,41 @@ +{ + "schema_version": 1, + "kind": "judge.result", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "compilation": { + "status": "succeeded", + "program": { + "digest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "bytes": 4096 + }, + "diagnostics": "", + "diagnostics_truncated": false, + "cpu_time_us": 100000, + "memory_peak_bytes": 16777216 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "verdict": "wrong_answer", + "cpu_time_us": 100, + "memory_peak_bytes": 262144 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "verdict": "system_error", + "cpu_time_us": null, + "memory_peak_bytes": null + } + ], + "verdict": "system_error", + "cleanup_complete": true, + "failure_code": "sandbox_unavailable", + "run_cpu_time_us": null, + "run_memory_peak_bytes": null +} diff --git a/tests/fixtures/contracts/judge-result.valid.json b/tests/fixtures/contracts/judge-result.valid.json new file mode 100644 index 0000000..9c8bba0 --- /dev/null +++ b/tests/fixtures/contracts/judge-result.valid.json @@ -0,0 +1,47 @@ +{ + "schema_version": 1, + "kind": "judge.result", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "manifest_digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "compilation": { + "status": "succeeded", + "program": { + "digest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "bytes": 4096 + }, + "diagnostics": "", + "diagnostics_truncated": false, + "cpu_time_us": 100000, + "memory_peak_bytes": 16777216 + }, + "cases": [ + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000004", + "verdict": "accepted", + "cpu_time_us": 100, + "memory_peak_bytes": 262144 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000005", + "verdict": "accepted", + "cpu_time_us": 200, + "memory_peak_bytes": 524288 + }, + { + "case_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000006", + "verdict": "accepted", + "cpu_time_us": 300, + "memory_peak_bytes": 524288 + } + ], + "verdict": "accepted", + "cleanup_complete": true, + "failure_code": null, + "run_cpu_time_us": 600, + "run_memory_peak_bytes": 524288 +} diff --git a/tests/fixtures/contracts/judge-stage.invalid-extra.json b/tests/fixtures/contracts/judge-stage.invalid-extra.json new file mode 100644 index 0000000..ade4a0b --- /dev/null +++ b/tests/fixtures/contracts/judge-stage.invalid-extra.json @@ -0,0 +1,14 @@ +{ + "schema_version": 1, + "kind": "judge.stage", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "sequence": 1, + "stage": "compiling", + "case_index": null, + "host_path": "/etc/passwd" +} diff --git a/tests/fixtures/contracts/judge-stage.invalid-index.json b/tests/fixtures/contracts/judge-stage.invalid-index.json new file mode 100644 index 0000000..644e675 --- /dev/null +++ b/tests/fixtures/contracts/judge-stage.invalid-index.json @@ -0,0 +1,13 @@ +{ + "schema_version": 1, + "kind": "judge.stage", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "sequence": 1, + "stage": "running", + "case_index": 256 +} diff --git a/tests/fixtures/contracts/judge-stage.invalid-missing-index.json b/tests/fixtures/contracts/judge-stage.invalid-missing-index.json new file mode 100644 index 0000000..1857d54 --- /dev/null +++ b/tests/fixtures/contracts/judge-stage.invalid-missing-index.json @@ -0,0 +1,12 @@ +{ + "schema_version": 1, + "kind": "judge.stage", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "sequence": 1, + "stage": "compiling" +} diff --git a/tests/fixtures/contracts/judge-stage.invalid-semantic-compiling-index.json b/tests/fixtures/contracts/judge-stage.invalid-semantic-compiling-index.json new file mode 100644 index 0000000..1eb3c3a --- /dev/null +++ b/tests/fixtures/contracts/judge-stage.invalid-semantic-compiling-index.json @@ -0,0 +1,13 @@ +{ + "schema_version": 1, + "kind": "judge.stage", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "sequence": 1, + "stage": "compiling", + "case_index": 0 +} diff --git a/tests/fixtures/contracts/judge-stage.invalid-semantic-running-null.json b/tests/fixtures/contracts/judge-stage.invalid-semantic-running-null.json new file mode 100644 index 0000000..3371f3b --- /dev/null +++ b/tests/fixtures/contracts/judge-stage.invalid-semantic-running-null.json @@ -0,0 +1,13 @@ +{ + "schema_version": 1, + "kind": "judge.stage", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "sequence": 1, + "stage": "running", + "case_index": null +} diff --git a/tests/fixtures/contracts/judge-stage.valid-running.json b/tests/fixtures/contracts/judge-stage.valid-running.json new file mode 100644 index 0000000..d6bb5f0 --- /dev/null +++ b/tests/fixtures/contracts/judge-stage.valid-running.json @@ -0,0 +1,13 @@ +{ + "schema_version": 1, + "kind": "judge.stage", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "sequence": 1, + "stage": "running", + "case_index": 0 +} diff --git a/tests/fixtures/contracts/judge-stage.valid.json b/tests/fixtures/contracts/judge-stage.valid.json new file mode 100644 index 0000000..ee4dda2 --- /dev/null +++ b/tests/fixtures/contracts/judge-stage.valid.json @@ -0,0 +1,13 @@ +{ + "schema_version": 1, + "kind": "judge.stage", + "binding": { + "evaluation_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001", + "attempt_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000007", + "worker_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000008", + "fencing_version": 1 + }, + "sequence": 1, + "stage": "compiling", + "case_index": null +} diff --git a/tests/fixtures/contracts/judge-state.transitions.json b/tests/fixtures/contracts/judge-state.transitions.json new file mode 100644 index 0000000..043353f --- /dev/null +++ b/tests/fixtures/contracts/judge-state.transitions.json @@ -0,0 +1,32 @@ +{ + "queued": [ + "claimed", + "cancelled" + ], + "claimed": [ + "compiling", + "cancelling", + "failed", + "queued" + ], + "compiling": [ + "running", + "finished", + "cancelling", + "failed", + "queued" + ], + "running": [ + "finished", + "cancelling", + "failed", + "queued" + ], + "cancelling": [ + "cancelled", + "failed" + ], + "finished": [], + "cancelled": [], + "failed": [] +} diff --git a/tests/fixtures/contracts/judge-task.invalid-semantic-version-float.json b/tests/fixtures/contracts/judge-task.invalid-semantic-version-float.json new file mode 100644 index 0000000..25e90d5 --- /dev/null +++ b/tests/fixtures/contracts/judge-task.invalid-semantic-version-float.json @@ -0,0 +1,5 @@ +{ + "schema_version": 1.0, + "kind": "judge.evaluation", + "evaluation_id": "018f26d6-713c-7b7f-8d5d-5f832a5f47f2" +} diff --git a/tests/fixtures/contracts/judge-task.invalid-version-bool.json b/tests/fixtures/contracts/judge-task.invalid-version-bool.json new file mode 100644 index 0000000..b2e8522 --- /dev/null +++ b/tests/fixtures/contracts/judge-task.invalid-version-bool.json @@ -0,0 +1,5 @@ +{ + "schema_version": true, + "kind": "judge.evaluation", + "evaluation_id": "018f26d6-713c-7b7f-8d5d-5f832a5f47f2" +}