From 6a40d263669d880a39503d59de4e5c49de8f4989 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Sun, 26 Apr 2026 18:52:39 -0400 Subject: [PATCH] Publish stable client proto inputs --- clients/dotnet/generated/.gitkeep | 1 + clients/go/internal/generated/.gitkeep | 1 + clients/java/src/main/generated/.gitkeep | 1 + .../descriptors/mxaccessgw-client-v1.protoset | Bin 0 -> 52832 bytes .../fixtures/golden/on-data-change-event.json | 28 + .../golden/open-session-reply.ok.json | 18 + .../golden/register-command-request.json | 10 + clients/proto/proto-inputs.json | 26 + .../python/src/mxgateway/generated/.gitkeep | 1 + clients/rust/src/generated/.gitkeep | 1 + docs/Contracts.md | 13 + docs/client-libraries-design.md | 15 + docs/client-proto-generation.md | 133 ++++ scripts/publish-client-proto-inputs.ps1 | 95 +++ .../GatewayContractInfo.cs | 2 + .../Generated/MxaccessGateway.cs | 576 ++++++++++-------- .../Protos/mxaccess_gateway.proto | 4 + .../Grpc/MxAccessGatewayService.cs | 1 + .../Contracts/ClientProtoInputTests.cs | 102 ++++ .../Contracts/GatewayContractInfoTests.cs | 6 + .../Grpc/MxAccessGatewayServiceTests.cs | 1 + 21 files changed, 768 insertions(+), 267 deletions(-) create mode 100644 clients/dotnet/generated/.gitkeep create mode 100644 clients/go/internal/generated/.gitkeep create mode 100644 clients/java/src/main/generated/.gitkeep create mode 100644 clients/proto/descriptors/mxaccessgw-client-v1.protoset create mode 100644 clients/proto/fixtures/golden/on-data-change-event.json create mode 100644 clients/proto/fixtures/golden/open-session-reply.ok.json create mode 100644 clients/proto/fixtures/golden/register-command-request.json create mode 100644 clients/proto/proto-inputs.json create mode 100644 clients/python/src/mxgateway/generated/.gitkeep create mode 100644 clients/rust/src/generated/.gitkeep create mode 100644 docs/client-proto-generation.md create mode 100644 scripts/publish-client-proto-inputs.ps1 create mode 100644 src/MxGateway.Tests/Contracts/ClientProtoInputTests.cs diff --git a/clients/dotnet/generated/.gitkeep b/clients/dotnet/generated/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/clients/dotnet/generated/.gitkeep @@ -0,0 +1 @@ + diff --git a/clients/go/internal/generated/.gitkeep b/clients/go/internal/generated/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/clients/go/internal/generated/.gitkeep @@ -0,0 +1 @@ + diff --git a/clients/java/src/main/generated/.gitkeep b/clients/java/src/main/generated/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/clients/java/src/main/generated/.gitkeep @@ -0,0 +1 @@ + diff --git a/clients/proto/descriptors/mxaccessgw-client-v1.protoset b/clients/proto/descriptors/mxaccessgw-client-v1.protoset new file mode 100644 index 0000000000000000000000000000000000000000..ab29fa9a717277d6b653e2ad32ffb6592470e272 GIT binary patch literal 52832 zcmeI5d3+s7b?@)(Ze2?)OP1Q3yiSii9!p-dd2Ek8GXYtWZOzz{=Ss4fnGEu^bZv`~ zbv3$@J%&dT_ALa0(=5tO(21UHSC1p1(J}2tS<>!Apt@XAn$wXRCQlT*UKcl z&*%NYd|*buu5(VEI#qS*)TzGJ;qPw`x1KMR&QBLRXXi@urLzm?Iwu$A3iDH?nGW+L zTBYTRC~rL!*7jSHs3lxcE>4tYCd)0^INRpu9gNn5H8X{oQn|(Bc}-ry;b&yS)f1(Q z9ZO^$Zg3J$iWVoc_jg;0^QGy+%=wPe-1$_&`75)-f3)=bp%k(IGwm?%xh zhZoMBE6$bUJ+X?~QI01I^M!b7X1+K#aRHTz@ww96#ln0T_myU^%uSuYFdz4Hb=__m z;=!4TjyUd}o{mjfIi4$)i*uKXlO17vVSawLe5kW?vUsUDU7DpLXAo?o?L>(^Xf8^0 zhGCp9PEM8Q=cdjsNYBKDnaOyeTtuC?Tw0i$D4Hi{r)COsSBzfe-SOqA`3rGr&iuEu zfSwmilT+uWCQRS%jtg_en3^w6&CeGnW4ij%)Fgk*UntD;FKONMbm{Wc%=uWlcS@=) z3lnmR^M_DL{@J-iv2t8G=QNrqO%~&e3*~uQK3_mnkyQ7>wOAO>l;)=NJ|&1gCQoS3sV=1b6B#v5>!@U3#SBaoLsQ2IfnPL?JX zE*59zjftg8IJ2jafrllSEZj~*M1j}0I1AIOiyy+i#x9U9FK9v&MV&X0s~YwrlG zt)`@R=)QR12`BRdBO~!}J{~-A^7tUq5TEZI8XX)M*&PoK^&KDU9~?TmJ4Ql0G&~x{ z#|KXgjzTv&yxUZ}oG%_e5}z2z_Z>q_@8QAYgQNGE3Xcqq4oPK4hVxY z9q-M@C&%(9herltX<7f^NZ;|^!4m`h9n?>q@xZBpq0xBcSnu)UiyIoo!>5M^@}hlZ zGvmVpXxV%C_<&SJ)%PJZKhQTS4NCv&!+0ooe0La+oE+#Iqdb(L-vjUNOiBgQIV>l8g!&D|B?)&Uk3x=<&g$ z14DfSqR+61IXyTs&`yU9qT5lCDP}(1OQj4HDwYw6UUZTCT`_bqGW{739*KMVPa&k= zQ8NNY2JLWxX=JSLn6){>zc$QzksoJTcj1s4)YL6@~1w$HPdPyhLJCS>cbtGo6W;pB47U0hi#cV%){-GFMqzK zDfEI&6ckzbHomxtvF%n}T=cB0PcwLeLR_9YKU19C9iN+eq&T@}x;S&5m83jdm=PB= zkLOLvi<4no5T1$B!i@3VHXJYu(z&_9gf1MiENGk%v%Z+Xz`#(J#nQA{)tE=~F@9%i zX0kYouRY-xXI$5~V8j4SAy@>C-(CWm@6{qpJ z#_^4!b9ugSaaJ9*UEx>_Sze0>!%5CxE*58Se3wgcN`0v?y--9UX<%Y1S$n7EQHe!{ z1#MDRO=>SMoSm2EibceU!jcH;i1Q|55J9uJ+()KlIhei@@7mMdwY#gUE51@J5Cq^p zx5WdGpy+h546uL3-G>M=F3v9CuoE>*9gEZz%f++h;=*K!?wBl!IQb`0BgO`E^YLAA zM@PpUOUtnDqLQSdNgM0AQe|{cJ6yNkCCf{K_Gn!W+u9N)GXM}MEc&-&Fz61e`P8|% zE#Yw$-5Gbqx852j&z1kj;;#1iDXLqX7CNR~cg5XSiHcHNHD&aH{$q)r8W*P}zN)4G zRaH>{wXUVWo@*!|%DMWxoB|cy-;;KK+LxyPQ@AS~8IOGw^t�Ms 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 LPuaD{9kBmjq@dp{ literal 0 HcmV?d00001 diff --git a/clients/proto/fixtures/golden/on-data-change-event.json b/clients/proto/fixtures/golden/on-data-change-event.json new file mode 100644 index 0000000..de30480 --- /dev/null +++ b/clients/proto/fixtures/golden/on-data-change-event.json @@ -0,0 +1,28 @@ +{ + "family": "MX_EVENT_FAMILY_ON_DATA_CHANGE", + "sessionId": "session-fixture", + "serverHandle": 12, + "itemHandle": 34, + "value": { + "dataType": "MX_DATA_TYPE_INTEGER", + "variantType": "VT_I4", + "int32Value": 123 + }, + "quality": 192, + "sourceTimestamp": "2026-01-01T00:00:00Z", + "statuses": [ + { + "success": 1, + "category": "MX_STATUS_CATEGORY_OK", + "detectedBy": "MX_STATUS_SOURCE_RESPONDING_LMX", + "detail": 0, + "rawCategory": 0, + "rawDetectedBy": 0, + "diagnosticText": "OK" + } + ], + "workerSequence": "1", + "workerTimestamp": "2026-01-01T00:00:00.010Z", + "gatewayReceiveTimestamp": "2026-01-01T00:00:00.015Z", + "onDataChange": {} +} diff --git a/clients/proto/fixtures/golden/open-session-reply.ok.json b/clients/proto/fixtures/golden/open-session-reply.ok.json new file mode 100644 index 0000000..8d5bb49 --- /dev/null +++ b/clients/proto/fixtures/golden/open-session-reply.ok.json @@ -0,0 +1,18 @@ +{ + "sessionId": "session-fixture", + "backendName": "mxaccess-worker", + "workerProcessId": 1234, + "workerProtocolVersion": 1, + "gatewayProtocolVersion": 1, + "capabilities": [ + "unary-open-session", + "unary-close-session", + "unary-invoke", + "server-stream-events" + ], + "defaultCommandTimeout": "30s", + "protocolStatus": { + "code": "PROTOCOL_STATUS_CODE_OK", + "message": "Session opened." + } +} diff --git a/clients/proto/fixtures/golden/register-command-request.json b/clients/proto/fixtures/golden/register-command-request.json new file mode 100644 index 0000000..fd6fbd0 --- /dev/null +++ b/clients/proto/fixtures/golden/register-command-request.json @@ -0,0 +1,10 @@ +{ + "sessionId": "session-fixture", + "clientCorrelationId": "fixture-register-1", + "command": { + "kind": "MX_COMMAND_KIND_REGISTER", + "register": { + "clientName": "fixture-client" + } + } +} diff --git a/clients/proto/proto-inputs.json b/clients/proto/proto-inputs.json new file mode 100644 index 0000000..3d1f75e --- /dev/null +++ b/clients/proto/proto-inputs.json @@ -0,0 +1,26 @@ +{ + "schemaVersion": 1, + "contractName": "mxaccess-gateway", + "gatewayProtocolVersion": 1, + "workerProtocolVersion": 1, + "protoRoot": "src/MxGateway.Contracts/Protos", + "sourceFiles": [ + { + "path": "mxaccess_gateway.proto", + "role": "public_gateway" + }, + { + "path": "mxaccess_worker.proto", + "role": "gateway_worker_ipc" + } + ], + "descriptorSet": "clients/proto/descriptors/mxaccessgw-client-v1.protoset", + "fixtureRoot": "clients/proto/fixtures/golden", + "generatedOutputs": { + "dotnet": "clients/dotnet/generated", + "go": "clients/go/internal/generated", + "rust": "clients/rust/src/generated", + "python": "clients/python/src/mxgateway/generated", + "java": "clients/java/src/main/generated" + } +} diff --git a/clients/python/src/mxgateway/generated/.gitkeep b/clients/python/src/mxgateway/generated/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/clients/python/src/mxgateway/generated/.gitkeep @@ -0,0 +1 @@ + diff --git a/clients/rust/src/generated/.gitkeep b/clients/rust/src/generated/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/clients/rust/src/generated/.gitkeep @@ -0,0 +1 @@ + diff --git a/docs/Contracts.md b/docs/Contracts.md index bc64d85..f683104 100644 --- a/docs/Contracts.md +++ b/docs/Contracts.md @@ -18,6 +18,12 @@ event, value, and status shapes. Generated C# output is written to `src/MxGateway.Contracts/Generated/`. Do not hand-edit generated files. +Client generation inputs are published through +`clients/proto/proto-inputs.json` and the descriptor set under +`clients/proto/descriptors/`. See +[Client Proto Generation](./client-proto-generation.md) for language-specific +generation inputs, output directories, and golden protobuf JSON fixtures. + ## Generation Run the contracts build to regenerate C# protobuf and gRPC code: @@ -39,8 +45,15 @@ gateway and test projects: dotnet build src/MxGateway.sln ``` +Regenerate the client descriptor after changing either `.proto` file: + +```bash +powershell -ExecutionPolicy Bypass -File scripts/publish-client-proto-inputs.ps1 +``` + ## Related Documentation +- [Client Proto Generation](./client-proto-generation.md) - [Gateway Process Detailed Design](./gateway-process-design.md) - [MXAccess Worker Instance Detailed Design](./mxaccess-worker-instance-design.md) - [Protobuf Style Guide](./style-guides/ProtobufStyleGuide.md) diff --git a/docs/client-libraries-design.md b/docs/client-libraries-design.md index e5e7dad..b2cf188 100644 --- a/docs/client-libraries-design.md +++ b/docs/client-libraries-design.md @@ -26,6 +26,11 @@ Language-specific plans: - `docs/clients-python-design.md` - `docs/clients-java-design.md` +Shared generation inputs: + +- `docs/client-proto-generation.md` +- `clients/proto/proto-inputs.json` + Language style guides: | Client | Style guide | @@ -365,6 +370,16 @@ examples/ Generated code should be reproducible from `src/MxGateway.Contracts/Protos/`. Do not hand-edit generated code. +The stable client proto manifest defines the generated-code directories: + +```text +clients/dotnet/generated +clients/go/internal/generated +clients/rust/src/generated +clients/python/src/mxgateway/generated +clients/java/src/main/generated +``` + ## Versioning All clients should expose: diff --git a/docs/client-proto-generation.md b/docs/client-proto-generation.md new file mode 100644 index 0000000..88f8a92 --- /dev/null +++ b/docs/client-proto-generation.md @@ -0,0 +1,133 @@ +# Client Proto Generation + +This document defines the stable protobuf inputs that official clients use to +generate language-specific gRPC bindings. The checked-in `.proto` files remain +the source of truth so clients do not drift from the gateway and worker +contracts. + +## Stable Inputs + +The stable client input manifest is `clients/proto/proto-inputs.json`. It +records: + +- the public gateway protocol version, +- the worker IPC protocol version, +- the protobuf import root, +- the public and worker source files, +- the descriptor set path, +- golden fixture locations, +- generated-code output directories for each planned client. + +The source files listed by the manifest are: + +- `src/MxGateway.Contracts/Protos/mxaccess_gateway.proto` +- `src/MxGateway.Contracts/Protos/mxaccess_worker.proto` + +`mxaccess_gateway.proto` defines the public gRPC service and shared DTOs. +`mxaccess_worker.proto` is included in the descriptor because worker-aware +tests and fake-worker clients need the same command, reply, event, value, and +status shapes. + +## Protocol Version + +`GatewayContractInfo.GatewayProtocolVersion` is the public gateway protocol +version. `OpenSessionReply.gateway_protocol_version` returns the same value so +clients can compare their generated bindings against the gateway before issuing +MXAccess commands. + +`GatewayContractInfo.WorkerProtocolVersion` remains the gateway-to-worker IPC +protocol version. It is also present in `OpenSessionReply` because parity +fixtures and fake-worker tests need to know the worker contract used by the +session. + +## Descriptor Publishing + +Run this command after changing either source `.proto` file or the client proto +manifest: + +```powershell +scripts/publish-client-proto-inputs.ps1 +``` + +The script writes +`clients/proto/descriptors/mxaccessgw-client-v1.protoset` with imports and +source information included. The descriptor is a generated artifact; do not edit +it by hand. + +Use the check mode in CI or before committing: + +```powershell +scripts/publish-client-proto-inputs.ps1 -Check +``` + +`-Check` rebuilds the descriptor in a temporary path and fails when the checked +in descriptor is stale. + +## Output Directories + +The manifest declares these generated-code directories: + +| Client | Directory | +|--------|-----------| +| .NET | `clients/dotnet/generated` | +| Go | `clients/go/internal/generated` | +| Rust | `clients/rust/src/generated` | +| Python | `clients/python/src/mxgateway/generated` | +| Java | `clients/java/src/main/generated` | + +Only generator output belongs in these directories. Handwritten client wrappers +belong in the language-specific source trees created by the client scaffold +issues. + +## Language Generation Inputs + +All generators use `src/MxGateway.Contracts/Protos` as the protobuf import +root. The checked-in descriptor is available when a language build prefers a +descriptor input, but the `.proto` files remain canonical. + +.NET generation currently runs through the contracts project: + +```powershell +dotnet build src/MxGateway.Contracts/MxGateway.Contracts.csproj +``` + +Future .NET client projects may either reference `MxGateway.Contracts` or +generate client-local files into `clients/dotnet/generated` with `Grpc.Tools`. + +Go clients should generate `mxaccess_gateway.proto` and +`mxaccess_worker.proto` into `clients/go/internal/generated` with +`protoc-gen-go` and `protoc-gen-go-grpc`. Keep generated packages internal +unless the wrapper API intentionally exposes raw protobuf messages. + +Rust clients should use `tonic-build` or the selected protobuf generator from +the Rust client build script, with generated modules placed under +`clients/rust/src/generated` or included from the build output according to the +client crate design. + +Python clients should use `grpc_tools.protoc` and write generated modules under +`clients/python/src/mxgateway/generated` so imports stay separate from +handwritten async wrappers. + +Java clients should use the Gradle protobuf plugin and write generated sources +under `clients/java/src/main/generated`. The Java client scaffold owns the +Gradle plugin versions and source-set wiring. + +## Golden Fixtures + +Golden protobuf JSON fixtures live in `clients/proto/fixtures/golden`. They +exercise payloads that every language client must parse: + +- `open-session-reply.ok.json` +- `register-command-request.json` +- `on-data-change-event.json` + +The fixtures use protobuf JSON field names and enum values. Contract tests parse +them with the generated C# types so schema drift is caught before client +generation work starts. + +## Related Documentation + +- [Protobuf Contracts](./Contracts.md) +- [Client Libraries Detailed Design](./client-libraries-design.md) +- [Client Libraries Implementation Plan](./implementation-plan-clients.md) +- [Protobuf Style Guide](./style-guides/ProtobufStyleGuide.md) diff --git a/scripts/publish-client-proto-inputs.ps1 b/scripts/publish-client-proto-inputs.ps1 new file mode 100644 index 0000000..f4c5751 --- /dev/null +++ b/scripts/publish-client-proto-inputs.ps1 @@ -0,0 +1,95 @@ +[CmdletBinding()] +param( + [switch]$Check +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..") +$protoRoot = Join-Path $repoRoot "src/MxGateway.Contracts/Protos" +$manifestPath = Join-Path $repoRoot "clients/proto/proto-inputs.json" +$descriptorPath = Join-Path $repoRoot "clients/proto/descriptors/mxaccessgw-client-v1.protoset" + +function Resolve-Protoc { + $pathCommand = Get-Command "protoc.exe" -ErrorAction SilentlyContinue + if ($null -ne $pathCommand) { + return $pathCommand.Source + } + + $documentedPath = Join-Path $env:LOCALAPPDATA "Microsoft/WinGet/Packages/Google.Protobuf_Microsoft.Winget.Source_8wekyb3d8bbwe/bin/protoc.exe" + if (Test-Path $documentedPath) { + return $documentedPath + } + + throw "Could not find protoc.exe. See docs/toolchain-links.md for the documented protobuf toolchain path." +} + +function Ensure-Directory { + param([string]$Path) + + if (-not (Test-Path $Path)) { + New-Item -ItemType Directory -Path $Path | Out-Null + } +} + +function Compare-FileBytes { + param( + [string]$ExpectedPath, + [string]$ActualPath + ) + + if (-not (Test-Path $ExpectedPath)) { + return $false + } + + $expected = [System.IO.File]::ReadAllBytes($ExpectedPath) + $actual = [System.IO.File]::ReadAllBytes($ActualPath) + if ($expected.Length -ne $actual.Length) { + return $false + } + + for ($index = 0; $index -lt $expected.Length; $index++) { + if ($expected[$index] -ne $actual[$index]) { + return $false + } + } + + return $true +} + +$manifest = Get-Content -Raw $manifestPath | ConvertFrom-Json + +Ensure-Directory (Split-Path $descriptorPath -Parent) +foreach ($output in $manifest.generatedOutputs.PSObject.Properties.Value) { + Ensure-Directory (Join-Path $repoRoot $output) +} + +$protoc = Resolve-Protoc +$outputPath = $descriptorPath +if ($Check) { + $outputPath = Join-Path ([System.IO.Path]::GetTempPath()) ("mxaccessgw-client-v1-" + [System.Guid]::NewGuid().ToString("N") + ".protoset") +} + +try { + & $protoc ` + "--proto_path=$protoRoot" ` + "--include_imports" ` + "--include_source_info" ` + "--descriptor_set_out=$outputPath" ` + "mxaccess_gateway.proto" ` + "mxaccess_worker.proto" + + if ($LASTEXITCODE -ne 0) { + throw "protoc failed with exit code $LASTEXITCODE." + } + + if ($Check -and -not (Compare-FileBytes -ExpectedPath $descriptorPath -ActualPath $outputPath)) { + throw "Client proto descriptor is stale. Run scripts/publish-client-proto-inputs.ps1 and commit the updated descriptor." + } +} +finally { + if ($Check -and (Test-Path $outputPath)) { + Remove-Item -LiteralPath $outputPath + } +} diff --git a/src/MxGateway.Contracts/GatewayContractInfo.cs b/src/MxGateway.Contracts/GatewayContractInfo.cs index 22bcb20..cfc34d9 100644 --- a/src/MxGateway.Contracts/GatewayContractInfo.cs +++ b/src/MxGateway.Contracts/GatewayContractInfo.cs @@ -6,6 +6,8 @@ namespace MxGateway.Contracts; /// public static class GatewayContractInfo { + public const uint GatewayProtocolVersion = 1; + public const uint WorkerProtocolVersion = 1; public const string DefaultBackendName = "mxaccess-worker"; diff --git a/src/MxGateway.Contracts/Generated/MxaccessGateway.cs b/src/MxGateway.Contracts/Generated/MxaccessGateway.cs index 7cf72d4..9d2f179 100644 --- a/src/MxGateway.Contracts/Generated/MxaccessGateway.cs +++ b/src/MxGateway.Contracts/Generated/MxaccessGateway.cs @@ -30,282 +30,282 @@ namespace MxGateway.Contracts.Proto { "ChFyZXF1ZXN0ZWRfYmFja2VuZBgBIAEoCRIbChNjbGllbnRfc2Vzc2lvbl9u", "YW1lGAIgASgJEh0KFWNsaWVudF9jb3JyZWxhdGlvbl9pZBgDIAEoCRIyCg9j", "b21tYW5kX3RpbWVvdXQYBCABKAsyGS5nb29nbGUucHJvdG9idWYuRHVyYXRp", - "b24iiAIKEE9wZW5TZXNzaW9uUmVwbHkSEgoKc2Vzc2lvbl9pZBgBIAEoCRIU", + "b24iqgIKEE9wZW5TZXNzaW9uUmVwbHkSEgoKc2Vzc2lvbl9pZBgBIAEoCRIU", "CgxiYWNrZW5kX25hbWUYAiABKAkSGQoRd29ya2VyX3Byb2Nlc3NfaWQYAyAB", "KAUSHwoXd29ya2VyX3Byb3RvY29sX3ZlcnNpb24YBCABKA0SFAoMY2FwYWJp", "bGl0aWVzGAUgAygJEjoKF2RlZmF1bHRfY29tbWFuZF90aW1lb3V0GAYgASgL", "MhkuZ29vZ2xlLnByb3RvYnVmLkR1cmF0aW9uEjwKD3Byb3RvY29sX3N0YXR1", - "cxgHIAEoCzIjLm14YWNjZXNzX2dhdGV3YXkudjEuUHJvdG9jb2xTdGF0dXMi", - "SAoTQ2xvc2VTZXNzaW9uUmVxdWVzdBISCgpzZXNzaW9uX2lkGAEgASgJEh0K", - "FWNsaWVudF9jb3JyZWxhdGlvbl9pZBgCIAEoCSKdAQoRQ2xvc2VTZXNzaW9u", - "UmVwbHkSEgoKc2Vzc2lvbl9pZBgBIAEoCRI2CgtmaW5hbF9zdGF0ZRgCIAEo", - "DjIhLm14YWNjZXNzX2dhdGV3YXkudjEuU2Vzc2lvblN0YXRlEjwKD3Byb3Rv", - "Y29sX3N0YXR1cxgDIAEoCzIjLm14YWNjZXNzX2dhdGV3YXkudjEuUHJvdG9j", - "b2xTdGF0dXMiSAoTU3RyZWFtRXZlbnRzUmVxdWVzdBISCgpzZXNzaW9uX2lk", - "GAEgASgJEh0KFWFmdGVyX3dvcmtlcl9zZXF1ZW5jZRgCIAEoBCJ2ChBNeENv", - "bW1hbmRSZXF1ZXN0EhIKCnNlc3Npb25faWQYASABKAkSHQoVY2xpZW50X2Nv", - "cnJlbGF0aW9uX2lkGAIgASgJEi8KB2NvbW1hbmQYAyABKAsyHi5teGFjY2Vz", - "c19nYXRld2F5LnYxLk14Q29tbWFuZCKiDAoJTXhDb21tYW5kEjAKBGtpbmQY", - "ASABKA4yIi5teGFjY2Vzc19nYXRld2F5LnYxLk14Q29tbWFuZEtpbmQSOAoI", - "cmVnaXN0ZXIYCiABKAsyJC5teGFjY2Vzc19nYXRld2F5LnYxLlJlZ2lzdGVy", - "Q29tbWFuZEgAEjwKCnVucmVnaXN0ZXIYCyABKAsyJi5teGFjY2Vzc19nYXRl", - "d2F5LnYxLlVucmVnaXN0ZXJDb21tYW5kSAASNwoIYWRkX2l0ZW0YDCABKAsy", - "Iy5teGFjY2Vzc19nYXRld2F5LnYxLkFkZEl0ZW1Db21tYW5kSAASOQoJYWRk", - "X2l0ZW0yGA0gASgLMiQubXhhY2Nlc3NfZ2F0ZXdheS52MS5BZGRJdGVtMkNv", - "bW1hbmRIABI9CgtyZW1vdmVfaXRlbRgOIAEoCzImLm14YWNjZXNzX2dhdGV3", - "YXkudjEuUmVtb3ZlSXRlbUNvbW1hbmRIABI0CgZhZHZpc2UYDyABKAsyIi5t", - "eGFjY2Vzc19nYXRld2F5LnYxLkFkdmlzZUNvbW1hbmRIABI5Cgl1bl9hZHZp", - "c2UYECABKAsyJC5teGFjY2Vzc19nYXRld2F5LnYxLlVuQWR2aXNlQ29tbWFu", - "ZEgAEksKEmFkdmlzZV9zdXBlcnZpc29yeRgRIAEoCzItLm14YWNjZXNzX2dh", - "dGV3YXkudjEuQWR2aXNlU3VwZXJ2aXNvcnlDb21tYW5kSAASSAoRYWRkX2J1", - "ZmZlcmVkX2l0ZW0YEiABKAsyKy5teGFjY2Vzc19nYXRld2F5LnYxLkFkZEJ1", - "ZmZlcmVkSXRlbUNvbW1hbmRIABJdChxzZXRfYnVmZmVyZWRfdXBkYXRlX2lu", - "dGVydmFsGBMgASgLMjUubXhhY2Nlc3NfZ2F0ZXdheS52MS5TZXRCdWZmZXJl", - "ZFVwZGF0ZUludGVydmFsQ29tbWFuZEgAEjYKB3N1c3BlbmQYFCABKAsyIy5t", - "eGFjY2Vzc19nYXRld2F5LnYxLlN1c3BlbmRDb21tYW5kSAASOAoIYWN0aXZh", - "dGUYFSABKAsyJC5teGFjY2Vzc19nYXRld2F5LnYxLkFjdGl2YXRlQ29tbWFu", - "ZEgAEjIKBXdyaXRlGBYgASgLMiEubXhhY2Nlc3NfZ2F0ZXdheS52MS5Xcml0", - "ZUNvbW1hbmRIABI0CgZ3cml0ZTIYFyABKAsyIi5teGFjY2Vzc19nYXRld2F5", - "LnYxLldyaXRlMkNvbW1hbmRIABJBCg13cml0ZV9zZWN1cmVkGBggASgLMigu", - "bXhhY2Nlc3NfZ2F0ZXdheS52MS5Xcml0ZVNlY3VyZWRDb21tYW5kSAASQwoO", - "d3JpdGVfc2VjdXJlZDIYGSABKAsyKS5teGFjY2Vzc19nYXRld2F5LnYxLldy", - "aXRlU2VjdXJlZDJDb21tYW5kSAASSQoRYXV0aGVudGljYXRlX3VzZXIYGiAB", - "KAsyLC5teGFjY2Vzc19nYXRld2F5LnYxLkF1dGhlbnRpY2F0ZVVzZXJDb21t", - "YW5kSAASTQoUYXJjaGVzdHJhX3VzZXJfdG9faWQYGyABKAsyLS5teGFjY2Vz", - "c19nYXRld2F5LnYxLkFyY2hlc3RyQVVzZXJUb0lkQ29tbWFuZEgAEjAKBHBp", - "bmcYZCABKAsyIC5teGFjY2Vzc19nYXRld2F5LnYxLlBpbmdDb21tYW5kSAAS", - "SAoRZ2V0X3Nlc3Npb25fc3RhdGUYZSABKAsyKy5teGFjY2Vzc19nYXRld2F5", - "LnYxLkdldFNlc3Npb25TdGF0ZUNvbW1hbmRIABJECg9nZXRfd29ya2VyX2lu", - "Zm8YZiABKAsyKS5teGFjY2Vzc19nYXRld2F5LnYxLkdldFdvcmtlckluZm9D", - "b21tYW5kSAASPwoMZHJhaW5fZXZlbnRzGGcgASgLMicubXhhY2Nlc3NfZ2F0", - "ZXdheS52MS5EcmFpbkV2ZW50c0NvbW1hbmRIABJFCg9zaHV0ZG93bl93b3Jr", - "ZXIYaCABKAsyKi5teGFjY2Vzc19nYXRld2F5LnYxLlNodXRkb3duV29ya2Vy", - "Q29tbWFuZEgAQgkKB3BheWxvYWQiJgoPUmVnaXN0ZXJDb21tYW5kEhMKC2Ns", - "aWVudF9uYW1lGAEgASgJIioKEVVucmVnaXN0ZXJDb21tYW5kEhUKDXNlcnZl", - "cl9oYW5kbGUYASABKAUiQAoOQWRkSXRlbUNvbW1hbmQSFQoNc2VydmVyX2hh", - "bmRsZRgBIAEoBRIXCg9pdGVtX2RlZmluaXRpb24YAiABKAkiVwoPQWRkSXRl", - "bTJDb21tYW5kEhUKDXNlcnZlcl9oYW5kbGUYASABKAUSFwoPaXRlbV9kZWZp", - "bml0aW9uGAIgASgJEhQKDGl0ZW1fY29udGV4dBgDIAEoCSI/ChFSZW1vdmVJ", - "dGVtQ29tbWFuZBIVCg1zZXJ2ZXJfaGFuZGxlGAEgASgFEhMKC2l0ZW1faGFu", - "ZGxlGAIgASgFIjsKDUFkdmlzZUNvbW1hbmQSFQoNc2VydmVyX2hhbmRsZRgB", - "IAEoBRITCgtpdGVtX2hhbmRsZRgCIAEoBSI9Cg9VbkFkdmlzZUNvbW1hbmQS", - "FQoNc2VydmVyX2hhbmRsZRgBIAEoBRITCgtpdGVtX2hhbmRsZRgCIAEoBSJG", - "ChhBZHZpc2VTdXBlcnZpc29yeUNvbW1hbmQSFQoNc2VydmVyX2hhbmRsZRgB", - "IAEoBRITCgtpdGVtX2hhbmRsZRgCIAEoBSJeChZBZGRCdWZmZXJlZEl0ZW1D", - "b21tYW5kEhUKDXNlcnZlcl9oYW5kbGUYASABKAUSFwoPaXRlbV9kZWZpbml0", - "aW9uGAIgASgJEhQKDGl0ZW1fY29udGV4dBgDIAEoCSJfCiBTZXRCdWZmZXJl", - "ZFVwZGF0ZUludGVydmFsQ29tbWFuZBIVCg1zZXJ2ZXJfaGFuZGxlGAEgASgF", - "EiQKHHVwZGF0ZV9pbnRlcnZhbF9taWxsaXNlY29uZHMYAiABKAUiPAoOU3Vz", - "cGVuZENvbW1hbmQSFQoNc2VydmVyX2hhbmRsZRgBIAEoBRITCgtpdGVtX2hh", - "bmRsZRgCIAEoBSI9Cg9BY3RpdmF0ZUNvbW1hbmQSFQoNc2VydmVyX2hhbmRs", - "ZRgBIAEoBRITCgtpdGVtX2hhbmRsZRgCIAEoBSJ4CgxXcml0ZUNvbW1hbmQS", - "FQoNc2VydmVyX2hhbmRsZRgBIAEoBRITCgtpdGVtX2hhbmRsZRgCIAEoBRIr", - "CgV2YWx1ZRgDIAEoCzIcLm14YWNjZXNzX2dhdGV3YXkudjEuTXhWYWx1ZRIP", - "Cgd1c2VyX2lkGAQgASgFIrABCg1Xcml0ZTJDb21tYW5kEhUKDXNlcnZlcl9o", + "cxgHIAEoCzIjLm14YWNjZXNzX2dhdGV3YXkudjEuUHJvdG9jb2xTdGF0dXMS", + "IAoYZ2F0ZXdheV9wcm90b2NvbF92ZXJzaW9uGAggASgNIkgKE0Nsb3NlU2Vz", + "c2lvblJlcXVlc3QSEgoKc2Vzc2lvbl9pZBgBIAEoCRIdChVjbGllbnRfY29y", + "cmVsYXRpb25faWQYAiABKAkinQEKEUNsb3NlU2Vzc2lvblJlcGx5EhIKCnNl", + "c3Npb25faWQYASABKAkSNgoLZmluYWxfc3RhdGUYAiABKA4yIS5teGFjY2Vz", + "c19nYXRld2F5LnYxLlNlc3Npb25TdGF0ZRI8Cg9wcm90b2NvbF9zdGF0dXMY", + "AyABKAsyIy5teGFjY2Vzc19nYXRld2F5LnYxLlByb3RvY29sU3RhdHVzIkgK", + "E1N0cmVhbUV2ZW50c1JlcXVlc3QSEgoKc2Vzc2lvbl9pZBgBIAEoCRIdChVh", + "ZnRlcl93b3JrZXJfc2VxdWVuY2UYAiABKAQidgoQTXhDb21tYW5kUmVxdWVz", + "dBISCgpzZXNzaW9uX2lkGAEgASgJEh0KFWNsaWVudF9jb3JyZWxhdGlvbl9p", + "ZBgCIAEoCRIvCgdjb21tYW5kGAMgASgLMh4ubXhhY2Nlc3NfZ2F0ZXdheS52", + "MS5NeENvbW1hbmQiogwKCU14Q29tbWFuZBIwCgRraW5kGAEgASgOMiIubXhh", + "Y2Nlc3NfZ2F0ZXdheS52MS5NeENvbW1hbmRLaW5kEjgKCHJlZ2lzdGVyGAog", + "ASgLMiQubXhhY2Nlc3NfZ2F0ZXdheS52MS5SZWdpc3RlckNvbW1hbmRIABI8", + "Cgp1bnJlZ2lzdGVyGAsgASgLMiYubXhhY2Nlc3NfZ2F0ZXdheS52MS5VbnJl", + "Z2lzdGVyQ29tbWFuZEgAEjcKCGFkZF9pdGVtGAwgASgLMiMubXhhY2Nlc3Nf", + "Z2F0ZXdheS52MS5BZGRJdGVtQ29tbWFuZEgAEjkKCWFkZF9pdGVtMhgNIAEo", + "CzIkLm14YWNjZXNzX2dhdGV3YXkudjEuQWRkSXRlbTJDb21tYW5kSAASPQoL", + "cmVtb3ZlX2l0ZW0YDiABKAsyJi5teGFjY2Vzc19nYXRld2F5LnYxLlJlbW92", + "ZUl0ZW1Db21tYW5kSAASNAoGYWR2aXNlGA8gASgLMiIubXhhY2Nlc3NfZ2F0", + "ZXdheS52MS5BZHZpc2VDb21tYW5kSAASOQoJdW5fYWR2aXNlGBAgASgLMiQu", + "bXhhY2Nlc3NfZ2F0ZXdheS52MS5VbkFkdmlzZUNvbW1hbmRIABJLChJhZHZp", + "c2Vfc3VwZXJ2aXNvcnkYESABKAsyLS5teGFjY2Vzc19nYXRld2F5LnYxLkFk", + "dmlzZVN1cGVydmlzb3J5Q29tbWFuZEgAEkgKEWFkZF9idWZmZXJlZF9pdGVt", + "GBIgASgLMisubXhhY2Nlc3NfZ2F0ZXdheS52MS5BZGRCdWZmZXJlZEl0ZW1D", + "b21tYW5kSAASXQocc2V0X2J1ZmZlcmVkX3VwZGF0ZV9pbnRlcnZhbBgTIAEo", + "CzI1Lm14YWNjZXNzX2dhdGV3YXkudjEuU2V0QnVmZmVyZWRVcGRhdGVJbnRl", + "cnZhbENvbW1hbmRIABI2CgdzdXNwZW5kGBQgASgLMiMubXhhY2Nlc3NfZ2F0", + "ZXdheS52MS5TdXNwZW5kQ29tbWFuZEgAEjgKCGFjdGl2YXRlGBUgASgLMiQu", + "bXhhY2Nlc3NfZ2F0ZXdheS52MS5BY3RpdmF0ZUNvbW1hbmRIABIyCgV3cml0", + "ZRgWIAEoCzIhLm14YWNjZXNzX2dhdGV3YXkudjEuV3JpdGVDb21tYW5kSAAS", + "NAoGd3JpdGUyGBcgASgLMiIubXhhY2Nlc3NfZ2F0ZXdheS52MS5Xcml0ZTJD", + "b21tYW5kSAASQQoNd3JpdGVfc2VjdXJlZBgYIAEoCzIoLm14YWNjZXNzX2dh", + "dGV3YXkudjEuV3JpdGVTZWN1cmVkQ29tbWFuZEgAEkMKDndyaXRlX3NlY3Vy", + "ZWQyGBkgASgLMikubXhhY2Nlc3NfZ2F0ZXdheS52MS5Xcml0ZVNlY3VyZWQy", + "Q29tbWFuZEgAEkkKEWF1dGhlbnRpY2F0ZV91c2VyGBogASgLMiwubXhhY2Nl", + "c3NfZ2F0ZXdheS52MS5BdXRoZW50aWNhdGVVc2VyQ29tbWFuZEgAEk0KFGFy", + "Y2hlc3RyYV91c2VyX3RvX2lkGBsgASgLMi0ubXhhY2Nlc3NfZ2F0ZXdheS52", + "MS5BcmNoZXN0ckFVc2VyVG9JZENvbW1hbmRIABIwCgRwaW5nGGQgASgLMiAu", + "bXhhY2Nlc3NfZ2F0ZXdheS52MS5QaW5nQ29tbWFuZEgAEkgKEWdldF9zZXNz", + "aW9uX3N0YXRlGGUgASgLMisubXhhY2Nlc3NfZ2F0ZXdheS52MS5HZXRTZXNz", + "aW9uU3RhdGVDb21tYW5kSAASRAoPZ2V0X3dvcmtlcl9pbmZvGGYgASgLMiku", + "bXhhY2Nlc3NfZ2F0ZXdheS52MS5HZXRXb3JrZXJJbmZvQ29tbWFuZEgAEj8K", + "DGRyYWluX2V2ZW50cxhnIAEoCzInLm14YWNjZXNzX2dhdGV3YXkudjEuRHJh", + "aW5FdmVudHNDb21tYW5kSAASRQoPc2h1dGRvd25fd29ya2VyGGggASgLMiou", + "bXhhY2Nlc3NfZ2F0ZXdheS52MS5TaHV0ZG93bldvcmtlckNvbW1hbmRIAEIJ", + "CgdwYXlsb2FkIiYKD1JlZ2lzdGVyQ29tbWFuZBITCgtjbGllbnRfbmFtZRgB", + "IAEoCSIqChFVbnJlZ2lzdGVyQ29tbWFuZBIVCg1zZXJ2ZXJfaGFuZGxlGAEg", + "ASgFIkAKDkFkZEl0ZW1Db21tYW5kEhUKDXNlcnZlcl9oYW5kbGUYASABKAUS", + "FwoPaXRlbV9kZWZpbml0aW9uGAIgASgJIlcKD0FkZEl0ZW0yQ29tbWFuZBIV", + "Cg1zZXJ2ZXJfaGFuZGxlGAEgASgFEhcKD2l0ZW1fZGVmaW5pdGlvbhgCIAEo", + "CRIUCgxpdGVtX2NvbnRleHQYAyABKAkiPwoRUmVtb3ZlSXRlbUNvbW1hbmQS", + "FQoNc2VydmVyX2hhbmRsZRgBIAEoBRITCgtpdGVtX2hhbmRsZRgCIAEoBSI7", + "Cg1BZHZpc2VDb21tYW5kEhUKDXNlcnZlcl9oYW5kbGUYASABKAUSEwoLaXRl", + "bV9oYW5kbGUYAiABKAUiPQoPVW5BZHZpc2VDb21tYW5kEhUKDXNlcnZlcl9o", + "YW5kbGUYASABKAUSEwoLaXRlbV9oYW5kbGUYAiABKAUiRgoYQWR2aXNlU3Vw", + "ZXJ2aXNvcnlDb21tYW5kEhUKDXNlcnZlcl9oYW5kbGUYASABKAUSEwoLaXRl", + "bV9oYW5kbGUYAiABKAUiXgoWQWRkQnVmZmVyZWRJdGVtQ29tbWFuZBIVCg1z", + "ZXJ2ZXJfaGFuZGxlGAEgASgFEhcKD2l0ZW1fZGVmaW5pdGlvbhgCIAEoCRIU", + "CgxpdGVtX2NvbnRleHQYAyABKAkiXwogU2V0QnVmZmVyZWRVcGRhdGVJbnRl", + "cnZhbENvbW1hbmQSFQoNc2VydmVyX2hhbmRsZRgBIAEoBRIkChx1cGRhdGVf", + "aW50ZXJ2YWxfbWlsbGlzZWNvbmRzGAIgASgFIjwKDlN1c3BlbmRDb21tYW5k", + "EhUKDXNlcnZlcl9oYW5kbGUYASABKAUSEwoLaXRlbV9oYW5kbGUYAiABKAUi", + "PQoPQWN0aXZhdGVDb21tYW5kEhUKDXNlcnZlcl9oYW5kbGUYASABKAUSEwoL", + "aXRlbV9oYW5kbGUYAiABKAUieAoMV3JpdGVDb21tYW5kEhUKDXNlcnZlcl9o", "YW5kbGUYASABKAUSEwoLaXRlbV9oYW5kbGUYAiABKAUSKwoFdmFsdWUYAyAB", - "KAsyHC5teGFjY2Vzc19nYXRld2F5LnYxLk14VmFsdWUSNQoPdGltZXN0YW1w", - "X3ZhbHVlGAQgASgLMhwubXhhY2Nlc3NfZ2F0ZXdheS52MS5NeFZhbHVlEg8K", - "B3VzZXJfaWQYBSABKAUioQEKE1dyaXRlU2VjdXJlZENvbW1hbmQSFQoNc2Vy", - "dmVyX2hhbmRsZRgBIAEoBRITCgtpdGVtX2hhbmRsZRgCIAEoBRIXCg9jdXJy", - "ZW50X3VzZXJfaWQYAyABKAUSGAoQdmVyaWZpZXJfdXNlcl9pZBgEIAEoBRIr", - "CgV2YWx1ZRgFIAEoCzIcLm14YWNjZXNzX2dhdGV3YXkudjEuTXhWYWx1ZSLZ", - "AQoUV3JpdGVTZWN1cmVkMkNvbW1hbmQSFQoNc2VydmVyX2hhbmRsZRgBIAEo", - "BRITCgtpdGVtX2hhbmRsZRgCIAEoBRIXCg9jdXJyZW50X3VzZXJfaWQYAyAB", - "KAUSGAoQdmVyaWZpZXJfdXNlcl9pZBgEIAEoBRIrCgV2YWx1ZRgFIAEoCzIc", - "Lm14YWNjZXNzX2dhdGV3YXkudjEuTXhWYWx1ZRI1Cg90aW1lc3RhbXBfdmFs", - "dWUYBiABKAsyHC5teGFjY2Vzc19nYXRld2F5LnYxLk14VmFsdWUiYwoXQXV0", - "aGVudGljYXRlVXNlckNvbW1hbmQSFQoNc2VydmVyX2hhbmRsZRgBIAEoBRIT", - "Cgt2ZXJpZnlfdXNlchgCIAEoCRIcChR2ZXJpZnlfdXNlcl9wYXNzd29yZBgD", - "IAEoCSJHChhBcmNoZXN0ckFVc2VyVG9JZENvbW1hbmQSFQoNc2VydmVyX2hh", - "bmRsZRgBIAEoBRIUCgx1c2VyX2lkX2d1aWQYAiABKAkiHgoLUGluZ0NvbW1h", - "bmQSDwoHbWVzc2FnZRgBIAEoCSIYChZHZXRTZXNzaW9uU3RhdGVDb21tYW5k", - "IhYKFEdldFdvcmtlckluZm9Db21tYW5kIigKEkRyYWluRXZlbnRzQ29tbWFu", - "ZBISCgptYXhfZXZlbnRzGAEgASgNIkgKFVNodXRkb3duV29ya2VyQ29tbWFu", - "ZBIvCgxncmFjZV9wZXJpb2QYASABKAsyGS5nb29nbGUucHJvdG9idWYuRHVy", - "YXRpb24ikAgKDk14Q29tbWFuZFJlcGx5EhIKCnNlc3Npb25faWQYASABKAkS", - "FgoOY29ycmVsYXRpb25faWQYAiABKAkSMAoEa2luZBgDIAEoDjIiLm14YWNj", - "ZXNzX2dhdGV3YXkudjEuTXhDb21tYW5kS2luZBI8Cg9wcm90b2NvbF9zdGF0", - "dXMYBCABKAsyIy5teGFjY2Vzc19nYXRld2F5LnYxLlByb3RvY29sU3RhdHVz", - "EhQKB2hyZXN1bHQYBSABKAVIAYgBARIyCgxyZXR1cm5fdmFsdWUYBiABKAsy", - "HC5teGFjY2Vzc19nYXRld2F5LnYxLk14VmFsdWUSNAoIc3RhdHVzZXMYByAD", - "KAsyIi5teGFjY2Vzc19nYXRld2F5LnYxLk14U3RhdHVzUHJveHkSGgoSZGlh", - "Z25vc3RpY19tZXNzYWdlGAggASgJEjYKCHJlZ2lzdGVyGBQgASgLMiIubXhh", - "Y2Nlc3NfZ2F0ZXdheS52MS5SZWdpc3RlclJlcGx5SAASNQoIYWRkX2l0ZW0Y", - "FSABKAsyIS5teGFjY2Vzc19nYXRld2F5LnYxLkFkZEl0ZW1SZXBseUgAEjcK", - "CWFkZF9pdGVtMhgWIAEoCzIiLm14YWNjZXNzX2dhdGV3YXkudjEuQWRkSXRl", - "bTJSZXBseUgAEkYKEWFkZF9idWZmZXJlZF9pdGVtGBcgASgLMikubXhhY2Nl", - "c3NfZ2F0ZXdheS52MS5BZGRCdWZmZXJlZEl0ZW1SZXBseUgAEjQKB3N1c3Bl", - "bmQYGCABKAsyIS5teGFjY2Vzc19nYXRld2F5LnYxLlN1c3BlbmRSZXBseUgA", - "EjYKCGFjdGl2YXRlGBkgASgLMiIubXhhY2Nlc3NfZ2F0ZXdheS52MS5BY3Rp", - "dmF0ZVJlcGx5SAASRwoRYXV0aGVudGljYXRlX3VzZXIYGiABKAsyKi5teGFj", - "Y2Vzc19nYXRld2F5LnYxLkF1dGhlbnRpY2F0ZVVzZXJSZXBseUgAEksKFGFy", - "Y2hlc3RyYV91c2VyX3RvX2lkGBsgASgLMisubXhhY2Nlc3NfZ2F0ZXdheS52", - "MS5BcmNoZXN0ckFVc2VyVG9JZFJlcGx5SAASPwoNc2Vzc2lvbl9zdGF0ZRhk", - "IAEoCzImLm14YWNjZXNzX2dhdGV3YXkudjEuU2Vzc2lvblN0YXRlUmVwbHlI", - "ABI7Cgt3b3JrZXJfaW5mbxhlIAEoCzIkLm14YWNjZXNzX2dhdGV3YXkudjEu", - "V29ya2VySW5mb1JlcGx5SAASPQoMZHJhaW5fZXZlbnRzGGYgASgLMiUubXhh", - "Y2Nlc3NfZ2F0ZXdheS52MS5EcmFpbkV2ZW50c1JlcGx5SABCCQoHcGF5bG9h", - "ZEIKCghfaHJlc3VsdCImCg1SZWdpc3RlclJlcGx5EhUKDXNlcnZlcl9oYW5k", - "bGUYASABKAUiIwoMQWRkSXRlbVJlcGx5EhMKC2l0ZW1faGFuZGxlGAEgASgF", - "IiQKDUFkZEl0ZW0yUmVwbHkSEwoLaXRlbV9oYW5kbGUYASABKAUiKwoUQWRk", - "QnVmZmVyZWRJdGVtUmVwbHkSEwoLaXRlbV9oYW5kbGUYASABKAUiQgoMU3Vz", - "cGVuZFJlcGx5EjIKBnN0YXR1cxgBIAEoCzIiLm14YWNjZXNzX2dhdGV3YXku", - "djEuTXhTdGF0dXNQcm94eSJDCg1BY3RpdmF0ZVJlcGx5EjIKBnN0YXR1cxgB", - "IAEoCzIiLm14YWNjZXNzX2dhdGV3YXkudjEuTXhTdGF0dXNQcm94eSIoChVB", - "dXRoZW50aWNhdGVVc2VyUmVwbHkSDwoHdXNlcl9pZBgBIAEoBSIpChZBcmNo", - "ZXN0ckFVc2VyVG9JZFJlcGx5Eg8KB3VzZXJfaWQYASABKAUiRQoRU2Vzc2lv", - "blN0YXRlUmVwbHkSMAoFc3RhdGUYASABKA4yIS5teGFjY2Vzc19nYXRld2F5", - "LnYxLlNlc3Npb25TdGF0ZSJ1Cg9Xb3JrZXJJbmZvUmVwbHkSGQoRd29ya2Vy", - "X3Byb2Nlc3NfaWQYASABKAUSFgoOd29ya2VyX3ZlcnNpb24YAiABKAkSFwoP", - "bXhhY2Nlc3NfcHJvZ2lkGAMgASgJEhYKDm14YWNjZXNzX2Nsc2lkGAQgASgJ", - "IkAKEERyYWluRXZlbnRzUmVwbHkSLAoGZXZlbnRzGAEgAygLMhwubXhhY2Nl", - "c3NfZ2F0ZXdheS52MS5NeEV2ZW50IpsGCgdNeEV2ZW50EjIKBmZhbWlseRgB", - "IAEoDjIiLm14YWNjZXNzX2dhdGV3YXkudjEuTXhFdmVudEZhbWlseRISCgpz", - "ZXNzaW9uX2lkGAIgASgJEhUKDXNlcnZlcl9oYW5kbGUYAyABKAUSEwoLaXRl", - "bV9oYW5kbGUYBCABKAUSKwoFdmFsdWUYBSABKAsyHC5teGFjY2Vzc19nYXRl", - "d2F5LnYxLk14VmFsdWUSDwoHcXVhbGl0eRgGIAEoBRI0ChBzb3VyY2VfdGlt", - "ZXN0YW1wGAcgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBI0Cghz", - "dGF0dXNlcxgIIAMoCzIiLm14YWNjZXNzX2dhdGV3YXkudjEuTXhTdGF0dXNQ", - "cm94eRIXCg93b3JrZXJfc2VxdWVuY2UYCSABKAQSNAoQd29ya2VyX3RpbWVz", - "dGFtcBgKIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASPQoZZ2F0", - "ZXdheV9yZWNlaXZlX3RpbWVzdGFtcBgLIAEoCzIaLmdvb2dsZS5wcm90b2J1", - "Zi5UaW1lc3RhbXASFAoHaHJlc3VsdBgMIAEoBUgBiAEBEhIKCnJhd19zdGF0", - "dXMYDSABKAkSQAoOb25fZGF0YV9jaGFuZ2UYFCABKAsyJi5teGFjY2Vzc19n", - "YXRld2F5LnYxLk9uRGF0YUNoYW5nZUV2ZW50SAASRgoRb25fd3JpdGVfY29t", - "cGxldGUYFSABKAsyKS5teGFjY2Vzc19nYXRld2F5LnYxLk9uV3JpdGVDb21w", - "bGV0ZUV2ZW50SAASSQoSb3BlcmF0aW9uX2NvbXBsZXRlGBYgASgLMisubXhh", - "Y2Nlc3NfZ2F0ZXdheS52MS5PcGVyYXRpb25Db21wbGV0ZUV2ZW50SAASUQoX", - "b25fYnVmZmVyZWRfZGF0YV9jaGFuZ2UYFyABKAsyLi5teGFjY2Vzc19nYXRl", - "d2F5LnYxLk9uQnVmZmVyZWREYXRhQ2hhbmdlRXZlbnRIAEIGCgRib2R5QgoK", - "CF9ocmVzdWx0IhMKEU9uRGF0YUNoYW5nZUV2ZW50IhYKFE9uV3JpdGVDb21w", - "bGV0ZUV2ZW50IhgKFk9wZXJhdGlvbkNvbXBsZXRlRXZlbnQi1AEKGU9uQnVm", - "ZmVyZWREYXRhQ2hhbmdlRXZlbnQSMgoJZGF0YV90eXBlGAEgASgOMh8ubXhh", - "Y2Nlc3NfZ2F0ZXdheS52MS5NeERhdGFUeXBlEjQKDnF1YWxpdHlfdmFsdWVz", - "GAIgASgLMhwubXhhY2Nlc3NfZ2F0ZXdheS52MS5NeEFycmF5EjYKEHRpbWVz", - "dGFtcF92YWx1ZXMYAyABKAsyHC5teGFjY2Vzc19nYXRld2F5LnYxLk14QXJy", - "YXkSFQoNcmF3X2RhdGFfdHlwZRgEIAEoBSLrAQoNTXhTdGF0dXNQcm94eRIP", - "CgdzdWNjZXNzGAEgASgFEjcKCGNhdGVnb3J5GAIgASgOMiUubXhhY2Nlc3Nf", - "Z2F0ZXdheS52MS5NeFN0YXR1c0NhdGVnb3J5EjgKC2RldGVjdGVkX2J5GAMg", - "ASgOMiMubXhhY2Nlc3NfZ2F0ZXdheS52MS5NeFN0YXR1c1NvdXJjZRIOCgZk", - "ZXRhaWwYBCABKAUSFAoMcmF3X2NhdGVnb3J5GAUgASgFEhcKD3Jhd19kZXRl", - "Y3RlZF9ieRgGIAEoBRIXCg9kaWFnbm9zdGljX3RleHQYByABKAkipwMKB014", - "VmFsdWUSMgoJZGF0YV90eXBlGAEgASgOMh8ubXhhY2Nlc3NfZ2F0ZXdheS52", - "MS5NeERhdGFUeXBlEhQKDHZhcmlhbnRfdHlwZRgCIAEoCRIPCgdpc19udWxs", - "GAMgASgIEhYKDnJhd19kaWFnbm9zdGljGAQgASgJEhUKDXJhd19kYXRhX3R5", - "cGUYBSABKAUSFAoKYm9vbF92YWx1ZRgKIAEoCEgAEhUKC2ludDMyX3ZhbHVl", - "GAsgASgFSAASFQoLaW50NjRfdmFsdWUYDCABKANIABIVCgtmbG9hdF92YWx1", - "ZRgNIAEoAkgAEhYKDGRvdWJsZV92YWx1ZRgOIAEoAUgAEhYKDHN0cmluZ192", - "YWx1ZRgPIAEoCUgAEjUKD3RpbWVzdGFtcF92YWx1ZRgQIAEoCzIaLmdvb2ds", - "ZS5wcm90b2J1Zi5UaW1lc3RhbXBIABIzCgthcnJheV92YWx1ZRgRIAEoCzIc", - "Lm14YWNjZXNzX2dhdGV3YXkudjEuTXhBcnJheUgAEhMKCXJhd192YWx1ZRgS", - "IAEoDEgAQgYKBGtpbmQi/gQKB014QXJyYXkSOgoRZWxlbWVudF9kYXRhX3R5", - "cGUYASABKA4yHy5teGFjY2Vzc19nYXRld2F5LnYxLk14RGF0YVR5cGUSFAoM", - "dmFyaWFudF90eXBlGAIgASgJEhIKCmRpbWVuc2lvbnMYAyADKA0SFgoOcmF3", - "X2RpYWdub3N0aWMYBCABKAkSHQoVcmF3X2VsZW1lbnRfZGF0YV90eXBlGAUg", - "ASgFEjUKC2Jvb2xfdmFsdWVzGAogASgLMh4ubXhhY2Nlc3NfZ2F0ZXdheS52", - "MS5Cb29sQXJyYXlIABI3CgxpbnQzMl92YWx1ZXMYCyABKAsyHy5teGFjY2Vz", - "c19nYXRld2F5LnYxLkludDMyQXJyYXlIABI3CgxpbnQ2NF92YWx1ZXMYDCAB", - "KAsyHy5teGFjY2Vzc19nYXRld2F5LnYxLkludDY0QXJyYXlIABI3CgxmbG9h", - "dF92YWx1ZXMYDSABKAsyHy5teGFjY2Vzc19nYXRld2F5LnYxLkZsb2F0QXJy", - "YXlIABI5Cg1kb3VibGVfdmFsdWVzGA4gASgLMiAubXhhY2Nlc3NfZ2F0ZXdh", - "eS52MS5Eb3VibGVBcnJheUgAEjkKDXN0cmluZ192YWx1ZXMYDyABKAsyIC5t", - "eGFjY2Vzc19nYXRld2F5LnYxLlN0cmluZ0FycmF5SAASPwoQdGltZXN0YW1w", - "X3ZhbHVlcxgQIAEoCzIjLm14YWNjZXNzX2dhdGV3YXkudjEuVGltZXN0YW1w", - "QXJyYXlIABIzCgpyYXdfdmFsdWVzGBEgASgLMh0ubXhhY2Nlc3NfZ2F0ZXdh", - "eS52MS5SYXdBcnJheUgAQggKBnZhbHVlcyIbCglCb29sQXJyYXkSDgoGdmFs", - "dWVzGAEgAygIIhwKCkludDMyQXJyYXkSDgoGdmFsdWVzGAEgAygFIhwKCklu", - "dDY0QXJyYXkSDgoGdmFsdWVzGAEgAygDIhwKCkZsb2F0QXJyYXkSDgoGdmFs", - "dWVzGAEgAygCIh0KC0RvdWJsZUFycmF5Eg4KBnZhbHVlcxgBIAMoASIdCgtT", - "dHJpbmdBcnJheRIOCgZ2YWx1ZXMYASADKAkiPAoOVGltZXN0YW1wQXJyYXkS", - "KgoGdmFsdWVzGAEgAygLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcCIa", - "CghSYXdBcnJheRIOCgZ2YWx1ZXMYASADKAwiWAoOUHJvdG9jb2xTdGF0dXMS", - "NQoEY29kZRgBIAEoDjInLm14YWNjZXNzX2dhdGV3YXkudjEuUHJvdG9jb2xT", - "dGF0dXNDb2RlEg8KB21lc3NhZ2UYAiABKAkqvwYKDU14Q29tbWFuZEtpbmQS", - "HwobTVhfQ09NTUFORF9LSU5EX1VOU1BFQ0lGSUVEEAASHAoYTVhfQ09NTUFO", - "RF9LSU5EX1JFR0lTVEVSEAESHgoaTVhfQ09NTUFORF9LSU5EX1VOUkVHSVNU", - "RVIQAhIcChhNWF9DT01NQU5EX0tJTkRfQUREX0lURU0QAxIdChlNWF9DT01N", - "QU5EX0tJTkRfQUREX0lURU0yEAQSHwobTVhfQ09NTUFORF9LSU5EX1JFTU9W", - "RV9JVEVNEAUSGgoWTVhfQ09NTUFORF9LSU5EX0FEVklTRRAGEh0KGU1YX0NP", - "TU1BTkRfS0lORF9VTl9BRFZJU0UQBxImCiJNWF9DT01NQU5EX0tJTkRfQURW", - "SVNFX1NVUEVSVklTT1JZEAgSJQohTVhfQ09NTUFORF9LSU5EX0FERF9CVUZG", - "RVJFRF9JVEVNEAkSMAosTVhfQ09NTUFORF9LSU5EX1NFVF9CVUZGRVJFRF9V", - "UERBVEVfSU5URVJWQUwQChIbChdNWF9DT01NQU5EX0tJTkRfU1VTUEVORBAL", - "EhwKGE1YX0NPTU1BTkRfS0lORF9BQ1RJVkFURRAMEhkKFU1YX0NPTU1BTkRf", - "S0lORF9XUklURRANEhoKFk1YX0NPTU1BTkRfS0lORF9XUklURTIQDhIhCh1N", - "WF9DT01NQU5EX0tJTkRfV1JJVEVfU0VDVVJFRBAPEiIKHk1YX0NPTU1BTkRf", - "S0lORF9XUklURV9TRUNVUkVEMhAQEiUKIU1YX0NPTU1BTkRfS0lORF9BVVRI", - "RU5USUNBVEVfVVNFUhAREigKJE1YX0NPTU1BTkRfS0lORF9BUkNIRVNUUkFf", - "VVNFUl9UT19JRBASEhgKFE1YX0NPTU1BTkRfS0lORF9QSU5HEGQSJQohTVhf", - "Q09NTUFORF9LSU5EX0dFVF9TRVNTSU9OX1NUQVRFEGUSIwofTVhfQ09NTUFO", - "RF9LSU5EX0dFVF9XT1JLRVJfSU5GTxBmEiAKHE1YX0NPTU1BTkRfS0lORF9E", - "UkFJTl9FVkVOVFMQZxIjCh9NWF9DT01NQU5EX0tJTkRfU0hVVERPV05fV09S", - "S0VSEGgq0AEKDU14RXZlbnRGYW1pbHkSHwobTVhfRVZFTlRfRkFNSUxZX1VO", - "U1BFQ0lGSUVEEAASIgoeTVhfRVZFTlRfRkFNSUxZX09OX0RBVEFfQ0hBTkdF", - "EAESJQohTVhfRVZFTlRfRkFNSUxZX09OX1dSSVRFX0NPTVBMRVRFEAISJgoi", - "TVhfRVZFTlRfRkFNSUxZX09QRVJBVElPTl9DT01QTEVURRADEisKJ01YX0VW", - "RU5UX0ZBTUlMWV9PTl9CVUZGRVJFRF9EQVRBX0NIQU5HRRAEKqUDChBNeFN0", - "YXR1c0NhdGVnb3J5EiIKHk1YX1NUQVRVU19DQVRFR09SWV9VTlNQRUNJRklF", - "RBAAEh4KGk1YX1NUQVRVU19DQVRFR09SWV9VTktOT1dOEAESGQoVTVhfU1RB", - "VFVTX0NBVEVHT1JZX09LEAISHgoaTVhfU1RBVFVTX0NBVEVHT1JZX1BFTkRJ", - "TkcQAxIeChpNWF9TVEFUVVNfQ0FURUdPUllfV0FSTklORxAEEioKJk1YX1NU", - "QVRVU19DQVRFR09SWV9DT01NVU5JQ0FUSU9OX0VSUk9SEAUSKgomTVhfU1RB", - "VFVTX0NBVEVHT1JZX0NPTkZJR1VSQVRJT05fRVJST1IQBhIoCiRNWF9TVEFU", - "VVNfQ0FURUdPUllfT1BFUkFUSU9OQUxfRVJST1IQBxIlCiFNWF9TVEFUVVNf", - "Q0FURUdPUllfU0VDVVJJVFlfRVJST1IQCBIlCiFNWF9TVEFUVVNfQ0FURUdP", - "UllfU09GVFdBUkVfRVJST1IQCRIiCh5NWF9TVEFUVVNfQ0FURUdPUllfT1RI", - "RVJfRVJST1IQCirKAgoOTXhTdGF0dXNTb3VyY2USIAocTVhfU1RBVFVTX1NP", - "VVJDRV9VTlNQRUNJRklFRBAAEhwKGE1YX1NUQVRVU19TT1VSQ0VfVU5LTk9X", - "ThABEiMKH01YX1NUQVRVU19TT1VSQ0VfUkVRVUVTVElOR19MTVgQAhIjCh9N", - "WF9TVEFUVVNfU09VUkNFX1JFU1BPTkRJTkdfTE1YEAMSIwofTVhfU1RBVFVT", - "X1NPVVJDRV9SRVFVRVNUSU5HX05NWBAEEiMKH01YX1NUQVRVU19TT1VSQ0Vf", - "UkVTUE9ORElOR19OTVgQBRIxCi1NWF9TVEFUVVNfU09VUkNFX1JFUVVFU1RJ", - "TkdfQVVUT01BVElPTl9PQkpFQ1QQBhIxCi1NWF9TVEFUVVNfU09VUkNFX1JF", - "U1BPTkRJTkdfQVVUT01BVElPTl9PQkpFQ1QQByrdBAoKTXhEYXRhVHlwZRIc", - "ChhNWF9EQVRBX1RZUEVfVU5TUEVDSUZJRUQQABIYChRNWF9EQVRBX1RZUEVf", - "VU5LTk9XThABEhgKFE1YX0RBVEFfVFlQRV9OT19EQVRBEAISGAoUTVhfREFU", - "QV9UWVBFX0JPT0xFQU4QAxIYChRNWF9EQVRBX1RZUEVfSU5URUdFUhAEEhYK", - "Ek1YX0RBVEFfVFlQRV9GTE9BVBAFEhcKE01YX0RBVEFfVFlQRV9ET1VCTEUQ", - "BhIXChNNWF9EQVRBX1RZUEVfU1RSSU5HEAcSFQoRTVhfREFUQV9UWVBFX1RJ", - "TUUQCBIdChlNWF9EQVRBX1RZUEVfRUxBUFNFRF9USU1FEAkSHwobTVhfREFU", - "QV9UWVBFX1JFRkVSRU5DRV9UWVBFEAoSHAoYTVhfREFUQV9UWVBFX1NUQVRV", - "U19UWVBFEAsSFQoRTVhfREFUQV9UWVBFX0VOVU0QDBItCilNWF9EQVRBX1RZ", - "UEVfU0VDVVJJVFlfQ0xBU1NJRklDQVRJT05fRU5VTRANEiIKHk1YX0RBVEFf", - "VFlQRV9EQVRBX1FVQUxJVFlfVFlQRRAOEh8KG01YX0RBVEFfVFlQRV9RVUFM", - "SUZJRURfRU5VTRAPEiEKHU1YX0RBVEFfVFlQRV9RVUFMSUZJRURfU1RSVUNU", - "EBASKQolTVhfREFUQV9UWVBFX0lOVEVSTkFUSU9OQUxJWkVEX1NUUklORxAR", - "EhsKF01YX0RBVEFfVFlQRV9CSUdfU1RSSU5HEBISFAoQTVhfREFUQV9UWVBF", - "X0VORBATKqMDChJQcm90b2NvbFN0YXR1c0NvZGUSJAogUFJPVE9DT0xfU1RB", - "VFVTX0NPREVfVU5TUEVDSUZJRUQQABIbChdQUk9UT0NPTF9TVEFUVVNfQ09E", - "RV9PSxABEigKJFBST1RPQ09MX1NUQVRVU19DT0RFX0lOVkFMSURfUkVRVUVT", - "VBACEioKJlBST1RPQ09MX1NUQVRVU19DT0RFX1NFU1NJT05fTk9UX0ZPVU5E", - "EAMSKgomUFJPVE9DT0xfU1RBVFVTX0NPREVfU0VTU0lPTl9OT1RfUkVBRFkQ", - "BBIrCidQUk9UT0NPTF9TVEFUVVNfQ09ERV9XT1JLRVJfVU5BVkFJTEFCTEUQ", - "BRIgChxQUk9UT0NPTF9TVEFUVVNfQ09ERV9USU1FT1VUEAYSIQodUFJPVE9D", - "T0xfU1RBVFVTX0NPREVfQ0FOQ0VMRUQQBxIrCidQUk9UT0NPTF9TVEFUVVNf", - "Q09ERV9QUk9UT0NPTF9WSU9MQVRJT04QCBIpCiVQUk9UT0NPTF9TVEFUVVNf", - "Q09ERV9NWEFDQ0VTU19GQUlMVVJFEAkqvwIKDFNlc3Npb25TdGF0ZRIdChlT", - "RVNTSU9OX1NUQVRFX1VOU1BFQ0lGSUVEEAASGgoWU0VTU0lPTl9TVEFURV9D", - "UkVBVElORxABEiEKHVNFU1NJT05fU1RBVEVfU1RBUlRJTkdfV09SS0VSEAIS", - "IgoeU0VTU0lPTl9TVEFURV9XQUlUSU5HX0ZPUl9QSVBFEAMSHQoZU0VTU0lP", - "Tl9TVEFURV9IQU5EU0hBS0lORxAEEiUKIVNFU1NJT05fU1RBVEVfSU5JVElB", - "TElaSU5HX1dPUktFUhAFEhcKE1NFU1NJT05fU1RBVEVfUkVBRFkQBhIZChVT", - "RVNTSU9OX1NUQVRFX0NMT1NJTkcQBxIYChRTRVNTSU9OX1NUQVRFX0NMT1NF", - "RBAIEhkKFVNFU1NJT05fU1RBVEVfRkFVTFRFRBAJMoIDCg9NeEFjY2Vzc0dh", - "dGV3YXkSXQoLT3BlblNlc3Npb24SJy5teGFjY2Vzc19nYXRld2F5LnYxLk9w", - "ZW5TZXNzaW9uUmVxdWVzdBolLm14YWNjZXNzX2dhdGV3YXkudjEuT3BlblNl", - "c3Npb25SZXBseRJgCgxDbG9zZVNlc3Npb24SKC5teGFjY2Vzc19nYXRld2F5", - "LnYxLkNsb3NlU2Vzc2lvblJlcXVlc3QaJi5teGFjY2Vzc19nYXRld2F5LnYx", - "LkNsb3NlU2Vzc2lvblJlcGx5ElQKBkludm9rZRIlLm14YWNjZXNzX2dhdGV3", - "YXkudjEuTXhDb21tYW5kUmVxdWVzdBojLm14YWNjZXNzX2dhdGV3YXkudjEu", - "TXhDb21tYW5kUmVwbHkSWAoMU3RyZWFtRXZlbnRzEigubXhhY2Nlc3NfZ2F0", - "ZXdheS52MS5TdHJlYW1FdmVudHNSZXF1ZXN0GhwubXhhY2Nlc3NfZ2F0ZXdh", - "eS52MS5NeEV2ZW50MAFCHKoCGU14R2F0ZXdheS5Db250cmFjdHMuUHJvdG9i", - "BnByb3RvMw==")); + "KAsyHC5teGFjY2Vzc19nYXRld2F5LnYxLk14VmFsdWUSDwoHdXNlcl9pZBgE", + "IAEoBSKwAQoNV3JpdGUyQ29tbWFuZBIVCg1zZXJ2ZXJfaGFuZGxlGAEgASgF", + "EhMKC2l0ZW1faGFuZGxlGAIgASgFEisKBXZhbHVlGAMgASgLMhwubXhhY2Nl", + "c3NfZ2F0ZXdheS52MS5NeFZhbHVlEjUKD3RpbWVzdGFtcF92YWx1ZRgEIAEo", + "CzIcLm14YWNjZXNzX2dhdGV3YXkudjEuTXhWYWx1ZRIPCgd1c2VyX2lkGAUg", + "ASgFIqEBChNXcml0ZVNlY3VyZWRDb21tYW5kEhUKDXNlcnZlcl9oYW5kbGUY", + "ASABKAUSEwoLaXRlbV9oYW5kbGUYAiABKAUSFwoPY3VycmVudF91c2VyX2lk", + "GAMgASgFEhgKEHZlcmlmaWVyX3VzZXJfaWQYBCABKAUSKwoFdmFsdWUYBSAB", + "KAsyHC5teGFjY2Vzc19nYXRld2F5LnYxLk14VmFsdWUi2QEKFFdyaXRlU2Vj", + "dXJlZDJDb21tYW5kEhUKDXNlcnZlcl9oYW5kbGUYASABKAUSEwoLaXRlbV9o", + "YW5kbGUYAiABKAUSFwoPY3VycmVudF91c2VyX2lkGAMgASgFEhgKEHZlcmlm", + "aWVyX3VzZXJfaWQYBCABKAUSKwoFdmFsdWUYBSABKAsyHC5teGFjY2Vzc19n", + "YXRld2F5LnYxLk14VmFsdWUSNQoPdGltZXN0YW1wX3ZhbHVlGAYgASgLMhwu", + "bXhhY2Nlc3NfZ2F0ZXdheS52MS5NeFZhbHVlImMKF0F1dGhlbnRpY2F0ZVVz", + "ZXJDb21tYW5kEhUKDXNlcnZlcl9oYW5kbGUYASABKAUSEwoLdmVyaWZ5X3Vz", + "ZXIYAiABKAkSHAoUdmVyaWZ5X3VzZXJfcGFzc3dvcmQYAyABKAkiRwoYQXJj", + "aGVzdHJBVXNlclRvSWRDb21tYW5kEhUKDXNlcnZlcl9oYW5kbGUYASABKAUS", + "FAoMdXNlcl9pZF9ndWlkGAIgASgJIh4KC1BpbmdDb21tYW5kEg8KB21lc3Nh", + "Z2UYASABKAkiGAoWR2V0U2Vzc2lvblN0YXRlQ29tbWFuZCIWChRHZXRXb3Jr", + "ZXJJbmZvQ29tbWFuZCIoChJEcmFpbkV2ZW50c0NvbW1hbmQSEgoKbWF4X2V2", + "ZW50cxgBIAEoDSJIChVTaHV0ZG93bldvcmtlckNvbW1hbmQSLwoMZ3JhY2Vf", + "cGVyaW9kGAEgASgLMhkuZ29vZ2xlLnByb3RvYnVmLkR1cmF0aW9uIpAICg5N", + "eENvbW1hbmRSZXBseRISCgpzZXNzaW9uX2lkGAEgASgJEhYKDmNvcnJlbGF0", + "aW9uX2lkGAIgASgJEjAKBGtpbmQYAyABKA4yIi5teGFjY2Vzc19nYXRld2F5", + "LnYxLk14Q29tbWFuZEtpbmQSPAoPcHJvdG9jb2xfc3RhdHVzGAQgASgLMiMu", + "bXhhY2Nlc3NfZ2F0ZXdheS52MS5Qcm90b2NvbFN0YXR1cxIUCgdocmVzdWx0", + "GAUgASgFSAGIAQESMgoMcmV0dXJuX3ZhbHVlGAYgASgLMhwubXhhY2Nlc3Nf", + "Z2F0ZXdheS52MS5NeFZhbHVlEjQKCHN0YXR1c2VzGAcgAygLMiIubXhhY2Nl", + "c3NfZ2F0ZXdheS52MS5NeFN0YXR1c1Byb3h5EhoKEmRpYWdub3N0aWNfbWVz", + "c2FnZRgIIAEoCRI2CghyZWdpc3RlchgUIAEoCzIiLm14YWNjZXNzX2dhdGV3", + "YXkudjEuUmVnaXN0ZXJSZXBseUgAEjUKCGFkZF9pdGVtGBUgASgLMiEubXhh", + "Y2Nlc3NfZ2F0ZXdheS52MS5BZGRJdGVtUmVwbHlIABI3CglhZGRfaXRlbTIY", + "FiABKAsyIi5teGFjY2Vzc19nYXRld2F5LnYxLkFkZEl0ZW0yUmVwbHlIABJG", + "ChFhZGRfYnVmZmVyZWRfaXRlbRgXIAEoCzIpLm14YWNjZXNzX2dhdGV3YXku", + "djEuQWRkQnVmZmVyZWRJdGVtUmVwbHlIABI0CgdzdXNwZW5kGBggASgLMiEu", + "bXhhY2Nlc3NfZ2F0ZXdheS52MS5TdXNwZW5kUmVwbHlIABI2CghhY3RpdmF0", + "ZRgZIAEoCzIiLm14YWNjZXNzX2dhdGV3YXkudjEuQWN0aXZhdGVSZXBseUgA", + "EkcKEWF1dGhlbnRpY2F0ZV91c2VyGBogASgLMioubXhhY2Nlc3NfZ2F0ZXdh", + "eS52MS5BdXRoZW50aWNhdGVVc2VyUmVwbHlIABJLChRhcmNoZXN0cmFfdXNl", + "cl90b19pZBgbIAEoCzIrLm14YWNjZXNzX2dhdGV3YXkudjEuQXJjaGVzdHJB", + "VXNlclRvSWRSZXBseUgAEj8KDXNlc3Npb25fc3RhdGUYZCABKAsyJi5teGFj", + "Y2Vzc19nYXRld2F5LnYxLlNlc3Npb25TdGF0ZVJlcGx5SAASOwoLd29ya2Vy", + "X2luZm8YZSABKAsyJC5teGFjY2Vzc19nYXRld2F5LnYxLldvcmtlckluZm9S", + "ZXBseUgAEj0KDGRyYWluX2V2ZW50cxhmIAEoCzIlLm14YWNjZXNzX2dhdGV3", + "YXkudjEuRHJhaW5FdmVudHNSZXBseUgAQgkKB3BheWxvYWRCCgoIX2hyZXN1", + "bHQiJgoNUmVnaXN0ZXJSZXBseRIVCg1zZXJ2ZXJfaGFuZGxlGAEgASgFIiMK", + "DEFkZEl0ZW1SZXBseRITCgtpdGVtX2hhbmRsZRgBIAEoBSIkCg1BZGRJdGVt", + "MlJlcGx5EhMKC2l0ZW1faGFuZGxlGAEgASgFIisKFEFkZEJ1ZmZlcmVkSXRl", + "bVJlcGx5EhMKC2l0ZW1faGFuZGxlGAEgASgFIkIKDFN1c3BlbmRSZXBseRIy", + "CgZzdGF0dXMYASABKAsyIi5teGFjY2Vzc19nYXRld2F5LnYxLk14U3RhdHVz", + "UHJveHkiQwoNQWN0aXZhdGVSZXBseRIyCgZzdGF0dXMYASABKAsyIi5teGFj", + "Y2Vzc19nYXRld2F5LnYxLk14U3RhdHVzUHJveHkiKAoVQXV0aGVudGljYXRl", + "VXNlclJlcGx5Eg8KB3VzZXJfaWQYASABKAUiKQoWQXJjaGVzdHJBVXNlclRv", + "SWRSZXBseRIPCgd1c2VyX2lkGAEgASgFIkUKEVNlc3Npb25TdGF0ZVJlcGx5", + "EjAKBXN0YXRlGAEgASgOMiEubXhhY2Nlc3NfZ2F0ZXdheS52MS5TZXNzaW9u", + "U3RhdGUidQoPV29ya2VySW5mb1JlcGx5EhkKEXdvcmtlcl9wcm9jZXNzX2lk", + "GAEgASgFEhYKDndvcmtlcl92ZXJzaW9uGAIgASgJEhcKD214YWNjZXNzX3By", + "b2dpZBgDIAEoCRIWCg5teGFjY2Vzc19jbHNpZBgEIAEoCSJAChBEcmFpbkV2", + "ZW50c1JlcGx5EiwKBmV2ZW50cxgBIAMoCzIcLm14YWNjZXNzX2dhdGV3YXku", + "djEuTXhFdmVudCKbBgoHTXhFdmVudBIyCgZmYW1pbHkYASABKA4yIi5teGFj", + "Y2Vzc19nYXRld2F5LnYxLk14RXZlbnRGYW1pbHkSEgoKc2Vzc2lvbl9pZBgC", + "IAEoCRIVCg1zZXJ2ZXJfaGFuZGxlGAMgASgFEhMKC2l0ZW1faGFuZGxlGAQg", + "ASgFEisKBXZhbHVlGAUgASgLMhwubXhhY2Nlc3NfZ2F0ZXdheS52MS5NeFZh", + "bHVlEg8KB3F1YWxpdHkYBiABKAUSNAoQc291cmNlX3RpbWVzdGFtcBgHIAEo", + "CzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASNAoIc3RhdHVzZXMYCCAD", + "KAsyIi5teGFjY2Vzc19nYXRld2F5LnYxLk14U3RhdHVzUHJveHkSFwoPd29y", + "a2VyX3NlcXVlbmNlGAkgASgEEjQKEHdvcmtlcl90aW1lc3RhbXAYCiABKAsy", + "Gi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEj0KGWdhdGV3YXlfcmVjZWl2", + "ZV90aW1lc3RhbXAYCyABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1w", + "EhQKB2hyZXN1bHQYDCABKAVIAYgBARISCgpyYXdfc3RhdHVzGA0gASgJEkAK", + "Dm9uX2RhdGFfY2hhbmdlGBQgASgLMiYubXhhY2Nlc3NfZ2F0ZXdheS52MS5P", + "bkRhdGFDaGFuZ2VFdmVudEgAEkYKEW9uX3dyaXRlX2NvbXBsZXRlGBUgASgL", + "MikubXhhY2Nlc3NfZ2F0ZXdheS52MS5PbldyaXRlQ29tcGxldGVFdmVudEgA", + "EkkKEm9wZXJhdGlvbl9jb21wbGV0ZRgWIAEoCzIrLm14YWNjZXNzX2dhdGV3", + "YXkudjEuT3BlcmF0aW9uQ29tcGxldGVFdmVudEgAElEKF29uX2J1ZmZlcmVk", + "X2RhdGFfY2hhbmdlGBcgASgLMi4ubXhhY2Nlc3NfZ2F0ZXdheS52MS5PbkJ1", + "ZmZlcmVkRGF0YUNoYW5nZUV2ZW50SABCBgoEYm9keUIKCghfaHJlc3VsdCIT", + "ChFPbkRhdGFDaGFuZ2VFdmVudCIWChRPbldyaXRlQ29tcGxldGVFdmVudCIY", + "ChZPcGVyYXRpb25Db21wbGV0ZUV2ZW50ItQBChlPbkJ1ZmZlcmVkRGF0YUNo", + "YW5nZUV2ZW50EjIKCWRhdGFfdHlwZRgBIAEoDjIfLm14YWNjZXNzX2dhdGV3", + "YXkudjEuTXhEYXRhVHlwZRI0Cg5xdWFsaXR5X3ZhbHVlcxgCIAEoCzIcLm14", + "YWNjZXNzX2dhdGV3YXkudjEuTXhBcnJheRI2ChB0aW1lc3RhbXBfdmFsdWVz", + "GAMgASgLMhwubXhhY2Nlc3NfZ2F0ZXdheS52MS5NeEFycmF5EhUKDXJhd19k", + "YXRhX3R5cGUYBCABKAUi6wEKDU14U3RhdHVzUHJveHkSDwoHc3VjY2VzcxgB", + "IAEoBRI3CghjYXRlZ29yeRgCIAEoDjIlLm14YWNjZXNzX2dhdGV3YXkudjEu", + "TXhTdGF0dXNDYXRlZ29yeRI4CgtkZXRlY3RlZF9ieRgDIAEoDjIjLm14YWNj", + "ZXNzX2dhdGV3YXkudjEuTXhTdGF0dXNTb3VyY2USDgoGZGV0YWlsGAQgASgF", + "EhQKDHJhd19jYXRlZ29yeRgFIAEoBRIXCg9yYXdfZGV0ZWN0ZWRfYnkYBiAB", + "KAUSFwoPZGlhZ25vc3RpY190ZXh0GAcgASgJIqcDCgdNeFZhbHVlEjIKCWRh", + "dGFfdHlwZRgBIAEoDjIfLm14YWNjZXNzX2dhdGV3YXkudjEuTXhEYXRhVHlw", + "ZRIUCgx2YXJpYW50X3R5cGUYAiABKAkSDwoHaXNfbnVsbBgDIAEoCBIWCg5y", + "YXdfZGlhZ25vc3RpYxgEIAEoCRIVCg1yYXdfZGF0YV90eXBlGAUgASgFEhQK", + "CmJvb2xfdmFsdWUYCiABKAhIABIVCgtpbnQzMl92YWx1ZRgLIAEoBUgAEhUK", + "C2ludDY0X3ZhbHVlGAwgASgDSAASFQoLZmxvYXRfdmFsdWUYDSABKAJIABIW", + "Cgxkb3VibGVfdmFsdWUYDiABKAFIABIWCgxzdHJpbmdfdmFsdWUYDyABKAlI", + "ABI1Cg90aW1lc3RhbXBfdmFsdWUYECABKAsyGi5nb29nbGUucHJvdG9idWYu", + "VGltZXN0YW1wSAASMwoLYXJyYXlfdmFsdWUYESABKAsyHC5teGFjY2Vzc19n", + "YXRld2F5LnYxLk14QXJyYXlIABITCglyYXdfdmFsdWUYEiABKAxIAEIGCgRr", + "aW5kIv4ECgdNeEFycmF5EjoKEWVsZW1lbnRfZGF0YV90eXBlGAEgASgOMh8u", + "bXhhY2Nlc3NfZ2F0ZXdheS52MS5NeERhdGFUeXBlEhQKDHZhcmlhbnRfdHlw", + "ZRgCIAEoCRISCgpkaW1lbnNpb25zGAMgAygNEhYKDnJhd19kaWFnbm9zdGlj", + "GAQgASgJEh0KFXJhd19lbGVtZW50X2RhdGFfdHlwZRgFIAEoBRI1Cgtib29s", + "X3ZhbHVlcxgKIAEoCzIeLm14YWNjZXNzX2dhdGV3YXkudjEuQm9vbEFycmF5", + "SAASNwoMaW50MzJfdmFsdWVzGAsgASgLMh8ubXhhY2Nlc3NfZ2F0ZXdheS52", + "MS5JbnQzMkFycmF5SAASNwoMaW50NjRfdmFsdWVzGAwgASgLMh8ubXhhY2Nl", + "c3NfZ2F0ZXdheS52MS5JbnQ2NEFycmF5SAASNwoMZmxvYXRfdmFsdWVzGA0g", + "ASgLMh8ubXhhY2Nlc3NfZ2F0ZXdheS52MS5GbG9hdEFycmF5SAASOQoNZG91", + "YmxlX3ZhbHVlcxgOIAEoCzIgLm14YWNjZXNzX2dhdGV3YXkudjEuRG91Ymxl", + "QXJyYXlIABI5Cg1zdHJpbmdfdmFsdWVzGA8gASgLMiAubXhhY2Nlc3NfZ2F0", + "ZXdheS52MS5TdHJpbmdBcnJheUgAEj8KEHRpbWVzdGFtcF92YWx1ZXMYECAB", + "KAsyIy5teGFjY2Vzc19nYXRld2F5LnYxLlRpbWVzdGFtcEFycmF5SAASMwoK", + "cmF3X3ZhbHVlcxgRIAEoCzIdLm14YWNjZXNzX2dhdGV3YXkudjEuUmF3QXJy", + "YXlIAEIICgZ2YWx1ZXMiGwoJQm9vbEFycmF5Eg4KBnZhbHVlcxgBIAMoCCIc", + "CgpJbnQzMkFycmF5Eg4KBnZhbHVlcxgBIAMoBSIcCgpJbnQ2NEFycmF5Eg4K", + "BnZhbHVlcxgBIAMoAyIcCgpGbG9hdEFycmF5Eg4KBnZhbHVlcxgBIAMoAiId", + "CgtEb3VibGVBcnJheRIOCgZ2YWx1ZXMYASADKAEiHQoLU3RyaW5nQXJyYXkS", + "DgoGdmFsdWVzGAEgAygJIjwKDlRpbWVzdGFtcEFycmF5EioKBnZhbHVlcxgB", + "IAMoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXAiGgoIUmF3QXJyYXkS", + "DgoGdmFsdWVzGAEgAygMIlgKDlByb3RvY29sU3RhdHVzEjUKBGNvZGUYASAB", + "KA4yJy5teGFjY2Vzc19nYXRld2F5LnYxLlByb3RvY29sU3RhdHVzQ29kZRIP", + "CgdtZXNzYWdlGAIgASgJKr8GCg1NeENvbW1hbmRLaW5kEh8KG01YX0NPTU1B", + "TkRfS0lORF9VTlNQRUNJRklFRBAAEhwKGE1YX0NPTU1BTkRfS0lORF9SRUdJ", + "U1RFUhABEh4KGk1YX0NPTU1BTkRfS0lORF9VTlJFR0lTVEVSEAISHAoYTVhf", + "Q09NTUFORF9LSU5EX0FERF9JVEVNEAMSHQoZTVhfQ09NTUFORF9LSU5EX0FE", + "RF9JVEVNMhAEEh8KG01YX0NPTU1BTkRfS0lORF9SRU1PVkVfSVRFTRAFEhoK", + "Fk1YX0NPTU1BTkRfS0lORF9BRFZJU0UQBhIdChlNWF9DT01NQU5EX0tJTkRf", + "VU5fQURWSVNFEAcSJgoiTVhfQ09NTUFORF9LSU5EX0FEVklTRV9TVVBFUlZJ", + "U09SWRAIEiUKIU1YX0NPTU1BTkRfS0lORF9BRERfQlVGRkVSRURfSVRFTRAJ", + "EjAKLE1YX0NPTU1BTkRfS0lORF9TRVRfQlVGRkVSRURfVVBEQVRFX0lOVEVS", + "VkFMEAoSGwoXTVhfQ09NTUFORF9LSU5EX1NVU1BFTkQQCxIcChhNWF9DT01N", + "QU5EX0tJTkRfQUNUSVZBVEUQDBIZChVNWF9DT01NQU5EX0tJTkRfV1JJVEUQ", + "DRIaChZNWF9DT01NQU5EX0tJTkRfV1JJVEUyEA4SIQodTVhfQ09NTUFORF9L", + "SU5EX1dSSVRFX1NFQ1VSRUQQDxIiCh5NWF9DT01NQU5EX0tJTkRfV1JJVEVf", + "U0VDVVJFRDIQEBIlCiFNWF9DT01NQU5EX0tJTkRfQVVUSEVOVElDQVRFX1VT", + "RVIQERIoCiRNWF9DT01NQU5EX0tJTkRfQVJDSEVTVFJBX1VTRVJfVE9fSUQQ", + "EhIYChRNWF9DT01NQU5EX0tJTkRfUElORxBkEiUKIU1YX0NPTU1BTkRfS0lO", + "RF9HRVRfU0VTU0lPTl9TVEFURRBlEiMKH01YX0NPTU1BTkRfS0lORF9HRVRf", + "V09SS0VSX0lORk8QZhIgChxNWF9DT01NQU5EX0tJTkRfRFJBSU5fRVZFTlRT", + "EGcSIwofTVhfQ09NTUFORF9LSU5EX1NIVVRET1dOX1dPUktFUhBoKtABCg1N", + "eEV2ZW50RmFtaWx5Eh8KG01YX0VWRU5UX0ZBTUlMWV9VTlNQRUNJRklFRBAA", + "EiIKHk1YX0VWRU5UX0ZBTUlMWV9PTl9EQVRBX0NIQU5HRRABEiUKIU1YX0VW", + "RU5UX0ZBTUlMWV9PTl9XUklURV9DT01QTEVURRACEiYKIk1YX0VWRU5UX0ZB", + "TUlMWV9PUEVSQVRJT05fQ09NUExFVEUQAxIrCidNWF9FVkVOVF9GQU1JTFlf", + "T05fQlVGRkVSRURfREFUQV9DSEFOR0UQBCqlAwoQTXhTdGF0dXNDYXRlZ29y", + "eRIiCh5NWF9TVEFUVVNfQ0FURUdPUllfVU5TUEVDSUZJRUQQABIeChpNWF9T", + "VEFUVVNfQ0FURUdPUllfVU5LTk9XThABEhkKFU1YX1NUQVRVU19DQVRFR09S", + "WV9PSxACEh4KGk1YX1NUQVRVU19DQVRFR09SWV9QRU5ESU5HEAMSHgoaTVhf", + "U1RBVFVTX0NBVEVHT1JZX1dBUk5JTkcQBBIqCiZNWF9TVEFUVVNfQ0FURUdP", + "UllfQ09NTVVOSUNBVElPTl9FUlJPUhAFEioKJk1YX1NUQVRVU19DQVRFR09S", + "WV9DT05GSUdVUkFUSU9OX0VSUk9SEAYSKAokTVhfU1RBVFVTX0NBVEVHT1JZ", + "X09QRVJBVElPTkFMX0VSUk9SEAcSJQohTVhfU1RBVFVTX0NBVEVHT1JZX1NF", + "Q1VSSVRZX0VSUk9SEAgSJQohTVhfU1RBVFVTX0NBVEVHT1JZX1NPRlRXQVJF", + "X0VSUk9SEAkSIgoeTVhfU1RBVFVTX0NBVEVHT1JZX09USEVSX0VSUk9SEAoq", + "ygIKDk14U3RhdHVzU291cmNlEiAKHE1YX1NUQVRVU19TT1VSQ0VfVU5TUEVD", + "SUZJRUQQABIcChhNWF9TVEFUVVNfU09VUkNFX1VOS05PV04QARIjCh9NWF9T", + "VEFUVVNfU09VUkNFX1JFUVVFU1RJTkdfTE1YEAISIwofTVhfU1RBVFVTX1NP", + "VVJDRV9SRVNQT05ESU5HX0xNWBADEiMKH01YX1NUQVRVU19TT1VSQ0VfUkVR", + "VUVTVElOR19OTVgQBBIjCh9NWF9TVEFUVVNfU09VUkNFX1JFU1BPTkRJTkdf", + "Tk1YEAUSMQotTVhfU1RBVFVTX1NPVVJDRV9SRVFVRVNUSU5HX0FVVE9NQVRJ", + "T05fT0JKRUNUEAYSMQotTVhfU1RBVFVTX1NPVVJDRV9SRVNQT05ESU5HX0FV", + "VE9NQVRJT05fT0JKRUNUEAcq3QQKCk14RGF0YVR5cGUSHAoYTVhfREFUQV9U", + "WVBFX1VOU1BFQ0lGSUVEEAASGAoUTVhfREFUQV9UWVBFX1VOS05PV04QARIY", + "ChRNWF9EQVRBX1RZUEVfTk9fREFUQRACEhgKFE1YX0RBVEFfVFlQRV9CT09M", + "RUFOEAMSGAoUTVhfREFUQV9UWVBFX0lOVEVHRVIQBBIWChJNWF9EQVRBX1RZ", + "UEVfRkxPQVQQBRIXChNNWF9EQVRBX1RZUEVfRE9VQkxFEAYSFwoTTVhfREFU", + "QV9UWVBFX1NUUklORxAHEhUKEU1YX0RBVEFfVFlQRV9USU1FEAgSHQoZTVhf", + "REFUQV9UWVBFX0VMQVBTRURfVElNRRAJEh8KG01YX0RBVEFfVFlQRV9SRUZF", + "UkVOQ0VfVFlQRRAKEhwKGE1YX0RBVEFfVFlQRV9TVEFUVVNfVFlQRRALEhUK", + "EU1YX0RBVEFfVFlQRV9FTlVNEAwSLQopTVhfREFUQV9UWVBFX1NFQ1VSSVRZ", + "X0NMQVNTSUZJQ0FUSU9OX0VOVU0QDRIiCh5NWF9EQVRBX1RZUEVfREFUQV9R", + "VUFMSVRZX1RZUEUQDhIfChtNWF9EQVRBX1RZUEVfUVVBTElGSUVEX0VOVU0Q", + "DxIhCh1NWF9EQVRBX1RZUEVfUVVBTElGSUVEX1NUUlVDVBAQEikKJU1YX0RB", + "VEFfVFlQRV9JTlRFUk5BVElPTkFMSVpFRF9TVFJJTkcQERIbChdNWF9EQVRB", + "X1RZUEVfQklHX1NUUklORxASEhQKEE1YX0RBVEFfVFlQRV9FTkQQEyqjAwoS", + "UHJvdG9jb2xTdGF0dXNDb2RlEiQKIFBST1RPQ09MX1NUQVRVU19DT0RFX1VO", + "U1BFQ0lGSUVEEAASGwoXUFJPVE9DT0xfU1RBVFVTX0NPREVfT0sQARIoCiRQ", + "Uk9UT0NPTF9TVEFUVVNfQ09ERV9JTlZBTElEX1JFUVVFU1QQAhIqCiZQUk9U", + "T0NPTF9TVEFUVVNfQ09ERV9TRVNTSU9OX05PVF9GT1VORBADEioKJlBST1RP", + "Q09MX1NUQVRVU19DT0RFX1NFU1NJT05fTk9UX1JFQURZEAQSKwonUFJPVE9D", + "T0xfU1RBVFVTX0NPREVfV09SS0VSX1VOQVZBSUxBQkxFEAUSIAocUFJPVE9D", + "T0xfU1RBVFVTX0NPREVfVElNRU9VVBAGEiEKHVBST1RPQ09MX1NUQVRVU19D", + "T0RFX0NBTkNFTEVEEAcSKwonUFJPVE9DT0xfU1RBVFVTX0NPREVfUFJPVE9D", + "T0xfVklPTEFUSU9OEAgSKQolUFJPVE9DT0xfU1RBVFVTX0NPREVfTVhBQ0NF", + "U1NfRkFJTFVSRRAJKr8CCgxTZXNzaW9uU3RhdGUSHQoZU0VTU0lPTl9TVEFU", + "RV9VTlNQRUNJRklFRBAAEhoKFlNFU1NJT05fU1RBVEVfQ1JFQVRJTkcQARIh", + "Ch1TRVNTSU9OX1NUQVRFX1NUQVJUSU5HX1dPUktFUhACEiIKHlNFU1NJT05f", + "U1RBVEVfV0FJVElOR19GT1JfUElQRRADEh0KGVNFU1NJT05fU1RBVEVfSEFO", + "RFNIQUtJTkcQBBIlCiFTRVNTSU9OX1NUQVRFX0lOSVRJQUxJWklOR19XT1JL", + "RVIQBRIXChNTRVNTSU9OX1NUQVRFX1JFQURZEAYSGQoVU0VTU0lPTl9TVEFU", + "RV9DTE9TSU5HEAcSGAoUU0VTU0lPTl9TVEFURV9DTE9TRUQQCBIZChVTRVNT", + "SU9OX1NUQVRFX0ZBVUxURUQQCTKCAwoPTXhBY2Nlc3NHYXRld2F5El0KC09w", + "ZW5TZXNzaW9uEicubXhhY2Nlc3NfZ2F0ZXdheS52MS5PcGVuU2Vzc2lvblJl", + "cXVlc3QaJS5teGFjY2Vzc19nYXRld2F5LnYxLk9wZW5TZXNzaW9uUmVwbHkS", + "YAoMQ2xvc2VTZXNzaW9uEigubXhhY2Nlc3NfZ2F0ZXdheS52MS5DbG9zZVNl", + "c3Npb25SZXF1ZXN0GiYubXhhY2Nlc3NfZ2F0ZXdheS52MS5DbG9zZVNlc3Np", + "b25SZXBseRJUCgZJbnZva2USJS5teGFjY2Vzc19nYXRld2F5LnYxLk14Q29t", + "bWFuZFJlcXVlc3QaIy5teGFjY2Vzc19nYXRld2F5LnYxLk14Q29tbWFuZFJl", + "cGx5ElgKDFN0cmVhbUV2ZW50cxIoLm14YWNjZXNzX2dhdGV3YXkudjEuU3Ry", + "ZWFtRXZlbnRzUmVxdWVzdBocLm14YWNjZXNzX2dhdGV3YXkudjEuTXhFdmVu", + "dDABQhyqAhlNeEdhdGV3YXkuQ29udHJhY3RzLlByb3RvYgZwcm90bzM=")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.DurationReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, }, new pbr::GeneratedClrTypeInfo(new[] {typeof(global::MxGateway.Contracts.Proto.MxCommandKind), typeof(global::MxGateway.Contracts.Proto.MxEventFamily), typeof(global::MxGateway.Contracts.Proto.MxStatusCategory), typeof(global::MxGateway.Contracts.Proto.MxStatusSource), typeof(global::MxGateway.Contracts.Proto.MxDataType), typeof(global::MxGateway.Contracts.Proto.ProtocolStatusCode), typeof(global::MxGateway.Contracts.Proto.SessionState), }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::MxGateway.Contracts.Proto.OpenSessionRequest), global::MxGateway.Contracts.Proto.OpenSessionRequest.Parser, new[]{ "RequestedBackend", "ClientSessionName", "ClientCorrelationId", "CommandTimeout" }, null, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::MxGateway.Contracts.Proto.OpenSessionReply), global::MxGateway.Contracts.Proto.OpenSessionReply.Parser, new[]{ "SessionId", "BackendName", "WorkerProcessId", "WorkerProtocolVersion", "Capabilities", "DefaultCommandTimeout", "ProtocolStatus" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::MxGateway.Contracts.Proto.OpenSessionReply), global::MxGateway.Contracts.Proto.OpenSessionReply.Parser, new[]{ "SessionId", "BackendName", "WorkerProcessId", "WorkerProtocolVersion", "Capabilities", "DefaultCommandTimeout", "ProtocolStatus", "GatewayProtocolVersion" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::MxGateway.Contracts.Proto.CloseSessionRequest), global::MxGateway.Contracts.Proto.CloseSessionRequest.Parser, new[]{ "SessionId", "ClientCorrelationId" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::MxGateway.Contracts.Proto.CloseSessionReply), global::MxGateway.Contracts.Proto.CloseSessionReply.Parser, new[]{ "SessionId", "FinalState", "ProtocolStatus" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::MxGateway.Contracts.Proto.StreamEventsRequest), global::MxGateway.Contracts.Proto.StreamEventsRequest.Parser, new[]{ "SessionId", "AfterWorkerSequence" }, null, null, null, null), @@ -841,6 +841,7 @@ namespace MxGateway.Contracts.Proto { capabilities_ = other.capabilities_.Clone(); defaultCommandTimeout_ = other.defaultCommandTimeout_ != null ? other.defaultCommandTimeout_.Clone() : null; protocolStatus_ = other.protocolStatus_ != null ? other.protocolStatus_.Clone() : null; + gatewayProtocolVersion_ = other.gatewayProtocolVersion_; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } @@ -933,6 +934,23 @@ namespace MxGateway.Contracts.Proto { } } + /// Field number for the "gateway_protocol_version" field. + public const int GatewayProtocolVersionFieldNumber = 8; + private uint gatewayProtocolVersion_; + /// + /// Public gateway contract version implemented by this endpoint. Clients use + /// this value to reject incompatible generated-code inputs before issuing + /// command-specific MXAccess calls. + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public uint GatewayProtocolVersion { + get { return gatewayProtocolVersion_; } + set { + gatewayProtocolVersion_ = value; + } + } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public override bool Equals(object other) { @@ -955,6 +973,7 @@ namespace MxGateway.Contracts.Proto { if(!capabilities_.Equals(other.capabilities_)) return false; if (!object.Equals(DefaultCommandTimeout, other.DefaultCommandTimeout)) return false; if (!object.Equals(ProtocolStatus, other.ProtocolStatus)) return false; + if (GatewayProtocolVersion != other.GatewayProtocolVersion) return false; return Equals(_unknownFields, other._unknownFields); } @@ -969,6 +988,7 @@ namespace MxGateway.Contracts.Proto { hash ^= capabilities_.GetHashCode(); if (defaultCommandTimeout_ != null) hash ^= DefaultCommandTimeout.GetHashCode(); if (protocolStatus_ != null) hash ^= ProtocolStatus.GetHashCode(); + if (GatewayProtocolVersion != 0) hash ^= GatewayProtocolVersion.GetHashCode(); if (_unknownFields != null) { hash ^= _unknownFields.GetHashCode(); } @@ -1012,6 +1032,10 @@ namespace MxGateway.Contracts.Proto { output.WriteRawTag(58); output.WriteMessage(ProtocolStatus); } + if (GatewayProtocolVersion != 0) { + output.WriteRawTag(64); + output.WriteUInt32(GatewayProtocolVersion); + } if (_unknownFields != null) { _unknownFields.WriteTo(output); } @@ -1047,6 +1071,10 @@ namespace MxGateway.Contracts.Proto { output.WriteRawTag(58); output.WriteMessage(ProtocolStatus); } + if (GatewayProtocolVersion != 0) { + output.WriteRawTag(64); + output.WriteUInt32(GatewayProtocolVersion); + } if (_unknownFields != null) { _unknownFields.WriteTo(ref output); } @@ -1076,6 +1104,9 @@ namespace MxGateway.Contracts.Proto { if (protocolStatus_ != null) { size += 1 + pb::CodedOutputStream.ComputeMessageSize(ProtocolStatus); } + if (GatewayProtocolVersion != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(GatewayProtocolVersion); + } if (_unknownFields != null) { size += _unknownFields.CalculateSize(); } @@ -1113,6 +1144,9 @@ namespace MxGateway.Contracts.Proto { } ProtocolStatus.MergeFrom(other.ProtocolStatus); } + if (other.GatewayProtocolVersion != 0) { + GatewayProtocolVersion = other.GatewayProtocolVersion; + } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); } @@ -1166,6 +1200,10 @@ namespace MxGateway.Contracts.Proto { input.ReadMessage(ProtocolStatus); break; } + case 64: { + GatewayProtocolVersion = input.ReadUInt32(); + break; + } } } #endif @@ -1219,6 +1257,10 @@ namespace MxGateway.Contracts.Proto { input.ReadMessage(ProtocolStatus); break; } + case 64: { + GatewayProtocolVersion = input.ReadUInt32(); + break; + } } } } diff --git a/src/MxGateway.Contracts/Protos/mxaccess_gateway.proto b/src/MxGateway.Contracts/Protos/mxaccess_gateway.proto index 6bdbfbb..898c742 100644 --- a/src/MxGateway.Contracts/Protos/mxaccess_gateway.proto +++ b/src/MxGateway.Contracts/Protos/mxaccess_gateway.proto @@ -30,6 +30,10 @@ message OpenSessionReply { repeated string capabilities = 5; google.protobuf.Duration default_command_timeout = 6; ProtocolStatus protocol_status = 7; + // Public gateway contract version implemented by this endpoint. Clients use + // this value to reject incompatible generated-code inputs before issuing + // command-specific MXAccess calls. + uint32 gateway_protocol_version = 8; } message CloseSessionRequest { diff --git a/src/MxGateway.Server/Grpc/MxAccessGatewayService.cs b/src/MxGateway.Server/Grpc/MxAccessGatewayService.cs index 2b75baf..201bedf 100644 --- a/src/MxGateway.Server/Grpc/MxAccessGatewayService.cs +++ b/src/MxGateway.Server/Grpc/MxAccessGatewayService.cs @@ -35,6 +35,7 @@ public sealed class MxAccessGatewayService( BackendName = session.BackendName, WorkerProcessId = session.WorkerProcessId ?? 0, WorkerProtocolVersion = GatewayContractInfo.WorkerProtocolVersion, + GatewayProtocolVersion = GatewayContractInfo.GatewayProtocolVersion, DefaultCommandTimeout = Google.Protobuf.WellKnownTypes.Duration.FromTimeSpan(session.CommandTimeout), ProtocolStatus = MxAccessGrpcMapper.Ok(), }; diff --git a/src/MxGateway.Tests/Contracts/ClientProtoInputTests.cs b/src/MxGateway.Tests/Contracts/ClientProtoInputTests.cs new file mode 100644 index 0000000..684abe5 --- /dev/null +++ b/src/MxGateway.Tests/Contracts/ClientProtoInputTests.cs @@ -0,0 +1,102 @@ +using System.Text.Json; +using Google.Protobuf; +using MxGateway.Contracts; +using MxGateway.Contracts.Proto; + +namespace MxGateway.Tests.Contracts; + +public sealed class ClientProtoInputTests +{ + [Fact] + public void Manifest_DeclaresCurrentProtocolVersionsAndExistingInputs() + { + DirectoryInfo repositoryRoot = FindRepositoryRoot(); + string manifestPath = Path.Combine(repositoryRoot.FullName, "clients", "proto", "proto-inputs.json"); + + using JsonDocument manifest = JsonDocument.Parse(File.ReadAllText(manifestPath)); + JsonElement root = manifest.RootElement; + + Assert.Equal(1, root.GetProperty("schemaVersion").GetInt32()); + Assert.Equal(GatewayContractInfo.GatewayProtocolVersion, root.GetProperty("gatewayProtocolVersion").GetUInt32()); + Assert.Equal(GatewayContractInfo.WorkerProtocolVersion, root.GetProperty("workerProtocolVersion").GetUInt32()); + + string protoRoot = Path.Combine(repositoryRoot.FullName, root.GetProperty("protoRoot").GetString()!); + foreach (JsonElement sourceFile in root.GetProperty("sourceFiles").EnumerateArray()) + { + string sourcePath = Path.Combine(protoRoot, sourceFile.GetProperty("path").GetString()!); + Assert.True(File.Exists(sourcePath), $"Expected proto source file '{sourcePath}' to exist."); + } + + foreach (JsonProperty output in root.GetProperty("generatedOutputs").EnumerateObject()) + { + string outputPath = Path.Combine(repositoryRoot.FullName, output.Value.GetString()!); + Assert.True(Directory.Exists(outputPath), $"Expected generated output directory '{outputPath}' to exist."); + } + } + + [Fact] + public void OpenSessionReplyFixture_ParsesWithCurrentContract() + { + OpenSessionReply reply = ParseFixture( + "open-session-reply.ok.json", + OpenSessionReply.Parser); + + Assert.Equal(GatewayContractInfo.GatewayProtocolVersion, reply.GatewayProtocolVersion); + Assert.Equal(GatewayContractInfo.WorkerProtocolVersion, reply.WorkerProtocolVersion); + Assert.Equal(ProtocolStatusCode.Ok, reply.ProtocolStatus.Code); + } + + [Fact] + public void RegisterCommandRequestFixture_ParsesWithCurrentContract() + { + MxCommandRequest request = ParseFixture( + "register-command-request.json", + MxCommandRequest.Parser); + + Assert.Equal(MxCommandKind.Register, request.Command.Kind); + Assert.Equal("fixture-client", request.Command.Register.ClientName); + } + + [Fact] + public void OnDataChangeEventFixture_ParsesWithCurrentContract() + { + MxEvent gatewayEvent = ParseFixture( + "on-data-change-event.json", + MxEvent.Parser); + + Assert.Equal(MxEventFamily.OnDataChange, gatewayEvent.Family); + Assert.Equal(1ul, gatewayEvent.WorkerSequence); + Assert.Equal(MxDataType.Integer, gatewayEvent.Value.DataType); + Assert.Equal(MxEvent.BodyOneofCase.OnDataChange, gatewayEvent.BodyCase); + } + + private static T ParseFixture( + string fixtureName, + MessageParser parser) + where T : IMessage + { + DirectoryInfo repositoryRoot = FindRepositoryRoot(); + string fixturePath = Path.Combine(repositoryRoot.FullName, "clients", "proto", "fixtures", "golden", fixtureName); + + return parser.ParseJson(File.ReadAllText(fixturePath)); + } + + private static DirectoryInfo FindRepositoryRoot() + { + DirectoryInfo? current = new(AppContext.BaseDirectory); + + while (current is not null) + { + if (File.Exists(Path.Combine(current.FullName, "AGENTS.md")) + && Directory.Exists(Path.Combine(current.FullName, "src")) + && Directory.Exists(Path.Combine(current.FullName, "clients"))) + { + return current; + } + + current = current.Parent; + } + + throw new DirectoryNotFoundException("Could not locate the repository root from the test output directory."); + } +} diff --git a/src/MxGateway.Tests/Contracts/GatewayContractInfoTests.cs b/src/MxGateway.Tests/Contracts/GatewayContractInfoTests.cs index 93c0acf..65456fb 100644 --- a/src/MxGateway.Tests/Contracts/GatewayContractInfoTests.cs +++ b/src/MxGateway.Tests/Contracts/GatewayContractInfoTests.cs @@ -10,6 +10,12 @@ public sealed class GatewayContractInfoTests Assert.Equal("mxaccess-worker", GatewayContractInfo.DefaultBackendName); } + [Fact] + public void GatewayProtocolVersion_StartsAtVersionOne() + { + Assert.Equal(1u, GatewayContractInfo.GatewayProtocolVersion); + } + [Fact] public void WorkerProtocolVersion_StartsAtVersionOne() { diff --git a/src/MxGateway.Tests/Gateway/Grpc/MxAccessGatewayServiceTests.cs b/src/MxGateway.Tests/Gateway/Grpc/MxAccessGatewayServiceTests.cs index 0d7d605..f6d5806 100644 --- a/src/MxGateway.Tests/Gateway/Grpc/MxAccessGatewayServiceTests.cs +++ b/src/MxGateway.Tests/Gateway/Grpc/MxAccessGatewayServiceTests.cs @@ -37,6 +37,7 @@ public sealed class MxAccessGatewayServiceTests Assert.Equal(GatewayContractInfo.DefaultBackendName, reply.BackendName); Assert.Equal(4321, reply.WorkerProcessId); Assert.Equal(GatewayContractInfo.WorkerProtocolVersion, reply.WorkerProtocolVersion); + Assert.Equal(GatewayContractInfo.GatewayProtocolVersion, reply.GatewayProtocolVersion); Assert.Equal(ProtocolStatusCode.Ok, reply.ProtocolStatus.Code); Assert.Contains("unary-invoke", reply.Capabilities); Assert.Equal("Operator Key", sessionManager.LastClientIdentity); -- 2.52.0