sonamu 0.11.16 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/_rolldown/runtime.js +1 -2
- package/dist/ai/agents/agent.js +2 -3
- package/dist/ai/agents/index.js +1 -2
- package/dist/ai/index.js +1 -2
- package/dist/ai/providers/rtzr/api.js +1 -2
- package/dist/ai/providers/rtzr/error.js +2 -3
- package/dist/ai/providers/rtzr/model.js +1 -2
- package/dist/ai/providers/rtzr/options.js +1 -2
- package/dist/ai/providers/rtzr/provider.js +1 -2
- package/dist/ai/providers/rtzr/utils.js +1 -2
- package/dist/api/base-frame.js +4 -4
- package/dist/api/caster.d.ts +1 -1
- package/dist/api/caster.d.ts.map +1 -1
- package/dist/api/caster.js +9 -9
- package/dist/api/code-converters.js +6 -5
- package/dist/api/config.d.ts +1 -1
- package/dist/api/config.d.ts.map +1 -1
- package/dist/api/config.js +2 -3
- package/dist/api/context.d.ts +2 -3
- package/dist/api/context.d.ts.map +1 -1
- package/dist/api/context.js +2 -3
- package/dist/api/decorators.js +2 -3
- package/dist/api/http-validator.js +2 -3
- package/dist/api/index.js +8 -3
- package/dist/api/secret.js +1 -2
- package/dist/api/sonamu.d.ts +3 -5
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +30 -24
- package/dist/api/validator.js +1 -2
- package/dist/api/websocket-helpers.js +2 -3
- package/dist/auth/audit-log/builders.js +1 -2
- package/dist/auth/audit-log/client-ip.js +2 -3
- package/dist/auth/audit-log/events.js +1 -2
- package/dist/auth/audit-log/plugin.d.ts.map +1 -1
- package/dist/auth/audit-log/plugin.js +2 -3
- package/dist/auth/audit-log-ingestor.js +2 -3
- package/dist/auth/auth-generator.js +2 -3
- package/dist/auth/better-auth-entities.js +1 -2
- package/dist/auth/better-auth-request.js +2 -3
- package/dist/auth/index.js +2 -3
- package/dist/auth/knex-adapter.js +2 -3
- package/dist/auth/plugins/entity-definitions/admin.js +1 -2
- package/dist/auth/plugins/entity-definitions/anonymous.js +1 -2
- package/dist/auth/plugins/entity-definitions/api-key.js +1 -2
- package/dist/auth/plugins/entity-definitions/audit-log.js +1 -2
- package/dist/auth/plugins/entity-definitions/index.js +1 -2
- package/dist/auth/plugins/entity-definitions/jwt.js +1 -2
- package/dist/auth/plugins/entity-definitions/organization.js +1 -2
- package/dist/auth/plugins/entity-definitions/passkey.js +1 -2
- package/dist/auth/plugins/entity-definitions/phone-number.js +1 -2
- package/dist/auth/plugins/entity-definitions/sso.js +1 -2
- package/dist/auth/plugins/entity-definitions/two-factor.js +1 -2
- package/dist/auth/plugins/entity-definitions/username.js +1 -2
- package/dist/auth/plugins/wrappers/admin.d.ts +33 -32
- package/dist/auth/plugins/wrappers/admin.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/admin.js +2 -3
- package/dist/auth/plugins/wrappers/anonymous.js +2 -3
- package/dist/auth/plugins/wrappers/api-key.js +2 -3
- package/dist/auth/plugins/wrappers/jwt.js +2 -3
- package/dist/auth/plugins/wrappers/organization.js +2 -3
- package/dist/auth/plugins/wrappers/passkey.js +2 -3
- package/dist/auth/plugins/wrappers/phone-number.d.ts +43 -1
- package/dist/auth/plugins/wrappers/phone-number.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/phone-number.js +2 -3
- package/dist/auth/plugins/wrappers/sso.d.ts +138 -187
- package/dist/auth/plugins/wrappers/sso.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/sso.js +1 -2
- package/dist/auth/plugins/wrappers/two-factor.d.ts +51 -10
- package/dist/auth/plugins/wrappers/two-factor.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/two-factor.js +2 -3
- package/dist/auth/plugins/wrappers/username.d.ts +39 -5
- package/dist/auth/plugins/wrappers/username.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/username.js +2 -3
- package/dist/bin/build-config.js +5 -5
- package/dist/bin/compiler-policy.js +2 -3
- package/dist/bin/fixture.js +7 -5
- package/dist/bin/hmr-hook-register.js +1 -2
- package/dist/bin/migrate-targets.js +2 -3
- package/dist/bin/test-command.js +2 -3
- package/dist/bin/ts-loader-register.js +2 -3
- package/dist/bin/ts-loader-registration.js +2 -3
- package/dist/bin/typecheck-web.js +2 -3
- package/dist/cache/cache-manager.js +1 -2
- package/dist/cache/decorator.js +2 -3
- package/dist/cache/drivers.js +1 -2
- package/dist/cache/index.js +2 -3
- package/dist/cache-control/cache-control.js +1 -2
- package/dist/code-formatting/index.js +2 -3
- package/dist/code-formatting/oxfmt.js +2 -3
- package/dist/code-formatting/oxlint.js +2 -3
- package/dist/compress/compress.js +1 -2
- package/dist/compress/index.js +2 -2
- package/dist/compress/types.d.ts +1 -1
- package/dist/compress/types.d.ts.map +1 -1
- package/dist/cone/cone-generator.js +2 -3
- package/dist/database/_batch_update.js +1 -2
- package/dist/database/base-model.js +4 -4
- package/dist/database/db.js +4 -4
- package/dist/database/knex.js +2 -3
- package/dist/database/puri-wrapper.js +2 -3
- package/dist/database/puri.js +23 -22
- package/dist/database/puri.types.js +1 -2
- package/dist/database/transaction-context.js +1 -2
- package/dist/database/upsert-builder.js +2 -3
- package/dist/dict/en.js +2 -3
- package/dist/dict/index.js +3 -3
- package/dist/dict/ko.js +2 -3
- package/dist/dict/rc-keys.js +1 -2
- package/dist/dict/sd.js +2 -3
- package/dist/dict/sonamu-dictionary.js +7 -6
- package/dist/dict/utils.js +2 -3
- package/dist/entity/entity-manager.d.ts +66 -66
- package/dist/entity/entity-manager.js +4 -4
- package/dist/entity/entity-template-cone.js +2 -3
- package/dist/entity/entity.js +21 -18
- package/dist/env.js +1 -2
- package/dist/exceptions/error-handler.d.ts.map +1 -1
- package/dist/exceptions/error-handler.js +2 -3
- package/dist/exceptions/so-exceptions.js +2 -3
- package/dist/filter/index.js +3 -2
- package/dist/filter/types.js +1 -2
- package/dist/filter/utils.js +7 -6
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +42 -6
- package/dist/logger/category.js +2 -3
- package/dist/logger/configure.js +5 -5
- package/dist/migration/code-generation.js +23 -16
- package/dist/migration/index-where-predicate.js +2 -3
- package/dist/migration/migration-set.js +2 -3
- package/dist/migration/migrator.js +2 -3
- package/dist/migration/postgresql-schema-reader.js +6 -9
- package/dist/migration/slack-confirm.js +2 -3
- package/dist/naite/naite-reporter.js +2 -3
- package/dist/naite/naite.js +10 -8
- package/dist/runtime-type.js +2 -3
- package/dist/ssr/hmr-opt-out.js +1 -2
- package/dist/ssr/index.js +7 -4
- package/dist/ssr/registry.js +1 -2
- package/dist/ssr/renderer.js +2 -3
- package/dist/storage/base-file.js +1 -2
- package/dist/storage/buffered-file.js +2 -3
- package/dist/storage/drivers.js +1 -2
- package/dist/storage/index.js +2 -3
- package/dist/storage/s3-driver.js +1 -2
- package/dist/storage/storage-manager.js +2 -3
- package/dist/storage/uploaded-file.js +2 -3
- package/dist/stream/__tests__/ws-test-helpers.d.ts +108 -0
- package/dist/stream/__tests__/ws-test-helpers.d.ts.map +1 -0
- package/dist/stream/__tests__/ws-test-helpers.js +259 -0
- package/dist/stream/index.d.ts +1 -0
- package/dist/stream/index.d.ts.map +1 -1
- package/dist/stream/index.js +15 -4
- package/dist/stream/sse.js +1 -2
- package/dist/stream/ws-audience-resolver.d.ts +8 -5
- package/dist/stream/ws-audience-resolver.d.ts.map +1 -1
- package/dist/stream/ws-audience-resolver.js +17 -15
- package/dist/stream/ws-audience.js +1 -2
- package/dist/stream/ws-cluster-bus.d.ts +9 -4
- package/dist/stream/ws-cluster-bus.d.ts.map +1 -1
- package/dist/stream/ws-cluster-bus.js +2 -3
- package/dist/stream/ws-core.d.ts +10 -0
- package/dist/stream/ws-core.d.ts.map +1 -1
- package/dist/stream/ws-delivery.d.ts +30 -4
- package/dist/stream/ws-delivery.d.ts.map +1 -1
- package/dist/stream/ws-delivery.js +200 -54
- package/dist/stream/ws-frame.d.ts +15 -0
- package/dist/stream/ws-frame.d.ts.map +1 -0
- package/dist/stream/ws-frame.js +28 -0
- package/dist/stream/ws-local-connection-store.d.ts +4 -4
- package/dist/stream/ws-local-connection-store.d.ts.map +1 -1
- package/dist/stream/ws-local-connection-store.js +3 -4
- package/dist/stream/ws-presence-index.d.ts +36 -0
- package/dist/stream/ws-presence-index.d.ts.map +1 -0
- package/dist/stream/ws-presence-index.js +176 -0
- package/dist/stream/ws-presence-store.d.ts +39 -39
- package/dist/stream/ws-presence-store.d.ts.map +1 -1
- package/dist/stream/ws-presence-store.js +23 -154
- package/dist/stream/ws-registry.d.ts +45 -17
- package/dist/stream/ws-registry.d.ts.map +1 -1
- package/dist/stream/ws-registry.js +170 -62
- package/dist/stream/ws-session-id.d.ts +14 -0
- package/dist/stream/ws-session-id.d.ts.map +1 -0
- package/dist/stream/ws-session-id.js +36 -0
- package/dist/stream/ws-telemetry-memory.js +3 -4
- package/dist/stream/ws-telemetry-trace.js +1 -2
- package/dist/stream/ws-telemetry.js +2 -3
- package/dist/stream/ws.d.ts +20 -10
- package/dist/stream/ws.d.ts.map +1 -1
- package/dist/stream/ws.js +60 -38
- package/dist/syncer/api-parser.js +2 -3
- package/dist/syncer/checksum.js +4 -4
- package/dist/syncer/code-generator.js +4 -4
- package/dist/syncer/entity-operations.js +2 -3
- package/dist/syncer/event-batcher.js +1 -2
- package/dist/syncer/file-copy.js +2 -3
- package/dist/syncer/file-patterns.js +2 -3
- package/dist/syncer/file-tracking.js +2 -3
- package/dist/syncer/filesystem-dependencies.js +1 -2
- package/dist/syncer/index.js +8 -2
- package/dist/syncer/module-loader.js +8 -6
- package/dist/syncer/syncer-actions.js +8 -7
- package/dist/syncer/syncer.js +13 -8
- package/dist/syncer/watcher.js +2 -3
- package/dist/tasks/decorator.js +1 -2
- package/dist/tasks/step-wrapper.js +2 -3
- package/dist/tasks/workflow-manager.js +2 -3
- package/dist/template/entity-converter.js +17 -16
- package/dist/template/helpers.js +2 -3
- package/dist/template/implementations/entity.template.js +2 -3
- package/dist/template/implementations/entry-server.template.js +2 -3
- package/dist/template/implementations/generated.template.js +2 -3
- package/dist/template/implementations/generated_http.template.js +6 -6
- package/dist/template/implementations/generated_sso.template.js +2 -3
- package/dist/template/implementations/http_validators.template.js +2 -3
- package/dist/template/implementations/init_types.template.js +2 -3
- package/dist/template/implementations/model.template.js +4 -4
- package/dist/template/implementations/model_test.template.js +2 -3
- package/dist/template/implementations/queries.template.js +2 -3
- package/dist/template/implementations/sd.template.js +2 -3
- package/dist/template/implementations/services.template.js +2 -3
- package/dist/template/implementations/view_form.template.js +12 -9
- package/dist/template/implementations/view_id_all_select.template.js +2 -3
- package/dist/template/implementations/view_list.template.d.ts.map +1 -1
- package/dist/template/implementations/view_list.template.js +19 -17
- package/dist/template/implementations/view_search_input.template.js +2 -3
- package/dist/template/index.js +9 -3
- package/dist/template/template-manager.js +2 -3
- package/dist/template/template-types.js +1 -2
- package/dist/template/template.js +2 -3
- package/dist/template/zod-converter.js +54 -47
- package/dist/testing/_relation-graph.js +2 -3
- package/dist/testing/bootstrap.js +2 -3
- package/dist/testing/data-explorer.js +2 -3
- package/dist/testing/dev-test-routes.js +2 -3
- package/dist/testing/dev-vitest-manager.js +15 -12
- package/dist/testing/faker-mappings.js +1 -2
- package/dist/testing/filesystem.js +2 -3
- package/dist/testing/fixture-generator.js +2 -3
- package/dist/testing/fixture-loader.js +1 -2
- package/dist/testing/fixture-manager.js +12 -9
- package/dist/testing/global-setup.js +5 -5
- package/dist/testing/index.js +6 -3
- package/dist/testing/naite-vitest-reporter.js +1 -2
- package/dist/testing/parallel-db-manager.js +2 -3
- package/dist/testing/vitest-helpers.js +2 -3
- package/dist/tooling/__tests__/helpers/sonamu-test-root.js +2 -3
- package/dist/tooling/cdd-service.js +1 -2
- package/dist/tooling/cli-tooling.js +1 -2
- package/dist/tooling/fixture-service.js +1 -2
- package/dist/tooling/index.js +1 -2
- package/dist/tooling/test-run-client.js +2 -3
- package/dist/tsdown.api.config.js +1 -2
- package/dist/types/types.js +2 -3
- package/dist/ui/ai-api.d.ts.map +1 -1
- package/dist/ui/ai-api.js +4 -5
- package/dist/ui/ai-client.d.ts +2 -2
- package/dist/ui/ai-client.d.ts.map +1 -1
- package/dist/ui/ai-client.js +9 -8
- package/dist/ui/api.d.ts.map +1 -1
- package/dist/ui/api.js +11 -8
- package/dist/ui/async-route.js +1 -2
- package/dist/ui/cdd-service.js +22 -21
- package/dist/ui/migrations-api.js +6 -5
- package/dist/ui-web/assets/index-QDMyy31K.js +180 -0
- package/dist/ui-web/assets/index-dV7akMFB.css +1 -0
- package/dist/ui-web/index.html +2 -2
- package/dist/utils/async-utils.js +1 -2
- package/dist/utils/class-name.js +1 -2
- package/dist/utils/console-util.js +1 -2
- package/dist/utils/controller.js +2 -3
- package/dist/utils/esm-utils.js +1 -2
- package/dist/utils/fs-utils.js +2 -3
- package/dist/utils/lodash-able.js +1 -2
- package/dist/utils/model.js +1 -2
- package/dist/utils/object-utils.js +2 -3
- package/dist/utils/path-utils.js +2 -3
- package/dist/utils/process-utils.js +2 -3
- package/dist/utils/runtime-value.js +1 -2
- package/dist/utils/sql-parser.js +2 -3
- package/dist/utils/type-utils.js +8 -8
- package/dist/utils/utils.js +2 -3
- package/dist/utils/zod-error.js +2 -3
- package/dist/vector/chunking.js +1 -2
- package/dist/vector/config.js +1 -2
- package/dist/vector/embedding.js +4 -4
- package/package.json +63 -63
- package/src/ai/agents/agent.ts +1 -1
- package/src/api/__tests__/sonamu.plugins.test.ts +11 -1
- package/src/api/__tests__/sonamu.websocket-routes.test.ts +234 -0
- package/src/api/__tests__/sonamu.websocket.test.ts +241 -24
- package/src/api/config.ts +1 -1
- package/src/api/context.ts +2 -8
- package/src/api/sonamu.ts +46 -28
- package/src/auth/audit-log/plugin.ts +2 -0
- package/src/compress/types.ts +1 -1
- package/src/exceptions/error-handler.ts +3 -2
- package/src/index.ts +1 -0
- package/src/stream/__tests__/ws-contracts.test.ts +483 -265
- package/src/stream/__tests__/ws-multinode.test.ts +326 -0
- package/src/stream/__tests__/ws-registry-async.test.ts +855 -0
- package/src/stream/__tests__/ws-test-helpers.ts +360 -0
- package/src/stream/__tests__/ws.test.ts +342 -145
- package/src/stream/index.ts +1 -0
- package/src/stream/ws-audience-resolver.ts +21 -19
- package/src/stream/ws-cluster-bus.ts +12 -4
- package/src/stream/ws-core.ts +14 -0
- package/src/stream/ws-delivery.ts +321 -97
- package/src/stream/ws-frame.ts +39 -0
- package/src/stream/ws-local-connection-store.ts +10 -9
- package/src/stream/ws-presence-index.ts +273 -0
- package/src/stream/ws-presence-store.ts +64 -284
- package/src/stream/ws-registry.ts +272 -85
- package/src/stream/ws-session-id.ts +39 -0
- package/src/stream/ws.ts +91 -50
- package/src/template/implementations/model.template.ts +3 -3
- package/src/template/implementations/view_list.template.ts +12 -13
- package/src/ui/ai-api.ts +4 -2
- package/src/ui/ai-client.ts +2 -2
- package/src/ui/api.ts +58 -62
- package/dist/ui-web/assets/index-BMdIyKXS.css +0 -1
- package/dist/ui-web/assets/index-LpE8u19O.js +0 -178
|
@@ -1,46 +1,74 @@
|
|
|
1
|
+
import { type z } from "zod";
|
|
1
2
|
import { type WebSocketAudience as WebSocketAudienceSpec } from "./ws-audience";
|
|
2
|
-
import { WebSocketAudienceResolver } from "./ws-audience-resolver";
|
|
3
3
|
import { type WebSocketClusterBus } from "./ws-cluster-bus";
|
|
4
|
-
import { type ManagedWebSocketConnection, type WebSocketRegistryStats, type WebSocketRoomId, type WebSocketUserId } from "./ws-core";
|
|
5
|
-
import {
|
|
4
|
+
import { type ManagedWebSocketConnection, type WebSocketFrameConnection, type WebSocketRegistryStats, type WebSocketRoomId, type WebSocketUserId } from "./ws-core";
|
|
5
|
+
import { type WebSocketRouteDefinition } from "./ws-delivery";
|
|
6
6
|
import { WebSocketLocalConnectionStore } from "./ws-local-connection-store";
|
|
7
7
|
import { type WebSocketPresenceStore, type WebSocketSessionPresence } from "./ws-presence-store";
|
|
8
8
|
import { type WebSocketTelemetryController } from "./ws-telemetry";
|
|
9
9
|
export type { ManagedWebSocketConnection, WebSocketRegistryStats, WebSocketRoomId, WebSocketUserId, };
|
|
10
10
|
export type WebSocketConnectionMeta = WebSocketSessionPresence;
|
|
11
|
+
export type WebSocketRoomMemberCount = {
|
|
12
|
+
count: number;
|
|
13
|
+
partial: boolean;
|
|
14
|
+
};
|
|
11
15
|
export type WebSocketRegistryOptions = {
|
|
12
16
|
nodeId: string;
|
|
13
17
|
presenceStore?: WebSocketPresenceStore;
|
|
14
18
|
clusterBus?: WebSocketClusterBus;
|
|
15
19
|
telemetryController?: WebSocketTelemetryController;
|
|
20
|
+
drainTimeoutMs?: number;
|
|
16
21
|
};
|
|
22
|
+
/**
|
|
23
|
+
* 노드 로컬 presence를 메모리에 소유하고, 설정된 store에는 세션별 순서대로 replica를 반영한다.
|
|
24
|
+
* mutation과 publish는 호출 시점에 메모리를 동기로 갱신하고, store 실패는 telemetry로만 기록하며 reject하지 않는다.
|
|
25
|
+
*/
|
|
17
26
|
export declare class WebSocketRegistry {
|
|
18
27
|
readonly nodeId: string;
|
|
19
28
|
readonly localConnections: WebSocketLocalConnectionStore;
|
|
20
29
|
readonly presenceStore: WebSocketPresenceStore;
|
|
21
30
|
readonly clusterBus: WebSocketClusterBus;
|
|
22
|
-
readonly audienceResolver: WebSocketAudienceResolver;
|
|
23
|
-
readonly deliveryEngine: WebSocketDeliveryEngine;
|
|
24
31
|
readonly telemetryController: WebSocketTelemetryController;
|
|
32
|
+
private readonly memory;
|
|
33
|
+
private readonly deliveryEngine;
|
|
34
|
+
private readonly drainTimeoutMs;
|
|
35
|
+
private readonly mutationQueues;
|
|
25
36
|
constructor(options: WebSocketRegistryOptions);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
37
|
+
registerRoute(routeKey: string, outEvents: z.ZodObject): void;
|
|
38
|
+
replaceRoutes(routes: WebSocketRouteDefinition[]): void;
|
|
39
|
+
/**
|
|
40
|
+
* 연결을 메모리에 즉시 등록하고 store.register가 끝나면 resolve한다.
|
|
41
|
+
* store가 실패해도 메모리 전용 등록으로 resolve한다.
|
|
42
|
+
*/
|
|
43
|
+
register(connection: WebSocketFrameConnection, active?: boolean): Promise<WebSocketConnectionMeta>;
|
|
44
|
+
activate(connectionId: string): Promise<void>;
|
|
45
|
+
unregister(connectionId: string): Promise<void>;
|
|
29
46
|
touch(connectionId: string): void;
|
|
30
|
-
setUserId(connectionId: string, userId: WebSocketUserId): void
|
|
31
|
-
clearUserId(connectionId: string): void
|
|
32
|
-
join(connectionId: string, roomId: WebSocketRoomId): void
|
|
33
|
-
leave(connectionId: string, roomId: WebSocketRoomId): void
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
publishToAudience<Data>(audience: WebSocketAudienceSpec, event: string, data: Data): void;
|
|
47
|
+
setUserId(connectionId: string, userId: WebSocketUserId): Promise<void>;
|
|
48
|
+
clearUserId(connectionId: string): Promise<void>;
|
|
49
|
+
join(connectionId: string, roomId: WebSocketRoomId): Promise<void>;
|
|
50
|
+
leave(connectionId: string, roomId: WebSocketRoomId): Promise<void>;
|
|
51
|
+
broadcast<Data>(event: string, data: Data, namespace?: string): Promise<void>;
|
|
52
|
+
publishToRoom<Data>(roomId: WebSocketRoomId, event: string, data: Data, namespace?: string): Promise<void>;
|
|
53
|
+
publishToUser<Data>(userId: WebSocketUserId, event: string, data: Data, namespace?: string): Promise<void>;
|
|
54
|
+
publishToAudience<Data>(audience: WebSocketAudienceSpec, event: string, data: Data): Promise<void>;
|
|
39
55
|
getConnection(connectionId: string): WebSocketConnectionMeta | undefined;
|
|
40
56
|
getConnectionCount(namespace?: string): number;
|
|
41
57
|
getRoomMembers(roomId: WebSocketRoomId, namespace?: string): WebSocketConnectionMeta[];
|
|
42
58
|
getStats(): WebSocketRegistryStats;
|
|
59
|
+
/**
|
|
60
|
+
* 클러스터 전체의 활성 방 인원수. store가 실패하면 노드 로컬 수에 partial: true를 붙여 반환하며 reject하지 않는다.
|
|
61
|
+
*/
|
|
62
|
+
getRoomMemberCount(roomId: WebSocketRoomId, namespace?: string): Promise<WebSocketRoomMemberCount>;
|
|
43
63
|
closeAll(code?: number, reason?: string): void;
|
|
64
|
+
/**
|
|
65
|
+
* 로컬 연결을 닫고, 진행 중인 store mutation과 publish를 drainTimeoutMs까지 기다린 뒤 store와 bus를 종료한다.
|
|
66
|
+
*/
|
|
44
67
|
shutdown(code?: number, reason?: string): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* 세션별 큐 뒤에 store 호출을 이어 붙인다. 실패는 telemetry로만 기록하고, 반환한 promise는 reject하지 않는다.
|
|
70
|
+
*/
|
|
71
|
+
private enqueueStoreMutation;
|
|
72
|
+
private emitMutationSkipped;
|
|
45
73
|
}
|
|
46
74
|
//# sourceMappingURL=ws-registry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-registry.d.ts","sourceRoot":"","sources":["../../src/stream/ws-registry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ws-registry.d.ts","sourceRoot":"","sources":["../../src/stream/ws-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
import { __esmMin } from "../_virtual/_rolldown/runtime.js";
|
|
2
2
|
import { init_runtime_value, isFunctionValue } from "../utils/runtime-value.js";
|
|
3
|
+
import { init_runtime_type, runtimeTypeOf } from "../runtime-type.js";
|
|
3
4
|
import { WebSocketAudience, init_ws_audience } from "./ws-audience.js";
|
|
4
5
|
import { WebSocketAudienceResolver, init_ws_audience_resolver } from "./ws-audience-resolver.js";
|
|
5
6
|
import { NoopWebSocketClusterBus, init_ws_cluster_bus } from "./ws-cluster-bus.js";
|
|
6
7
|
import { NoopWebSocketTelemetryController, init_ws_telemetry } from "./ws-telemetry.js";
|
|
7
8
|
import { WebSocketDeliveryEngine, init_ws_delivery } from "./ws-delivery.js";
|
|
8
9
|
import { WebSocketLocalConnectionStore, init_ws_local_connection_store } from "./ws-local-connection-store.js";
|
|
10
|
+
import { WebSocketPresenceIndex, init_ws_presence_index } from "./ws-presence-index.js";
|
|
9
11
|
import { InMemoryWebSocketPresenceStore, init_ws_presence_store } from "./ws-presence-store.js";
|
|
10
|
-
|
|
12
|
+
// src/stream/ws-registry.ts
|
|
13
|
+
function callStore(call) {
|
|
14
|
+
return Promise.resolve().then(call);
|
|
15
|
+
}
|
|
16
|
+
function assertMatchingNodeId(source, sourceNodeId, nodeId) {
|
|
17
|
+
if (sourceNodeId !== void 0 && sourceNodeId !== nodeId) throw new Error(`WebSocket ${source}.nodeId (${sourceNodeId}) must match the runtime nodeId (${nodeId}).`);
|
|
18
|
+
}
|
|
19
|
+
function describeError(cause) {
|
|
20
|
+
return cause instanceof Error ? cause.name : runtimeTypeOf(cause);
|
|
21
|
+
}
|
|
11
22
|
function getConnectionTelemetryContext(connection) {
|
|
12
23
|
if (!connection || !isTelemetryContextProvider(connection)) return {};
|
|
13
24
|
return connection.getTelemetryContext();
|
|
@@ -18,42 +29,50 @@ function formatUserId(userId) {
|
|
|
18
29
|
function isTelemetryContextProvider(connection) {
|
|
19
30
|
return "getTelemetryContext" in connection && isFunctionValue(connection.getTelemetryContext);
|
|
20
31
|
}
|
|
21
|
-
var WebSocketRegistry;
|
|
32
|
+
var DEFAULT_DRAIN_TIMEOUT_MS, WebSocketRegistry;
|
|
22
33
|
var init_ws_registry = __esmMin((() => {
|
|
34
|
+
init_runtime_type();
|
|
23
35
|
init_runtime_value();
|
|
24
36
|
init_ws_audience();
|
|
25
37
|
init_ws_audience_resolver();
|
|
26
38
|
init_ws_cluster_bus();
|
|
27
39
|
init_ws_delivery();
|
|
28
40
|
init_ws_local_connection_store();
|
|
41
|
+
init_ws_presence_index();
|
|
29
42
|
init_ws_presence_store();
|
|
30
43
|
init_ws_telemetry();
|
|
44
|
+
DEFAULT_DRAIN_TIMEOUT_MS = 5e3;
|
|
31
45
|
WebSocketRegistry = class {
|
|
32
46
|
nodeId;
|
|
33
47
|
localConnections = new WebSocketLocalConnectionStore();
|
|
34
48
|
presenceStore;
|
|
35
49
|
clusterBus;
|
|
36
|
-
audienceResolver;
|
|
37
|
-
deliveryEngine;
|
|
38
50
|
telemetryController;
|
|
51
|
+
memory = new WebSocketPresenceIndex();
|
|
52
|
+
deliveryEngine;
|
|
53
|
+
drainTimeoutMs;
|
|
54
|
+
mutationQueues = /* @__PURE__ */ new Map();
|
|
39
55
|
constructor(options) {
|
|
40
56
|
this.nodeId = options.nodeId;
|
|
41
57
|
this.presenceStore = options.presenceStore ?? new InMemoryWebSocketPresenceStore();
|
|
42
58
|
this.clusterBus = options.clusterBus ?? new NoopWebSocketClusterBus();
|
|
59
|
+
this.drainTimeoutMs = options.drainTimeoutMs ?? DEFAULT_DRAIN_TIMEOUT_MS;
|
|
60
|
+
assertMatchingNodeId("presenceStore", this.presenceStore.nodeId, this.nodeId);
|
|
61
|
+
assertMatchingNodeId("clusterBus", this.clusterBus.nodeId, this.nodeId);
|
|
43
62
|
this.telemetryController = options.telemetryController ?? new NoopWebSocketTelemetryController();
|
|
44
|
-
this.audienceResolver = new WebSocketAudienceResolver({
|
|
45
|
-
nodeId: this.nodeId,
|
|
46
|
-
presenceStore: this.presenceStore
|
|
47
|
-
});
|
|
48
63
|
this.deliveryEngine = new WebSocketDeliveryEngine({
|
|
49
64
|
nodeId: this.nodeId,
|
|
50
65
|
localConnections: this.localConnections,
|
|
51
|
-
|
|
66
|
+
resolveLocalSessionIds: (audience) => this.memory.queryAudience(audience).map((session) => session.sessionId),
|
|
67
|
+
audienceResolver: new WebSocketAudienceResolver({
|
|
68
|
+
nodeId: this.nodeId,
|
|
69
|
+
presenceStore: this.presenceStore
|
|
70
|
+
}),
|
|
52
71
|
clusterBus: this.clusterBus,
|
|
53
72
|
telemetryController: this.telemetryController
|
|
54
73
|
});
|
|
55
74
|
this.telemetryController.registerMetricSource({ collect: (_now) => {
|
|
56
|
-
const stats = this.
|
|
75
|
+
const stats = this.memory.getStats();
|
|
57
76
|
const localSnapshot = this.localConnections.getTelemetrySnapshot();
|
|
58
77
|
return {
|
|
59
78
|
activeConnections: stats.totalConnections,
|
|
@@ -65,14 +84,26 @@ var init_ws_registry = __esmMin((() => {
|
|
|
65
84
|
};
|
|
66
85
|
} });
|
|
67
86
|
}
|
|
68
|
-
|
|
69
|
-
this.
|
|
70
|
-
|
|
87
|
+
registerRoute(routeKey, outEvents) {
|
|
88
|
+
this.deliveryEngine.registerRoute(routeKey, outEvents);
|
|
89
|
+
}
|
|
90
|
+
replaceRoutes(routes) {
|
|
91
|
+
this.deliveryEngine.replaceRoutes(routes);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 연결을 메모리에 즉시 등록하고 store.register가 끝나면 resolve한다.
|
|
95
|
+
* store가 실패해도 메모리 전용 등록으로 resolve한다.
|
|
96
|
+
*/
|
|
97
|
+
async register(connection, active = true) {
|
|
98
|
+
const registration = {
|
|
71
99
|
sessionId: connection.id,
|
|
72
100
|
nodeId: this.nodeId,
|
|
73
101
|
namespace: connection.namespace,
|
|
74
|
-
active
|
|
75
|
-
|
|
102
|
+
active,
|
|
103
|
+
connectedAt: /* @__PURE__ */ new Date()
|
|
104
|
+
};
|
|
105
|
+
this.localConnections.register(connection);
|
|
106
|
+
this.memory.register(registration);
|
|
76
107
|
this.telemetryController.emit({
|
|
77
108
|
name: "ws.connection.registered",
|
|
78
109
|
level: "info",
|
|
@@ -92,14 +123,19 @@ var init_ws_registry = __esmMin((() => {
|
|
|
92
123
|
},
|
|
93
124
|
userId: connection.userId
|
|
94
125
|
});
|
|
95
|
-
|
|
126
|
+
await this.enqueueStoreMutation(connection.id, "register", () => this.presenceStore.register(registration));
|
|
127
|
+
return this.memory.getConnection(connection.id) ?? {
|
|
128
|
+
...registration,
|
|
129
|
+
rooms: /* @__PURE__ */ new Set(),
|
|
130
|
+
lastSeenAt: registration.connectedAt
|
|
131
|
+
};
|
|
96
132
|
}
|
|
97
133
|
activate(connectionId) {
|
|
98
|
-
if (!this.
|
|
134
|
+
if (!this.memory.has(connectionId)) {
|
|
99
135
|
this.emitMutationSkipped(connectionId, { operation: "activate" });
|
|
100
|
-
return;
|
|
136
|
+
return Promise.resolve();
|
|
101
137
|
}
|
|
102
|
-
this.
|
|
138
|
+
this.memory.activate(connectionId);
|
|
103
139
|
const connection = this.localConnections.getConnection(connectionId);
|
|
104
140
|
this.telemetryController.emit({
|
|
105
141
|
name: "ws.connection.activated",
|
|
@@ -108,12 +144,13 @@ var init_ws_registry = __esmMin((() => {
|
|
|
108
144
|
userId: connection?.userId,
|
|
109
145
|
...getConnectionTelemetryContext(connection)
|
|
110
146
|
});
|
|
147
|
+
return this.enqueueStoreMutation(connectionId, "activate", () => this.presenceStore.activate(connectionId));
|
|
111
148
|
}
|
|
112
149
|
unregister(connectionId) {
|
|
113
150
|
const connection = this.localConnections.getConnection(connectionId);
|
|
114
151
|
const telemetryContext = getConnectionTelemetryContext(connection);
|
|
115
|
-
const
|
|
116
|
-
const
|
|
152
|
+
const meta = this.memory.unregister(connectionId);
|
|
153
|
+
const userId = connection?.userId ?? formatUserId(meta?.userId);
|
|
117
154
|
this.localConnections.unregister(connectionId);
|
|
118
155
|
this.telemetryController.emit({
|
|
119
156
|
name: "ws.connection.unregistered",
|
|
@@ -123,7 +160,8 @@ var init_ws_registry = __esmMin((() => {
|
|
|
123
160
|
userId,
|
|
124
161
|
...telemetryContext
|
|
125
162
|
});
|
|
126
|
-
if (meta)
|
|
163
|
+
if (!meta) return Promise.resolve();
|
|
164
|
+
this.telemetryController.recordMetric({
|
|
127
165
|
name: "sonamu.ws.connections",
|
|
128
166
|
kind: "counter",
|
|
129
167
|
value: 1,
|
|
@@ -134,38 +172,40 @@ var init_ws_registry = __esmMin((() => {
|
|
|
134
172
|
},
|
|
135
173
|
userId
|
|
136
174
|
});
|
|
175
|
+
return this.enqueueStoreMutation(connectionId, "unregister", () => this.presenceStore.unregister(connectionId));
|
|
137
176
|
}
|
|
138
177
|
touch(connectionId) {
|
|
139
|
-
this.
|
|
178
|
+
this.memory.touch(connectionId);
|
|
140
179
|
}
|
|
141
180
|
setUserId(connectionId, userId) {
|
|
142
|
-
|
|
181
|
+
const meta = this.memory.getConnection(connectionId);
|
|
182
|
+
if (!meta) {
|
|
143
183
|
this.emitMutationSkipped(connectionId, {
|
|
144
184
|
operation: "setUserId",
|
|
145
185
|
userId
|
|
146
186
|
});
|
|
147
|
-
return;
|
|
187
|
+
return Promise.resolve();
|
|
148
188
|
}
|
|
149
|
-
this.
|
|
150
|
-
const meta = this.presenceStore.getConnection(connectionId);
|
|
189
|
+
this.memory.setUserId(connectionId, userId);
|
|
151
190
|
this.telemetryController.emit({
|
|
152
191
|
name: "ws.user.bound",
|
|
153
192
|
level: "debug",
|
|
154
193
|
connectionId,
|
|
155
|
-
namespace: meta
|
|
194
|
+
namespace: meta.namespace,
|
|
156
195
|
userId: String(userId),
|
|
157
196
|
detail: { userId },
|
|
158
197
|
...getConnectionTelemetryContext(this.localConnections.getConnection(connectionId))
|
|
159
198
|
});
|
|
199
|
+
return this.enqueueStoreMutation(connectionId, "setUserId", () => this.presenceStore.setUserId(connectionId, userId));
|
|
160
200
|
}
|
|
161
201
|
clearUserId(connectionId) {
|
|
162
|
-
const meta = this.
|
|
202
|
+
const meta = this.memory.getConnection(connectionId);
|
|
163
203
|
if (!meta) {
|
|
164
204
|
this.emitMutationSkipped(connectionId, { operation: "clearUserId" });
|
|
165
|
-
return;
|
|
205
|
+
return Promise.resolve();
|
|
166
206
|
}
|
|
167
207
|
const userId = meta.userId;
|
|
168
|
-
this.
|
|
208
|
+
this.memory.clearUserId(connectionId);
|
|
169
209
|
this.telemetryController.emit({
|
|
170
210
|
name: "ws.user.cleared",
|
|
171
211
|
level: "debug",
|
|
@@ -175,38 +215,40 @@ var init_ws_registry = __esmMin((() => {
|
|
|
175
215
|
detail: userId !== void 0 ? { userId } : void 0,
|
|
176
216
|
...getConnectionTelemetryContext(this.localConnections.getConnection(connectionId))
|
|
177
217
|
});
|
|
218
|
+
return this.enqueueStoreMutation(connectionId, "clearUserId", () => this.presenceStore.clearUserId(connectionId));
|
|
178
219
|
}
|
|
179
220
|
join(connectionId, roomId) {
|
|
180
|
-
|
|
221
|
+
const meta = this.memory.getConnection(connectionId);
|
|
222
|
+
if (!meta) {
|
|
181
223
|
this.emitMutationSkipped(connectionId, {
|
|
182
224
|
operation: "join",
|
|
183
225
|
roomId
|
|
184
226
|
});
|
|
185
|
-
return;
|
|
227
|
+
return Promise.resolve();
|
|
186
228
|
}
|
|
187
|
-
this.
|
|
188
|
-
const meta = this.presenceStore.getConnection(connectionId);
|
|
229
|
+
this.memory.join(connectionId, roomId);
|
|
189
230
|
const connection = this.localConnections.getConnection(connectionId);
|
|
190
231
|
this.telemetryController.emit({
|
|
191
232
|
name: "ws.room.joined",
|
|
192
233
|
level: "debug",
|
|
193
234
|
connectionId,
|
|
194
|
-
namespace: meta
|
|
195
|
-
userId: connection?.userId ?? formatUserId(meta
|
|
235
|
+
namespace: meta.namespace,
|
|
236
|
+
userId: connection?.userId ?? formatUserId(meta.userId),
|
|
196
237
|
detail: { roomId },
|
|
197
238
|
...getConnectionTelemetryContext(connection)
|
|
198
239
|
});
|
|
240
|
+
return this.enqueueStoreMutation(connectionId, "join", () => this.presenceStore.join(connectionId, roomId));
|
|
199
241
|
}
|
|
200
242
|
leave(connectionId, roomId) {
|
|
201
|
-
const meta = this.
|
|
243
|
+
const meta = this.memory.getConnection(connectionId);
|
|
202
244
|
if (!meta) {
|
|
203
245
|
this.emitMutationSkipped(connectionId, {
|
|
204
246
|
operation: "leave",
|
|
205
247
|
roomId
|
|
206
248
|
});
|
|
207
|
-
return;
|
|
249
|
+
return Promise.resolve();
|
|
208
250
|
}
|
|
209
|
-
this.
|
|
251
|
+
this.memory.leave(connectionId, roomId);
|
|
210
252
|
const connection = this.localConnections.getConnection(connectionId);
|
|
211
253
|
this.telemetryController.emit({
|
|
212
254
|
name: "ws.room.left",
|
|
@@ -217,53 +259,119 @@ var init_ws_registry = __esmMin((() => {
|
|
|
217
259
|
detail: { roomId },
|
|
218
260
|
...getConnectionTelemetryContext(connection)
|
|
219
261
|
});
|
|
220
|
-
|
|
221
|
-
emitMutationSkipped(connectionId, detail) {
|
|
222
|
-
this.telemetryController.emit({
|
|
223
|
-
name: "ws.registry.mutation.skipped",
|
|
224
|
-
level: "debug",
|
|
225
|
-
connectionId,
|
|
226
|
-
detail: {
|
|
227
|
-
...detail,
|
|
228
|
-
reason: "connectionMissing"
|
|
229
|
-
}
|
|
230
|
-
});
|
|
262
|
+
return this.enqueueStoreMutation(connectionId, "leave", () => this.presenceStore.leave(connectionId, roomId));
|
|
231
263
|
}
|
|
232
264
|
broadcast(event, data, namespace) {
|
|
233
|
-
this.publishToAudience(WebSocketAudience.all(namespace), event, data);
|
|
265
|
+
return this.publishToAudience(WebSocketAudience.all(namespace), event, data);
|
|
234
266
|
}
|
|
235
267
|
publishToRoom(roomId, event, data, namespace) {
|
|
236
|
-
this.publishToAudience(WebSocketAudience.room(roomId, namespace), event, data);
|
|
268
|
+
return this.publishToAudience(WebSocketAudience.room(roomId, namespace), event, data);
|
|
237
269
|
}
|
|
238
270
|
publishToUser(userId, event, data, namespace) {
|
|
239
|
-
this.publishToAudience(WebSocketAudience.user(userId, namespace), event, data);
|
|
271
|
+
return this.publishToAudience(WebSocketAudience.user(userId, namespace), event, data);
|
|
240
272
|
}
|
|
241
273
|
publishToAudience(audience, event, data) {
|
|
242
|
-
this.deliveryEngine.publishToAudience(audience, event, data);
|
|
274
|
+
return this.deliveryEngine.publishToAudience(audience, event, data);
|
|
243
275
|
}
|
|
244
276
|
getConnection(connectionId) {
|
|
245
|
-
return this.
|
|
277
|
+
return this.memory.getConnection(connectionId);
|
|
246
278
|
}
|
|
247
279
|
getConnectionCount(namespace) {
|
|
248
|
-
return this.
|
|
280
|
+
return this.memory.getConnectionCount(namespace);
|
|
249
281
|
}
|
|
250
282
|
getRoomMembers(roomId, namespace) {
|
|
251
|
-
return this.
|
|
283
|
+
return this.memory.getRoomMembers(roomId, namespace);
|
|
252
284
|
}
|
|
253
285
|
getStats() {
|
|
254
|
-
return this.
|
|
286
|
+
return this.memory.getStats();
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* 클러스터 전체의 활성 방 인원수. store가 실패하면 노드 로컬 수에 partial: true를 붙여 반환하며 reject하지 않는다.
|
|
290
|
+
*/
|
|
291
|
+
async getRoomMemberCount(roomId, namespace) {
|
|
292
|
+
try {
|
|
293
|
+
return {
|
|
294
|
+
count: await callStore(() => this.presenceStore.getRoomMemberCount(roomId, namespace)),
|
|
295
|
+
partial: false
|
|
296
|
+
};
|
|
297
|
+
} catch (cause) {
|
|
298
|
+
this.telemetryController.emit({
|
|
299
|
+
name: "ws.registry.read.failed",
|
|
300
|
+
level: "warn",
|
|
301
|
+
detail: {
|
|
302
|
+
operation: "getRoomMemberCount",
|
|
303
|
+
roomId,
|
|
304
|
+
errorType: describeError(cause)
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
return {
|
|
308
|
+
count: this.memory.getRoomMemberCount(roomId, namespace),
|
|
309
|
+
partial: true
|
|
310
|
+
};
|
|
311
|
+
}
|
|
255
312
|
}
|
|
256
313
|
closeAll(code, reason) {
|
|
257
314
|
this.localConnections.closeAll(code, reason);
|
|
258
315
|
}
|
|
316
|
+
/**
|
|
317
|
+
* 로컬 연결을 닫고, 진행 중인 store mutation과 publish를 drainTimeoutMs까지 기다린 뒤 store와 bus를 종료한다.
|
|
318
|
+
*/
|
|
259
319
|
async shutdown(code, reason) {
|
|
260
320
|
this.closeAll(code, reason);
|
|
261
|
-
|
|
321
|
+
let timer;
|
|
322
|
+
const deadline = new Promise((resolve) => {
|
|
323
|
+
timer = setTimeout(resolve, this.drainTimeoutMs);
|
|
324
|
+
});
|
|
325
|
+
try {
|
|
326
|
+
await Promise.race([Promise.all([...this.mutationQueues.values(), this.deliveryEngine.drainPublishes()]), deadline]);
|
|
327
|
+
} finally {
|
|
328
|
+
clearTimeout(timer);
|
|
329
|
+
}
|
|
330
|
+
try {
|
|
331
|
+
await callStore(() => this.presenceStore.shutdown?.());
|
|
332
|
+
} catch (cause) {
|
|
333
|
+
this.telemetryController.emit({
|
|
334
|
+
name: "ws.registry.shutdown.failed",
|
|
335
|
+
level: "error",
|
|
336
|
+
detail: { errorType: describeError(cause) }
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
await this.deliveryEngine.shutdown(Promise.resolve());
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* 세션별 큐 뒤에 store 호출을 이어 붙인다. 실패는 telemetry로만 기록하고, 반환한 promise는 reject하지 않는다.
|
|
343
|
+
*/
|
|
344
|
+
enqueueStoreMutation(sessionId, operation, call) {
|
|
345
|
+
const next = (this.mutationQueues.get(sessionId) ?? Promise.resolve()).then(call).then(() => void 0, (cause) => {
|
|
346
|
+
this.telemetryController.emit({
|
|
347
|
+
name: "ws.registry.mutation.failed",
|
|
348
|
+
level: "warn",
|
|
349
|
+
connectionId: sessionId,
|
|
350
|
+
detail: {
|
|
351
|
+
operation,
|
|
352
|
+
errorType: describeError(cause)
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
}).then(() => {
|
|
356
|
+
if (this.mutationQueues.get(sessionId) === next) this.mutationQueues.delete(sessionId);
|
|
357
|
+
});
|
|
358
|
+
this.mutationQueues.set(sessionId, next);
|
|
359
|
+
return next;
|
|
360
|
+
}
|
|
361
|
+
emitMutationSkipped(connectionId, detail) {
|
|
362
|
+
this.telemetryController.emit({
|
|
363
|
+
name: "ws.registry.mutation.skipped",
|
|
364
|
+
level: "debug",
|
|
365
|
+
connectionId,
|
|
366
|
+
detail: {
|
|
367
|
+
...detail,
|
|
368
|
+
reason: "connectionMissing"
|
|
369
|
+
}
|
|
370
|
+
});
|
|
262
371
|
}
|
|
263
372
|
};
|
|
264
373
|
}));
|
|
265
|
-
//#endregion
|
|
266
374
|
init_ws_registry();
|
|
267
375
|
export { WebSocketRegistry, init_ws_registry };
|
|
268
376
|
|
|
269
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid3MtcmVnaXN0cnkuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3N0cmVhbS93cy1yZWdpc3RyeS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBpc0Z1bmN0aW9uVmFsdWUgfSBmcm9tIFwiLi4vdXRpbHMvcnVudGltZS12YWx1ZVwiO1xuaW1wb3J0IHsgV2ViU29ja2V0QXVkaWVuY2UsIHR5cGUgV2ViU29ja2V0QXVkaWVuY2UgYXMgV2ViU29ja2V0QXVkaWVuY2VTcGVjIH0gZnJvbSBcIi4vd3MtYXVkaWVuY2VcIjtcbmltcG9ydCB7IFdlYlNvY2tldEF1ZGllbmNlUmVzb2x2ZXIgfSBmcm9tIFwiLi93cy1hdWRpZW5jZS1yZXNvbHZlclwiO1xuaW1wb3J0IHsgTm9vcFdlYlNvY2tldENsdXN0ZXJCdXMsIHR5cGUgV2ViU29ja2V0Q2x1c3RlckJ1cyB9IGZyb20gXCIuL3dzLWNsdXN0ZXItYnVzXCI7XG5pbXBvcnQge1xuICB0eXBlIE1hbmFnZWRXZWJTb2NrZXRDb25uZWN0aW9uLFxuICB0eXBlIFdlYlNvY2tldFJlZ2lzdHJ5U3RhdHMsXG4gIHR5cGUgV2ViU29ja2V0Um9vbUlkLFxuICB0eXBlIFdlYlNvY2tldFVzZXJJZCxcbn0gZnJvbSBcIi4vd3MtY29yZVwiO1xuaW1wb3J0IHsgV2ViU29ja2V0RGVsaXZlcnlFbmdpbmUgfSBmcm9tIFwiLi93cy1kZWxpdmVyeVwiO1xuaW1wb3J0IHsgV2ViU29ja2V0TG9jYWxDb25uZWN0aW9uU3RvcmUgfSBmcm9tIFwiLi93cy1sb2NhbC1jb25uZWN0aW9uLXN0b3JlXCI7XG5pbXBvcnQge1xuICBJbk1lbW9yeVdlYlNvY2tldFByZXNlbmNlU3RvcmUsXG4gIHR5cGUgV2ViU29ja2V0UHJlc2VuY2VTdG9yZSxcbiAgdHlwZSBXZWJTb2NrZXRTZXNzaW9uUHJlc2VuY2UsXG59IGZyb20gXCIuL3dzLXByZXNlbmNlLXN0b3JlXCI7XG5pbXBvcnQge1xuICB0eXBlIFRlbGVtZXRyeUNvbnRleHRQcm92aWRlcixcbiAgTm9vcFdlYlNvY2tldFRlbGVtZXRyeUNvbnRyb2xsZXIsXG4gIHR5cGUgV2ViU29ja2V0VGVsZW1ldHJ5Q29ubmVjdGlvbkNvbnRleHQsXG4gIHR5cGUgV2ViU29ja2V0VGVsZW1ldHJ5Q29udHJvbGxlcixcbn0gZnJvbSBcIi4vd3MtdGVsZW1ldHJ5XCI7XG5cbmV4cG9ydCB0eXBlIHtcbiAgTWFuYWdlZFdlYlNvY2tldENvbm5lY3Rpb24sXG4gIFdlYlNvY2tldFJlZ2lzdHJ5U3RhdHMsXG4gIFdlYlNvY2tldFJvb21JZCxcbiAgV2ViU29ja2V0VXNlcklkLFxufTtcbmV4cG9ydCB0eXBlIFdlYlNvY2tldENvbm5lY3Rpb25NZXRhID0gV2ViU29ja2V0U2Vzc2lvblByZXNlbmNlO1xuXG5leHBvcnQgdHlwZSBXZWJTb2NrZXRSZWdpc3RyeU9wdGlvbnMgPSB7XG4gIC8vIOu2hOyCsCDtmZjqsr3sl5DshJwg64W465OcIOqwhCDrnbzsmrDtjIUg7Iud67OE7J6Q66GcIOyTsOydtOuvgOuhnCDrsJjrk5zsi5wg7Zi47LacIOy4oShXZWJTb2NrZXRSdW50aW1lKeyXkOyEnCDqsrDsoJXtlbQg64SY6ri064ukXG4gIG5vZGVJZDogc3RyaW5nO1xuICBwcmVzZW5jZVN0b3JlPzogV2ViU29ja2V0UHJlc2VuY2VTdG9yZTtcbiAgY2x1c3RlckJ1cz86IFdlYlNvY2tldENsdXN0ZXJCdXM7XG4gIHRlbGVtZXRyeUNvbnRyb2xsZXI/OiBXZWJTb2NrZXRUZWxlbWV0cnlDb250cm9sbGVyO1xufTtcblxuZXhwb3J0IGNsYXNzIFdlYlNvY2tldFJlZ2lzdHJ5IHtcbiAgcmVhZG9ubHkgbm9kZUlkOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGxvY2FsQ29ubmVjdGlvbnMgPSBuZXcgV2ViU29ja2V0TG9jYWxDb25uZWN0aW9uU3RvcmUoKTtcbiAgcmVhZG9ubHkgcHJlc2VuY2VTdG9yZTogV2ViU29ja2V0UHJlc2VuY2VTdG9yZTtcbiAgcmVhZG9ubHkgY2x1c3RlckJ1czogV2ViU29ja2V0Q2x1c3RlckJ1cztcbiAgcmVhZG9ubHkgYXVkaWVuY2VSZXNvbHZlcjogV2ViU29ja2V0QXVkaWVuY2VSZXNvbHZlcjtcbiAgcmVhZG9ubHkgZGVsaXZlcnlFbmdpbmU6IFdlYlNvY2tldERlbGl2ZXJ5RW5naW5lO1xuICByZWFkb25seSB0ZWxlbWV0cnlDb250cm9sbGVyOiBXZWJTb2NrZXRUZWxlbWV0cnlDb250cm9sbGVyO1xuXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnM6IFdlYlNvY2tldFJlZ2lzdHJ5T3B0aW9ucykge1xuICAgIHRoaXMubm9kZUlkID0gb3B0aW9ucy5ub2RlSWQ7XG4gICAgdGhpcy5wcmVzZW5jZVN0b3JlID0gb3B0aW9ucy5wcmVzZW5jZVN0b3JlID8/IG5ldyBJbk1lbW9yeVdlYlNvY2tldFByZXNlbmNlU3RvcmUoKTtcbiAgICB0aGlzLmNsdXN0ZXJCdXMgPSBvcHRpb25zLmNsdXN0ZXJCdXMgPz8gbmV3IE5vb3BXZWJTb2NrZXRDbHVzdGVyQnVzKCk7XG4gICAgdGhpcy50ZWxlbWV0cnlDb250cm9sbGVyID1cbiAgICAgIG9wdGlvbnMudGVsZW1ldHJ5Q29udHJvbGxlciA/PyBuZXcgTm9vcFdlYlNvY2tldFRlbGVtZXRyeUNvbnRyb2xsZXIoKTtcbiAgICB0aGlzLmF1ZGllbmNlUmVzb2x2ZXIgPSBuZXcgV2ViU29ja2V0QXVkaWVuY2VSZXNvbHZlcih7XG4gICAgICBub2RlSWQ6IHRoaXMubm9kZUlkLFxuICAgICAgcHJlc2VuY2VTdG9yZTogdGhpcy5wcmVzZW5jZVN0b3JlLFxuICAgIH0pO1xuICAgIHRoaXMuZGVsaXZlcnlFbmdpbmUgPSBuZXcgV2ViU29ja2V0RGVsaXZlcnlFbmdpbmUoe1xuICAgICAgbm9kZUlkOiB0aGlzLm5vZGVJZCxcbiAgICAgIGxvY2FsQ29ubmVjdGlvbnM6IHRoaXMubG9jYWxDb25uZWN0aW9ucyxcbiAgICAgIGF1ZGllbmNlUmVzb2x2ZXI6IHRoaXMuYXVkaWVuY2VSZXNvbHZlcixcbiAgICAgIGNsdXN0ZXJCdXM6IHRoaXMuY2x1c3RlckJ1cyxcbiAgICAgIHRlbGVtZXRyeUNvbnRyb2xsZXI6IHRoaXMudGVsZW1ldHJ5Q29udHJvbGxlcixcbiAgICB9KTtcblxuICAgIHRoaXMudGVsZW1ldHJ5Q29udHJvbGxlci5yZWdpc3Rlck1ldHJpY1NvdXJjZSh7XG4gICAgICBjb2xsZWN0OiAoX25vdykgPT4ge1xuICAgICAgICBjb25zdCBzdGF0cyA9IHRoaXMucHJlc2VuY2VTdG9yZS5nZXRTdGF0cygpO1xuICAgICAgICBjb25zdCBsb2NhbFNuYXBzaG90ID0gdGhpcy5sb2NhbENvbm5lY3Rpb25zLmdldFRlbGVtZXRyeVNuYXBzaG90KCk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgYWN0aXZlQ29ubmVjdGlvbnM6IHN0YXRzLnRvdGFsQ29ubmVjdGlvbnMsXG4gICAgICAgICAgYWN0aXZlQ29ubmVjdGlvbnNCeU5hbWVzcGFjZTogc3RhdHMuYnlOYW1lc3BhY2UsXG4gICAgICAgICAgcm9vbUNvdW50OiBzdGF0cy50b3RhbFJvb21zLFxuICAgICAgICAgIHBlbmRpbmdJbmJvdW5kTWVzc2FnZXM6IGxvY2FsU25hcHNob3QucGVuZGluZ0luYm91bmRNZXNzYWdlcyxcbiAgICAgICAgICBwZW5kaW5nT3V0Ym91bmRNZXNzYWdlczogbG9jYWxTbmFwc2hvdC5wZW5kaW5nT3V0Ym91bmRNZXNzYWdlcyxcbiAgICAgICAgICBzb2NrZXRCdWZmZXJlZEJ5dGVzOiBsb2NhbFNuYXBzaG90LnNvY2tldEJ1ZmZlcmVkQnl0ZXMsXG4gICAgICAgIH07XG4gICAgICB9LFxuICAgIH0pO1xuICB9XG5cbiAgcmVnaXN0ZXIoXG4gICAgY29ubmVjdGlvbjogTWFuYWdlZFdlYlNvY2tldENvbm5lY3Rpb24sXG4gICAgYWN0aXZlOiBib29sZWFuID0gdHJ1ZSxcbiAgKTogV2ViU29ja2V0Q29ubmVjdGlvbk1ldGEge1xuICAgIHRoaXMubG9jYWxDb25uZWN0aW9ucy5yZWdpc3Rlcihjb25uZWN0aW9uKTtcbiAgICBjb25zdCBtZXRhID0gdGhpcy5wcmVzZW5jZVN0b3JlLnJlZ2lzdGVyKHtcbiAgICAgIHNlc3Npb25JZDogY29ubmVjdGlvbi5pZCxcbiAgICAgIG5vZGVJZDogdGhpcy5ub2RlSWQsXG4gICAgICBuYW1lc3BhY2U6IGNvbm5lY3Rpb24ubmFtZXNwYWNlLFxuICAgICAgYWN0aXZlLFxuICAgIH0pO1xuICAgIHRoaXMudGVsZW1ldHJ5Q29udHJvbGxlci5lbWl0KHtcbiAgICAgIG5hbWU6IFwid3MuY29ubmVjdGlvbi5yZWdpc3RlcmVkXCIsXG4gICAgICBsZXZlbDogXCJpbmZvXCIsXG4gICAgICBjb25uZWN0aW9uSWQ6IGNvbm5lY3Rpb24uaWQsXG4gICAgICBuYW1lc3BhY2U6IGNvbm5lY3Rpb24ubmFtZXNwYWNlLFxuICAgICAgdXNlcklkOiBjb25uZWN0aW9uLnVzZXJJZCxcbiAgICAgIC4uLmdldENvbm5lY3Rpb25UZWxlbWV0cnlDb250ZXh0KGNvbm5lY3Rpb24pLFxuICAgIH0pO1xuICAgIHRoaXMudGVsZW1ldHJ5Q29udHJvbGxlci5yZWNvcmRNZXRyaWMoe1xuICAgICAgbmFtZTogXCJzb25hbXUud3MuY29ubmVjdGlvbnNcIixcbiAgICAgIGtpbmQ6IFwiY291bnRlclwiLFxuICAgICAgdmFsdWU6IDEsXG4gICAgICB1bml0OiBcIjFcIixcbiAgICAgIHRhZ3M6IHsgb3V0Y29tZTogXCJyZWdpc3RlcmVkXCIsIG5hbWVzcGFjZTogY29ubmVjdGlvbi5uYW1lc3BhY2UgfSxcbiAgICAgIHVzZXJJZDogY29ubmVjdGlvbi51c2VySWQsXG4gICAgfSk7XG4gICAgcmV0dXJuIG1ldGE7XG4gIH1cblxuICBhY3RpdmF0ZShjb25uZWN0aW9uSWQ6IHN0cmluZyk6IHZvaWQge1xuICAgIGlmICghdGhpcy5wcmVzZW5jZVN0b3JlLmdldENvbm5lY3Rpb24oY29ubmVjdGlvbklkKSkge1xuICAgICAgdGhpcy5lbWl0TXV0YXRpb25Ta2lwcGVkKGNvbm5lY3Rpb25JZCwgeyBvcGVyYXRpb246IFwiYWN0aXZhdGVcIiB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLnByZXNlbmNlU3RvcmUuYWN0aXZhdGUoY29ubmVjdGlvbklkKTtcbiAgICBjb25zdCBjb25uZWN0aW9uID0gdGhpcy5sb2NhbENvbm5lY3Rpb25zLmdldENvbm5lY3Rpb24oY29ubmVjdGlvbklkKTtcbiAgICB0aGlzLnRlbGVtZXRyeUNvbnRyb2xsZXIuZW1pdCh7XG4gICAgICBuYW1lOiBcIndzLmNvbm5lY3Rpb24uYWN0aXZhdGVkXCIsXG4gICAgICBsZXZlbDogXCJpbmZvXCIsXG4gICAgICBjb25uZWN0aW9uSWQsXG4gICAgICB1c2VySWQ6IGNvbm5lY3Rpb24/LnVzZXJJZCxcbiAgICAgIC4uLmdldENvbm5lY3Rpb25UZWxlbWV0cnlDb250ZXh0KGNvbm5lY3Rpb24pLFxuICAgIH0pO1xuICB9XG5cbiAgdW5yZWdpc3Rlcihjb25uZWN0aW9uSWQ6IHN0cmluZyk6IHZvaWQge1xuICAgIGNvbnN0IGNvbm5lY3Rpb24gPSB0aGlzLmxvY2FsQ29ubmVjdGlvbnMuZ2V0Q29ubmVjdGlvbihjb25uZWN0aW9uSWQpO1xuICAgIGNvbnN0IHRlbGVtZXRyeUNvbnRleHQgPSBnZXRDb25uZWN0aW9uVGVsZW1ldHJ5Q29udGV4dChjb25uZWN0aW9uKTtcbiAgICBjb25zdCB1c2VySWQgPVxuICAgICAgY29ubmVjdGlvbj8udXNlcklkID8/IGZvcm1hdFVzZXJJZCh0aGlzLnByZXNlbmNlU3RvcmUuZ2V0Q29ubmVjdGlvbihjb25uZWN0aW9uSWQpPy51c2VySWQpO1xuICAgIGNvbnN0IG1ldGEgPSB0aGlzLnByZXNlbmNlU3RvcmUudW5yZWdpc3Rlcihjb25uZWN0aW9uSWQpO1xuICAgIHRoaXMubG9jYWxDb25uZWN0aW9ucy51bnJlZ2lzdGVyKGNvbm5lY3Rpb25JZCk7XG4gICAgdGhpcy50ZWxlbWV0cnlDb250cm9sbGVyLmVtaXQoe1xuICAgICAgbmFtZTogXCJ3cy5jb25uZWN0aW9uLnVucmVnaXN0ZXJlZFwiLFxuICAgICAgbGV2ZWw6IFwiZGVidWdcIixcbiAgICAgIGNvbm5lY3Rpb25JZCxcbiAgICAgIG5hbWVzcGFjZTogbWV0YT8ubmFtZXNwYWNlLFxuICAgICAgdXNlcklkLFxuICAgICAgLi4udGVsZW1ldHJ5Q29udGV4dCxcbiAgICB9KTtcbiAgICBpZiAobWV0YSkge1xuICAgICAgdGhpcy50ZWxlbWV0cnlDb250cm9sbGVyLnJlY29yZE1ldHJpYyh7XG4gICAgICAgIG5hbWU6IFwic29uYW11LndzLmNvbm5lY3Rpb25zXCIsXG4gICAgICAgIGtpbmQ6IFwiY291bnRlclwiLFxuICAgICAgICB2YWx1ZTogMSxcbiAgICAgICAgdW5pdDogXCIxXCIsXG4gICAgICAgIHRhZ3M6IHsgb3V0Y29tZTogXCJ1bnJlZ2lzdGVyZWRcIiwgbmFtZXNwYWNlOiBtZXRhLm5hbWVzcGFjZSB9LFxuICAgICAgICB1c2VySWQsXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICB0b3VjaChjb25uZWN0aW9uSWQ6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMucHJlc2VuY2VTdG9yZS50b3VjaChjb25uZWN0aW9uSWQpO1xuICB9XG5cbiAgc2V0VXNlcklkKGNvbm5lY3Rpb25JZDogc3RyaW5nLCB1c2VySWQ6IFdlYlNvY2tldFVzZXJJZCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5wcmVzZW5jZVN0b3JlLmdldENvbm5lY3Rpb24oY29ubmVjdGlvbklkKSkge1xuICAgICAgdGhpcy5lbWl0TXV0YXRpb25Ta2lwcGVkKGNvbm5lY3Rpb25JZCwgeyBvcGVyYXRpb246IFwic2V0VXNlcklkXCIsIHVzZXJJZCB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLnByZXNlbmNlU3RvcmUuc2V0VXNlcklkKGNvbm5lY3Rpb25JZCwgdXNlcklkKTtcbiAgICBjb25zdCBtZXRhID0gdGhpcy5wcmVzZW5jZVN0b3JlLmdldENvbm5lY3Rpb24oY29ubmVjdGlvbklkKTtcbiAgICB0aGlzLnRlbGVtZXRyeUNvbnRyb2xsZXIuZW1pdCh7XG4gICAgICBuYW1lOiBcIndzLnVzZXIuYm91bmRcIixcbiAgICAgIGxldmVsOiBcImRlYnVnXCIsXG4gICAgICBjb25uZWN0aW9uSWQsXG4gICAgICBuYW1lc3BhY2U6IG1ldGE/Lm5hbWVzcGFjZSxcbiAgICAgIHVzZXJJZDogU3RyaW5nKHVzZXJJZCksXG4gICAgICBkZXRhaWw6IHsgdXNlcklkIH0sXG4gICAgICAuLi5nZXRDb25uZWN0aW9uVGVsZW1ldHJ5Q29udGV4dCh0aGlzLmxvY2FsQ29ubmVjdGlvbnMuZ2V0Q29ubmVjdGlvbihjb25uZWN0aW9uSWQpKSxcbiAgICB9KTtcbiAgfVxuXG4gIGNsZWFyVXNlcklkKGNvbm5lY3Rpb25JZDogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgbWV0YSA9IHRoaXMucHJlc2VuY2VTdG9yZS5nZXRDb25uZWN0aW9uKGNvbm5lY3Rpb25JZCk7XG4gICAgaWYgKCFtZXRhKSB7XG4gICAgICB0aGlzLmVtaXRNdXRhdGlvblNraXBwZWQoY29ubmVjdGlvbklkLCB7IG9wZXJhdGlvbjogXCJjbGVhclVzZXJJZFwiIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHVzZXJJZCA9IG1ldGEudXNlcklkO1xuICAgIHRoaXMucHJlc2VuY2VTdG9yZS5jbGVhclVzZXJJZChjb25uZWN0aW9uSWQpO1xuICAgIHRoaXMudGVsZW1ldHJ5Q29udHJvbGxlci5lbWl0KHtcbiAgICAgIG5hbWU6IFwid3MudXNlci5jbGVhcmVkXCIsXG4gICAgICBsZXZlbDogXCJkZWJ1Z1wiLFxuICAgICAgY29ubmVjdGlvbklkLFxuICAgICAgbmFtZXNwYWNlOiBtZXRhLm5hbWVzcGFjZSxcbiAgICAgIHVzZXJJZDogZm9ybWF0VXNlcklkKHVzZXJJZCksXG4gICAgICBkZXRhaWw6IHVzZXJJZCAhPT0gdW5kZWZpbmVkID8geyB1c2VySWQgfSA6IHVuZGVmaW5lZCxcbiAgICAgIC4uLmdldENvbm5lY3Rpb25UZWxlbWV0cnlDb250ZXh0KHRoaXMubG9jYWxDb25uZWN0aW9ucy5nZXRDb25uZWN0aW9uKGNvbm5lY3Rpb25JZCkpLFxuICAgIH0pO1xuICB9XG5cbiAgam9pbihjb25uZWN0aW9uSWQ6IHN0cmluZywgcm9vbUlkOiBXZWJTb2NrZXRSb29tSWQpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMucHJlc2VuY2VTdG9yZS5nZXRDb25uZWN0aW9uKGNvbm5lY3Rpb25JZCkpIHtcbiAgICAgIHRoaXMuZW1pdE11dGF0aW9uU2tpcHBlZChjb25uZWN0aW9uSWQsIHsgb3BlcmF0aW9uOiBcImpvaW5cIiwgcm9vbUlkIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMucHJlc2VuY2VTdG9yZS5qb2luKGNvbm5lY3Rpb25JZCwgcm9vbUlkKTtcbiAgICBjb25zdCBtZXRhID0gdGhpcy5wcmVzZW5jZVN0b3JlLmdldENvbm5lY3Rpb24oY29ubmVjdGlvbklkKTtcbiAgICBjb25zdCBjb25uZWN0aW9uID0gdGhpcy5sb2NhbENvbm5lY3Rpb25zLmdldENvbm5lY3Rpb24oY29ubmVjdGlvbklkKTtcbiAgICB0aGlzLnRlbGVtZXRyeUNvbnRyb2xsZXIuZW1pdCh7XG4gICAgICBuYW1lOiBcIndzLnJvb20uam9pbmVkXCIsXG4gICAgICBsZXZlbDogXCJkZWJ1Z1wiLFxuICAgICAgY29ubmVjdGlvbklkLFxuICAgICAgbmFtZXNwYWNlOiBtZXRhPy5uYW1lc3BhY2UsXG4gICAgICB1c2VySWQ6IGNvbm5lY3Rpb24/LnVzZXJJZCA/PyBmb3JtYXRVc2VySWQobWV0YT8udXNlcklkKSxcbiAgICAgIGRldGFpbDogeyByb29tSWQgfSxcbiAgICAgIC4uLmdldENvbm5lY3Rpb25UZWxlbWV0cnlDb250ZXh0KGNvbm5lY3Rpb24pLFxuICAgIH0pO1xuICB9XG5cbiAgbGVhdmUoY29ubmVjdGlvbklkOiBzdHJpbmcsIHJvb21JZDogV2ViU29ja2V0Um9vbUlkKTogdm9pZCB7XG4gICAgY29uc3QgbWV0YSA9IHRoaXMucHJlc2VuY2VTdG9yZS5nZXRDb25uZWN0aW9uKGNvbm5lY3Rpb25JZCk7XG4gICAgaWYgKCFtZXRhKSB7XG4gICAgICB0aGlzLmVtaXRNdXRhdGlvblNraXBwZWQoY29ubmVjdGlvbklkLCB7IG9wZXJhdGlvbjogXCJsZWF2ZVwiLCByb29tSWQgfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5wcmVzZW5jZVN0b3JlLmxlYXZlKGNvbm5lY3Rpb25JZCwgcm9vbUlkKTtcbiAgICBjb25zdCBjb25uZWN0aW9uID0gdGhpcy5sb2NhbENvbm5lY3Rpb25zLmdldENvbm5lY3Rpb24oY29ubmVjdGlvbklkKTtcbiAgICB0aGlzLnRlbGVtZXRyeUNvbnRyb2xsZXIuZW1pdCh7XG4gICAgICBuYW1lOiBcIndzLnJvb20ubGVmdFwiLFxuICAgICAgbGV2ZWw6IFwiZGVidWdcIixcbiAgICAgIGNvbm5lY3Rpb25JZCxcbiAgICAgIG5hbWVzcGFjZTogbWV0YS5uYW1lc3BhY2UsXG4gICAgICB1c2VySWQ6IGNvbm5lY3Rpb24/LnVzZXJJZCA/PyBmb3JtYXRVc2VySWQobWV0YS51c2VySWQpLFxuICAgICAgZGV0YWlsOiB7IHJvb21JZCB9LFxuICAgICAgLi4uZ2V0Q29ubmVjdGlvblRlbGVtZXRyeUNvbnRleHQoY29ubmVjdGlvbiksXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGVtaXRNdXRhdGlvblNraXBwZWQoXG4gICAgY29ubmVjdGlvbklkOiBzdHJpbmcsXG4gICAgZGV0YWlsOiB7XG4gICAgICBvcGVyYXRpb246IFwiYWN0aXZhdGVcIiB8IFwic2V0VXNlcklkXCIgfCBcImNsZWFyVXNlcklkXCIgfCBcImpvaW5cIiB8IFwibGVhdmVcIjtcbiAgICAgIHJvb21JZD86IFdlYlNvY2tldFJvb21JZDtcbiAgICAgIHVzZXJJZD86IFdlYlNvY2tldFVzZXJJZDtcbiAgICB9LFxuICApOiB2b2lkIHtcbiAgICB0aGlzLnRlbGVtZXRyeUNvbnRyb2xsZXIuZW1pdCh7XG4gICAgICBuYW1lOiBcIndzLnJlZ2lzdHJ5Lm11dGF0aW9uLnNraXBwZWRcIixcbiAgICAgIGxldmVsOiBcImRlYnVnXCIsXG4gICAgICBjb25uZWN0aW9uSWQsXG4gICAgICBkZXRhaWw6IHsgLi4uZGV0YWlsLCByZWFzb246IFwiY29ubmVjdGlvbk1pc3NpbmdcIiB9LFxuICAgIH0pO1xuICB9XG5cbiAgYnJvYWRjYXN0PERhdGE+KGV2ZW50OiBzdHJpbmcsIGRhdGE6IERhdGEsIG5hbWVzcGFjZT86IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMucHVibGlzaFRvQXVkaWVuY2UoV2ViU29ja2V0QXVkaWVuY2UuYWxsKG5hbWVzcGFjZSksIGV2ZW50LCBkYXRhKTtcbiAgfVxuXG4gIHB1Ymxpc2hUb1Jvb208RGF0YT4oXG4gICAgcm9vbUlkOiBXZWJTb2NrZXRSb29tSWQsXG4gICAgZXZlbnQ6IHN0cmluZyxcbiAgICBkYXRhOiBEYXRhLFxuICAgIG5hbWVzcGFjZT86IHN0cmluZyxcbiAgKTogdm9pZCB7XG4gICAgdGhpcy5wdWJsaXNoVG9BdWRpZW5jZShXZWJTb2NrZXRBdWRpZW5jZS5yb29tKHJvb21JZCwgbmFtZXNwYWNlKSwgZXZlbnQsIGRhdGEpO1xuICB9XG5cbiAgcHVibGlzaFRvVXNlcjxEYXRhPihcbiAgICB1c2VySWQ6IFdlYlNvY2tldFVzZXJJZCxcbiAgICBldmVudDogc3RyaW5nLFxuICAgIGRhdGE6IERhdGEsXG4gICAgbmFtZXNwYWNlPzogc3RyaW5nLFxuICApOiB2b2lkIHtcbiAgICB0aGlzLnB1Ymxpc2hUb0F1ZGllbmNlKFdlYlNvY2tldEF1ZGllbmNlLnVzZXIodXNlcklkLCBuYW1lc3BhY2UpLCBldmVudCwgZGF0YSk7XG4gIH1cblxuICBwdWJsaXNoVG9BdWRpZW5jZTxEYXRhPihhdWRpZW5jZTogV2ViU29ja2V0QXVkaWVuY2VTcGVjLCBldmVudDogc3RyaW5nLCBkYXRhOiBEYXRhKTogdm9pZCB7XG4gICAgdGhpcy5kZWxpdmVyeUVuZ2luZS5wdWJsaXNoVG9BdWRpZW5jZShhdWRpZW5jZSwgZXZlbnQsIGRhdGEpO1xuICB9XG5cbiAgZ2V0Q29ubmVjdGlvbihjb25uZWN0aW9uSWQ6IHN0cmluZyk6IFdlYlNvY2tldENvbm5lY3Rpb25NZXRhIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5wcmVzZW5jZVN0b3JlLmdldENvbm5lY3Rpb24oY29ubmVjdGlvbklkKTtcbiAgfVxuXG4gIGdldENvbm5lY3Rpb25Db3VudChuYW1lc3BhY2U/OiBzdHJpbmcpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnByZXNlbmNlU3RvcmUuZ2V0Q29ubmVjdGlvbkNvdW50KG5hbWVzcGFjZSk7XG4gIH1cblxuICBnZXRSb29tTWVtYmVycyhyb29tSWQ6IFdlYlNvY2tldFJvb21JZCwgbmFtZXNwYWNlPzogc3RyaW5nKTogV2ViU29ja2V0Q29ubmVjdGlvbk1ldGFbXSB7XG4gICAgcmV0dXJuIHRoaXMucHJlc2VuY2VTdG9yZS5nZXRSb29tTWVtYmVycyhyb29tSWQsIG5hbWVzcGFjZSk7XG4gIH1cblxuICBnZXRTdGF0cygpOiBXZWJTb2NrZXRSZWdpc3RyeVN0YXRzIHtcbiAgICByZXR1cm4gdGhpcy5wcmVzZW5jZVN0b3JlLmdldFN0YXRzKCk7XG4gIH1cblxuICBjbG9zZUFsbChjb2RlPzogbnVtYmVyLCByZWFzb24/OiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmxvY2FsQ29ubmVjdGlvbnMuY2xvc2VBbGwoY29kZSwgcmVhc29uKTtcbiAgfVxuXG4gIGFzeW5jIHNodXRkb3duKGNvZGU/OiBudW1iZXIsIHJlYXNvbj86IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMuY2xvc2VBbGwoY29kZSwgcmVhc29uKTtcbiAgICBhd2FpdCB0aGlzLmRlbGl2ZXJ5RW5naW5lLnNodXRkb3duKCk7XG4gIH1cbn1cblxuZnVuY3Rpb24gZ2V0Q29ubmVjdGlvblRlbGVtZXRyeUNvbnRleHQoXG4gIGNvbm5lY3Rpb246IE1hbmFnZWRXZWJTb2NrZXRDb25uZWN0aW9uIHwgdW5kZWZpbmVkLFxuKTogV2ViU29ja2V0VGVsZW1ldHJ5Q29ubmVjdGlvbkNvbnRleHQge1xuICBpZiAoIWNvbm5lY3Rpb24gfHwgIWlzVGVsZW1ldHJ5Q29udGV4dFByb3ZpZGVyKGNvbm5lY3Rpb24pKSB7XG4gICAgcmV0dXJuIHt9O1xuICB9XG5cbiAgcmV0dXJuIGNvbm5lY3Rpb24uZ2V0VGVsZW1ldHJ5Q29udGV4dCgpO1xufVxuXG4vLyB0ZWxlbWV0cnkgcmVjb3Jk7J2YIHVzZXJJZOuKlCBzdHJpbmcg7KCV6rec7ZmUIOKAlCBwcmVzZW5jZSBzdG9yZeuKlCBudW1iZXIgfCBzdHJpbmcg6re464yA66GcIOuztOq0gO2VqFxuZnVuY3Rpb24gZm9ybWF0VXNlcklkKHVzZXJJZDogV2ViU29ja2V0VXNlcklkIHwgdW5kZWZpbmVkKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgcmV0dXJuIHVzZXJJZCA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogU3RyaW5nKHVzZXJJZCk7XG59XG5cbmZ1bmN0aW9uIGlzVGVsZW1ldHJ5Q29udGV4dFByb3ZpZGVyKFxuICBjb25uZWN0aW9uOiBNYW5hZ2VkV2ViU29ja2V0Q29ubmVjdGlvbixcbik6IGNvbm5lY3Rpb24gaXMgTWFuYWdlZFdlYlNvY2tldENvbm5lY3Rpb24gJiBUZWxlbWV0cnlDb250ZXh0UHJvdmlkZXIge1xuICByZXR1cm4gXCJnZXRUZWxlbWV0cnlDb250ZXh0XCIgaW4gY29ubmVjdGlvbiAmJiBpc0Z1bmN0aW9uVmFsdWUoY29ubmVjdGlvbi5nZXRUZWxlbWV0cnlDb250ZXh0KTtcbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7OztBQW9UQSxTQUFTLDhCQUNQLFlBQ3FDO0NBQ3JDLElBQUksQ0FBQyxjQUFjLENBQUMsMkJBQTJCLFVBQVUsR0FDdkQsT0FBTyxDQUFDO0NBR1YsT0FBTyxXQUFXLG9CQUFvQjtBQUN4QztBQUdBLFNBQVMsYUFBYSxRQUF5RDtDQUM3RSxPQUFPLFdBQVcsU0FBWSxTQUFZLE9BQU8sTUFBTTtBQUN6RDtBQUVBLFNBQVMsMkJBQ1AsWUFDcUU7Q0FDckUsT0FBTyx5QkFBeUIsY0FBYyxnQkFBZ0IsV0FBVyxtQkFBbUI7QUFDOUY7OztvQkF2VXdEO2tCQUMwQzsyQkFDaEM7cUJBQ2tCO2tCQU83QjtnQ0FDb0I7d0JBSy9DO21CQU1MO0NBa0JWLG9CQUFiLE1BQStCO0VBQzdCO0VBQ0EsbUJBQTRCLElBQUksOEJBQThCO0VBQzlEO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFFQSxZQUFZLFNBQW1DO0dBQzdDLEtBQUssU0FBUyxRQUFRO0dBQ3RCLEtBQUssZ0JBQWdCLFFBQVEsaUJBQWlCLElBQUksK0JBQStCO0dBQ2pGLEtBQUssYUFBYSxRQUFRLGNBQWMsSUFBSSx3QkFBd0I7R0FDcEUsS0FBSyxzQkFDSCxRQUFRLHVCQUF1QixJQUFJLGlDQUFpQztHQUN0RSxLQUFLLG1CQUFtQixJQUFJLDBCQUEwQjtJQUNwRCxRQUFRLEtBQUs7SUFDYixlQUFlLEtBQUs7R0FDdEIsQ0FBQztHQUNELEtBQUssaUJBQWlCLElBQUksd0JBQXdCO0lBQ2hELFFBQVEsS0FBSztJQUNiLGtCQUFrQixLQUFLO0lBQ3ZCLGtCQUFrQixLQUFLO0lBQ3ZCLFlBQVksS0FBSztJQUNqQixxQkFBcUIsS0FBSztHQUM1QixDQUFDO0dBRUQsS0FBSyxvQkFBb0IscUJBQXFCLEVBQzVDLFVBQVUsU0FBUztJQUNqQixNQUFNLFFBQVEsS0FBSyxjQUFjLFNBQVM7SUFDMUMsTUFBTSxnQkFBZ0IsS0FBSyxpQkFBaUIscUJBQXFCO0lBQ2pFLE9BQU87S0FDTCxtQkFBbUIsTUFBTTtLQUN6Qiw4QkFBOEIsTUFBTTtLQUNwQyxXQUFXLE1BQU07S0FDakIsd0JBQXdCLGNBQWM7S0FDdEMseUJBQXlCLGNBQWM7S0FDdkMscUJBQXFCLGNBQWM7SUFDckM7R0FDRixFQUNGLENBQUM7RUFDSDtFQUVBLFNBQ0UsWUFDQSxTQUFrQixNQUNPO0dBQ3pCLEtBQUssaUJBQWlCLFNBQVMsVUFBVTtHQUN6QyxNQUFNLE9BQU8sS0FBSyxjQUFjLFNBQVM7SUFDdkMsV0FBVyxXQUFXO0lBQ3RCLFFBQVEsS0FBSztJQUNiLFdBQVcsV0FBVztJQUN0QjtHQUNGLENBQUM7R0FDRCxLQUFLLG9CQUFvQixLQUFLO0lBQzVCLE1BQU07SUFDTixPQUFPO0lBQ1AsY0FBYyxXQUFXO0lBQ3pCLFdBQVcsV0FBVztJQUN0QixRQUFRLFdBQVc7SUFDbkIsR0FBRyw4QkFBOEIsVUFBVTtHQUM3QyxDQUFDO0dBQ0QsS0FBSyxvQkFBb0IsYUFBYTtJQUNwQyxNQUFNO0lBQ04sTUFBTTtJQUNOLE9BQU87SUFDUCxNQUFNO0lBQ04sTUFBTTtLQUFFLFNBQVM7S0FBYyxXQUFXLFdBQVc7SUFBVTtJQUMvRCxRQUFRLFdBQVc7R0FDckIsQ0FBQztHQUNELE9BQU87RUFDVDtFQUVBLFNBQVMsY0FBNEI7R0FDbkMsSUFBSSxDQUFDLEtBQUssY0FBYyxjQUFjLFlBQVksR0FBRztJQUNuRCxLQUFLLG9CQUFvQixjQUFjLEVBQUUsV0FBVyxXQUFXLENBQUM7SUFDaEU7R0FDRjtHQUVBLEtBQUssY0FBYyxTQUFTLFlBQVk7R0FDeEMsTUFBTSxhQUFhLEtBQUssaUJBQWlCLGNBQWMsWUFBWTtHQUNuRSxLQUFLLG9CQUFvQixLQUFLO0lBQzVCLE1BQU07SUFDTixPQUFPO0lBQ1A7SUFDQSxRQUFRLFlBQVk7SUFDcEIsR0FBRyw4QkFBOEIsVUFBVTtHQUM3QyxDQUFDO0VBQ0g7RUFFQSxXQUFXLGNBQTRCO0dBQ3JDLE1BQU0sYUFBYSxLQUFLLGlCQUFpQixjQUFjLFlBQVk7R0FDbkUsTUFBTSxtQkFBbUIsOEJBQThCLFVBQVU7R0FDakUsTUFBTSxTQUNKLFlBQVksVUFBVSxhQUFhLEtBQUssY0FBYyxjQUFjLFlBQVksQ0FBQyxFQUFFLE1BQU07R0FDM0YsTUFBTSxPQUFPLEtBQUssY0FBYyxXQUFXLFlBQVk7R0FDdkQsS0FBSyxpQkFBaUIsV0FBVyxZQUFZO0dBQzdDLEtBQUssb0JBQW9CLEtBQUs7SUFDNUIsTUFBTTtJQUNOLE9BQU87SUFDUDtJQUNBLFdBQVcsTUFBTTtJQUNqQjtJQUNBLEdBQUc7R0FDTCxDQUFDO0dBQ0QsSUFBSSxNQUNGLEtBQUssb0JBQW9CLGFBQWE7SUFDcEMsTUFBTTtJQUNOLE1BQU07SUFDTixPQUFPO0lBQ1AsTUFBTTtJQUNOLE1BQU07S0FBRSxTQUFTO0tBQWdCLFdBQVcsS0FBSztJQUFVO0lBQzNEO0dBQ0YsQ0FBQztFQUVMO0VBRUEsTUFBTSxjQUE0QjtHQUNoQyxLQUFLLGNBQWMsTUFBTSxZQUFZO0VBQ3ZDO0VBRUEsVUFBVSxjQUFzQixRQUErQjtHQUM3RCxJQUFJLENBQUMsS0FBSyxjQUFjLGNBQWMsWUFBWSxHQUFHO0lBQ25ELEtBQUssb0JBQW9CLGNBQWM7S0FBRSxXQUFXO0tBQWE7SUFBTyxDQUFDO0lBQ3pFO0dBQ0Y7R0FFQSxLQUFLLGNBQWMsVUFBVSxjQUFjLE1BQU07R0FDakQsTUFBTSxPQUFPLEtBQUssY0FBYyxjQUFjLFlBQVk7R0FDMUQsS0FBSyxvQkFBb0IsS0FBSztJQUM1QixNQUFNO0lBQ04sT0FBTztJQUNQO0lBQ0EsV0FBVyxNQUFNO0lBQ2pCLFFBQVEsT0FBTyxNQUFNO0lBQ3JCLFFBQVEsRUFBRSxPQUFPO0lBQ2pCLEdBQUcsOEJBQThCLEtBQUssaUJBQWlCLGNBQWMsWUFBWSxDQUFDO0dBQ3BGLENBQUM7RUFDSDtFQUVBLFlBQVksY0FBNEI7R0FDdEMsTUFBTSxPQUFPLEtBQUssY0FBYyxjQUFjLFlBQVk7R0FDMUQsSUFBSSxDQUFDLE1BQU07SUFDVCxLQUFLLG9CQUFvQixjQUFjLEVBQUUsV0FBVyxjQUFjLENBQUM7SUFDbkU7R0FDRjtHQUVBLE1BQU0sU0FBUyxLQUFLO0dBQ3BCLEtBQUssY0FBYyxZQUFZLFlBQVk7R0FDM0MsS0FBSyxvQkFBb0IsS0FBSztJQUM1QixNQUFNO0lBQ04sT0FBTztJQUNQO0lBQ0EsV0FBVyxLQUFLO0lBQ2hCLFFBQVEsYUFBYSxNQUFNO0lBQzNCLFFBQVEsV0FBVyxTQUFZLEVBQUUsT0FBTyxJQUFJO0lBQzVDLEdBQUcsOEJBQThCLEtBQUssaUJBQWlCLGNBQWMsWUFBWSxDQUFDO0dBQ3BGLENBQUM7RUFDSDtFQUVBLEtBQUssY0FBc0IsUUFBK0I7R0FDeEQsSUFBSSxDQUFDLEtBQUssY0FBYyxjQUFjLFlBQVksR0FBRztJQUNuRCxLQUFLLG9CQUFvQixjQUFjO0tBQUUsV0FBVztLQUFRO0lBQU8sQ0FBQztJQUNwRTtHQUNGO0dBRUEsS0FBSyxjQUFjLEtBQUssY0FBYyxNQUFNO0dBQzVDLE1BQU0sT0FBTyxLQUFLLGNBQWMsY0FBYyxZQUFZO0dBQzFELE1BQU0sYUFBYSxLQUFLLGlCQUFpQixjQUFjLFlBQVk7R0FDbkUsS0FBSyxvQkFBb0IsS0FBSztJQUM1QixNQUFNO0lBQ04sT0FBTztJQUNQO0lBQ0EsV0FBVyxNQUFNO0lBQ2pCLFFBQVEsWUFBWSxVQUFVLGFBQWEsTUFBTSxNQUFNO0lBQ3ZELFFBQVEsRUFBRSxPQUFPO0lBQ2pCLEdBQUcsOEJBQThCLFVBQVU7R0FDN0MsQ0FBQztFQUNIO0VBRUEsTUFBTSxjQUFzQixRQUErQjtHQUN6RCxNQUFNLE9BQU8sS0FBSyxjQUFjLGNBQWMsWUFBWTtHQUMxRCxJQUFJLENBQUMsTUFBTTtJQUNULEtBQUssb0JBQW9CLGNBQWM7S0FBRSxXQUFXO0tBQVM7SUFBTyxDQUFDO0lBQ3JFO0dBQ0Y7R0FFQSxLQUFLLGNBQWMsTUFBTSxjQUFjLE1BQU07R0FDN0MsTUFBTSxhQUFhLEtBQUssaUJBQWlCLGNBQWMsWUFBWTtHQUNuRSxLQUFLLG9CQUFvQixLQUFLO0lBQzVCLE1BQU07SUFDTixPQUFPO0lBQ1A7SUFDQSxXQUFXLEtBQUs7SUFDaEIsUUFBUSxZQUFZLFVBQVUsYUFBYSxLQUFLLE1BQU07SUFDdEQsUUFBUSxFQUFFLE9BQU87SUFDakIsR0FBRyw4QkFBOEIsVUFBVTtHQUM3QyxDQUFDO0VBQ0g7RUFFQSxvQkFDRSxjQUNBLFFBS007R0FDTixLQUFLLG9CQUFvQixLQUFLO0lBQzVCLE1BQU07SUFDTixPQUFPO0lBQ1A7SUFDQSxRQUFRO0tBQUUsR0FBRztLQUFRLFFBQVE7SUFBb0I7R0FDbkQsQ0FBQztFQUNIO0VBRUEsVUFBZ0IsT0FBZSxNQUFZLFdBQTBCO0dBQ25FLEtBQUssa0JBQWtCLGtCQUFrQixJQUFJLFNBQVMsR0FBRyxPQUFPLElBQUk7RUFDdEU7RUFFQSxjQUNFLFFBQ0EsT0FDQSxNQUNBLFdBQ007R0FDTixLQUFLLGtCQUFrQixrQkFBa0IsS0FBSyxRQUFRLFNBQVMsR0FBRyxPQUFPLElBQUk7RUFDL0U7RUFFQSxjQUNFLFFBQ0EsT0FDQSxNQUNBLFdBQ007R0FDTixLQUFLLGtCQUFrQixrQkFBa0IsS0FBSyxRQUFRLFNBQVMsR0FBRyxPQUFPLElBQUk7RUFDL0U7RUFFQSxrQkFBd0IsVUFBaUMsT0FBZSxNQUFrQjtHQUN4RixLQUFLLGVBQWUsa0JBQWtCLFVBQVUsT0FBTyxJQUFJO0VBQzdEO0VBRUEsY0FBYyxjQUEyRDtHQUN2RSxPQUFPLEtBQUssY0FBYyxjQUFjLFlBQVk7RUFDdEQ7RUFFQSxtQkFBbUIsV0FBNEI7R0FDN0MsT0FBTyxLQUFLLGNBQWMsbUJBQW1CLFNBQVM7RUFDeEQ7RUFFQSxlQUFlLFFBQXlCLFdBQStDO0dBQ3JGLE9BQU8sS0FBSyxjQUFjLGVBQWUsUUFBUSxTQUFTO0VBQzVEO0VBRUEsV0FBbUM7R0FDakMsT0FBTyxLQUFLLGNBQWMsU0FBUztFQUNyQztFQUVBLFNBQVMsTUFBZSxRQUF1QjtHQUM3QyxLQUFLLGlCQUFpQixTQUFTLE1BQU0sTUFBTTtFQUM3QztFQUVBLE1BQU0sU0FBUyxNQUFlLFFBQWdDO0dBQzVELEtBQUssU0FBUyxNQUFNLE1BQU07R0FDMUIsTUFBTSxLQUFLLGVBQWUsU0FBUztFQUNyQztDQUNGIn0=
|
|
377
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid3MtcmVnaXN0cnkuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3N0cmVhbS93cy1yZWdpc3RyeS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyB0eXBlIHogfSBmcm9tIFwiem9kXCI7XG5cbmltcG9ydCB7IHJ1bnRpbWVUeXBlT2YgfSBmcm9tIFwiLi4vcnVudGltZS10eXBlXCI7XG5pbXBvcnQgeyBpc0Z1bmN0aW9uVmFsdWUgfSBmcm9tIFwiLi4vdXRpbHMvcnVudGltZS12YWx1ZVwiO1xuaW1wb3J0IHsgV2ViU29ja2V0QXVkaWVuY2UsIHR5cGUgV2ViU29ja2V0QXVkaWVuY2UgYXMgV2ViU29ja2V0QXVkaWVuY2VTcGVjIH0gZnJvbSBcIi4vd3MtYXVkaWVuY2VcIjtcbmltcG9ydCB7IFdlYlNvY2tldEF1ZGllbmNlUmVzb2x2ZXIgfSBmcm9tIFwiLi93cy1hdWRpZW5jZS1yZXNvbHZlclwiO1xuaW1wb3J0IHsgTm9vcFdlYlNvY2tldENsdXN0ZXJCdXMsIHR5cGUgV2ViU29ja2V0Q2x1c3RlckJ1cyB9IGZyb20gXCIuL3dzLWNsdXN0ZXItYnVzXCI7XG5pbXBvcnQge1xuICB0eXBlIE1hbmFnZWRXZWJTb2NrZXRDb25uZWN0aW9uLFxuICB0eXBlIE1heWJlUHJvbWlzZSxcbiAgdHlwZSBXZWJTb2NrZXRGcmFtZUNvbm5lY3Rpb24sXG4gIHR5cGUgV2ViU29ja2V0UmVnaXN0cnlTdGF0cyxcbiAgdHlwZSBXZWJTb2NrZXRSb29tSWQsXG4gIHR5cGUgV2ViU29ja2V0VXNlcklkLFxufSBmcm9tIFwiLi93cy1jb3JlXCI7XG5pbXBvcnQgeyBXZWJTb2NrZXREZWxpdmVyeUVuZ2luZSwgdHlwZSBXZWJTb2NrZXRSb3V0ZURlZmluaXRpb24gfSBmcm9tIFwiLi93cy1kZWxpdmVyeVwiO1xuaW1wb3J0IHsgV2ViU29ja2V0TG9jYWxDb25uZWN0aW9uU3RvcmUgfSBmcm9tIFwiLi93cy1sb2NhbC1jb25uZWN0aW9uLXN0b3JlXCI7XG5pbXBvcnQgeyBXZWJTb2NrZXRQcmVzZW5jZUluZGV4IH0gZnJvbSBcIi4vd3MtcHJlc2VuY2UtaW5kZXhcIjtcbmltcG9ydCB7XG4gIEluTWVtb3J5V2ViU29ja2V0UHJlc2VuY2VTdG9yZSxcbiAgdHlwZSBXZWJTb2NrZXRQcmVzZW5jZVN0b3JlLFxuICB0eXBlIFdlYlNvY2tldFNlc3Npb25QcmVzZW5jZSxcbn0gZnJvbSBcIi4vd3MtcHJlc2VuY2Utc3RvcmVcIjtcbmltcG9ydCB7XG4gIHR5cGUgVGVsZW1ldHJ5Q29udGV4dFByb3ZpZGVyLFxuICBOb29wV2ViU29ja2V0VGVsZW1ldHJ5Q29udHJvbGxlcixcbiAgdHlwZSBXZWJTb2NrZXRUZWxlbWV0cnlDb25uZWN0aW9uQ29udGV4dCxcbiAgdHlwZSBXZWJTb2NrZXRUZWxlbWV0cnlDb250cm9sbGVyLFxufSBmcm9tIFwiLi93cy10ZWxlbWV0cnlcIjtcblxuZXhwb3J0IHR5cGUge1xuICBNYW5hZ2VkV2ViU29ja2V0Q29ubmVjdGlvbixcbiAgV2ViU29ja2V0UmVnaXN0cnlTdGF0cyxcbiAgV2ViU29ja2V0Um9vbUlkLFxuICBXZWJTb2NrZXRVc2VySWQsXG59O1xuZXhwb3J0IHR5cGUgV2ViU29ja2V0Q29ubmVjdGlvbk1ldGEgPSBXZWJTb2NrZXRTZXNzaW9uUHJlc2VuY2U7XG5leHBvcnQgdHlwZSBXZWJTb2NrZXRSb29tTWVtYmVyQ291bnQgPSB7XG4gIGNvdW50OiBudW1iZXI7XG4gIC8vIHN0b3JlIOyhsO2ajOyXkCDsi6TtjKjtlbQg64W465OcIOuhnOy7rCDsiJjroZwg64yA7LK07ZaI7Jy866m0IHRydWVcbiAgcGFydGlhbDogYm9vbGVhbjtcbn07XG5cbmNvbnN0IERFRkFVTFRfRFJBSU5fVElNRU9VVF9NUyA9IDUwMDA7XG5cbnR5cGUgU3RvcmVNdXRhdGlvbk9wZXJhdGlvbiA9XG4gIHwgXCJyZWdpc3RlclwiXG4gIHwgXCJhY3RpdmF0ZVwiXG4gIHwgXCJ1bnJlZ2lzdGVyXCJcbiAgfCBcInNldFVzZXJJZFwiXG4gIHwgXCJjbGVhclVzZXJJZFwiXG4gIHwgXCJqb2luXCJcbiAgfCBcImxlYXZlXCI7XG5cbmV4cG9ydCB0eXBlIFdlYlNvY2tldFJlZ2lzdHJ5T3B0aW9ucyA9IHtcbiAgLy8g67aE7IKwIO2ZmOqyveyXkOyEnCDrhbjrk5wg6rCEIOudvOyasO2MhSDsi53rs4TsnpDroZwg7JOw7J2066+A66GcIOuwmOuTnOyLnCDtmLjstpwg7LihKFdlYlNvY2tldFJ1bnRpbWUp7JeQ7IScIOqysOygle2VtCDrhJjquLTri6RcbiAgbm9kZUlkOiBzdHJpbmc7XG4gIHByZXNlbmNlU3RvcmU/OiBXZWJTb2NrZXRQcmVzZW5jZVN0b3JlO1xuICBjbHVzdGVyQnVzPzogV2ViU29ja2V0Q2x1c3RlckJ1cztcbiAgdGVsZW1ldHJ5Q29udHJvbGxlcj86IFdlYlNvY2tldFRlbGVtZXRyeUNvbnRyb2xsZXI7XG4gIC8vIHNodXRkb3duIOyLnCDsp4Ttlokg7KSR7J24IHN0b3JlIG11dGF0aW9u6rO8IHB1Ymxpc2jrpbwg6riw64uk66as64qUIOyDge2VnFxuICBkcmFpblRpbWVvdXRNcz86IG51bWJlcjtcbn07XG5cbi8qKlxuICog64W465OcIOuhnOy7rCBwcmVzZW5jZeulvCDrqZTrqqjrpqzsl5Ag7IaM7Jyg7ZWY6rOgLCDshKTsoJXrkJwgc3RvcmXsl5DripQg7IS47IWY67OEIOyInOyEnOuMgOuhnCByZXBsaWNh66W8IOuwmOyYge2VnOuLpC5cbiAqIG11dGF0aW9u6rO8IHB1Ymxpc2jripQg7Zi47LacIOyLnOygkOyXkCDrqZTrqqjrpqzrpbwg64+Z6riw66GcIOqwseyLoO2VmOqzoCwgc3RvcmUg7Iuk7Yyo64qUIHRlbGVtZXRyeeuhnOunjCDquLDroZ3tlZjrqbAgcmVqZWN07ZWY7KeAIOyViuuKlOuLpC5cbiAqL1xuZXhwb3J0IGNsYXNzIFdlYlNvY2tldFJlZ2lzdHJ5IHtcbiAgcmVhZG9ubHkgbm9kZUlkOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGxvY2FsQ29ubmVjdGlvbnMgPSBuZXcgV2ViU29ja2V0TG9jYWxDb25uZWN0aW9uU3RvcmUoKTtcbiAgcmVhZG9ubHkgcHJlc2VuY2VTdG9yZTogV2ViU29ja2V0UHJlc2VuY2VTdG9yZTtcbiAgcmVhZG9ubHkgY2x1c3RlckJ1czogV2ViU29ja2V0Q2x1c3RlckJ1cztcbiAgcmVhZG9ubHkgdGVsZW1ldHJ5Q29udHJvbGxlcjogV2ViU29ja2V0VGVsZW1ldHJ5Q29udHJvbGxlcjtcbiAgcHJpdmF0ZSByZWFkb25seSBtZW1vcnkgPSBuZXcgV2ViU29ja2V0UHJlc2VuY2VJbmRleCgpO1xuICBwcml2YXRlIHJlYWRvbmx5IGRlbGl2ZXJ5RW5naW5lOiBXZWJTb2NrZXREZWxpdmVyeUVuZ2luZTtcbiAgcHJpdmF0ZSByZWFkb25seSBkcmFpblRpbWVvdXRNczogbnVtYmVyO1xuICAvLyDshLjshZjrs4Qgc3RvcmUgbXV0YXRpb24g7YGQ7J2YIOq8rOumrC4g6rCZ7J2AIOyEuOyFmOydmCDtmLjstpzsnYAg7J20IHByb21pc2Ug65Kk7JeQIOydtOyWtCDrtpnslrQg7Zi47LacIOyInOyEnOuMgOuhnCBzdG9yZeyXkCDrj4Tri6ztlZzri6RcbiAgcHJpdmF0ZSByZWFkb25seSBtdXRhdGlvblF1ZXVlcyA9IG5ldyBNYXA8c3RyaW5nLCBQcm9taXNlPHZvaWQ+PigpO1xuXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnM6IFdlYlNvY2tldFJlZ2lzdHJ5T3B0aW9ucykge1xuICAgIHRoaXMubm9kZUlkID0gb3B0aW9ucy5ub2RlSWQ7XG4gICAgdGhpcy5wcmVzZW5jZVN0b3JlID0gb3B0aW9ucy5wcmVzZW5jZVN0b3JlID8/IG5ldyBJbk1lbW9yeVdlYlNvY2tldFByZXNlbmNlU3RvcmUoKTtcbiAgICB0aGlzLmNsdXN0ZXJCdXMgPSBvcHRpb25zLmNsdXN0ZXJCdXMgPz8gbmV3IE5vb3BXZWJTb2NrZXRDbHVzdGVyQnVzKCk7XG4gICAgdGhpcy5kcmFpblRpbWVvdXRNcyA9IG9wdGlvbnMuZHJhaW5UaW1lb3V0TXMgPz8gREVGQVVMVF9EUkFJTl9USU1FT1VUX01TO1xuICAgIGFzc2VydE1hdGNoaW5nTm9kZUlkKFwicHJlc2VuY2VTdG9yZVwiLCB0aGlzLnByZXNlbmNlU3RvcmUubm9kZUlkLCB0aGlzLm5vZGVJZCk7XG4gICAgYXNzZXJ0TWF0Y2hpbmdOb2RlSWQoXCJjbHVzdGVyQnVzXCIsIHRoaXMuY2x1c3RlckJ1cy5ub2RlSWQsIHRoaXMubm9kZUlkKTtcbiAgICB0aGlzLnRlbGVtZXRyeUNvbnRyb2xsZXIgPVxuICAgICAgb3B0aW9ucy50ZWxlbWV0cnlDb250cm9sbGVyID8/IG5ldyBOb29wV2ViU29ja2V0VGVsZW1ldHJ5Q29udHJvbGxlcigpO1xuICAgIHRoaXMuZGVsaXZlcnlFbmdpbmUgPSBuZXcgV2ViU29ja2V0RGVsaXZlcnlFbmdpbmUoe1xuICAgICAgbm9kZUlkOiB0aGlzLm5vZGVJZCxcbiAgICAgIGxvY2FsQ29ubmVjdGlvbnM6IHRoaXMubG9jYWxDb25uZWN0aW9ucyxcbiAgICAgIHJlc29sdmVMb2NhbFNlc3Npb25JZHM6IChhdWRpZW5jZSkgPT5cbiAgICAgICAgdGhpcy5tZW1vcnkucXVlcnlBdWRpZW5jZShhdWRpZW5jZSkubWFwKChzZXNzaW9uKSA9PiBzZXNzaW9uLnNlc3Npb25JZCksXG4gICAgICBhdWRpZW5jZVJlc29sdmVyOiBuZXcgV2ViU29ja2V0QXVkaWVuY2VSZXNvbHZlcih7XG4gICAgICAgIG5vZGVJZDogdGhpcy5ub2RlSWQsXG4gICAgICAgIHByZXNlbmNlU3RvcmU6IHRoaXMucHJlc2VuY2VTdG9yZSxcbiAgICAgIH0pLFxuICAgICAgY2x1c3RlckJ1czogdGhpcy5jbHVzdGVyQnVzLFxuICAgICAgdGVsZW1ldHJ5Q29udHJvbGxlcjogdGhpcy50ZWxlbWV0cnlDb250cm9sbGVyLFxuICAgIH0pO1xuXG4gICAgLy8gdGVsZW1ldHJ564qUIOuFuOuTnCDroZzsu6wg66mU66qo66as66eMIOynkeqzhO2VnOuLpC4g7YG065+s7Iqk7YSwIO2VqeqzhOulvCDrqqjrk6Ag64W465Oc6rCAIOuztOqzoO2VmOuptCDsp5Hqs4Qg7IucIOykkeuzteuQmOq4sCDrlYzrrLjsnbTri6RcbiAgICB0aGlzLnRlbGVtZXRyeUNvbnRyb2xsZXIucmVnaXN0ZXJNZXRyaWNTb3VyY2Uoe1xuICAgICAgY29sbGVjdDogKF9ub3cpID0+IHtcbiAgICAgICAgY29uc3Qgc3RhdHMgPSB0aGlzLm1lbW9yeS5nZXRTdGF0cygpO1xuICAgICAgICBjb25zdCBsb2NhbFNuYXBzaG90ID0gdGhpcy5sb2NhbENvbm5lY3Rpb25zLmdldFRlbGVtZXRyeVNuYXBzaG90KCk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgYWN0aXZlQ29ubmVjdGlvbnM6IHN0YXRzLnRvdGFsQ29ubmVjdGlvbnMsXG4gICAgICAgICAgYWN0aXZlQ29ubmVjdGlvbnNCeU5hbWVzcGFjZTogc3RhdHMuYnlOYW1lc3BhY2UsXG4gICAgICAgICAgcm9vbUNvdW50OiBzdGF0cy50b3RhbFJvb21zLFxuICAgICAgICAgIHBlbmRpbmdJbmJvdW5kTWVzc2FnZXM6IGxvY2FsU25hcHNob3QucGVuZGluZ0luYm91bmRNZXNzYWdlcyxcbiAgICAgICAgICBwZW5kaW5nT3V0Ym91bmRNZXNzYWdlczogbG9jYWxTbmFwc2hvdC5wZW5kaW5nT3V0Ym91bmRNZXNzYWdlcyxcbiAgICAgICAgICBzb2NrZXRCdWZmZXJlZEJ5dGVzOiBsb2NhbFNuYXBzaG90LnNvY2tldEJ1ZmZlcmVkQnl0ZXMsXG4gICAgICAgIH07XG4gICAgICB9LFxuICAgIH0pO1xuICB9XG5cbiAgcmVnaXN0ZXJSb3V0ZShyb3V0ZUtleTogc3RyaW5nLCBvdXRFdmVudHM6IHouWm9kT2JqZWN0KTogdm9pZCB7XG4gICAgdGhpcy5kZWxpdmVyeUVuZ2luZS5yZWdpc3RlclJvdXRlKHJvdXRlS2V5LCBvdXRFdmVudHMpO1xuICB9XG5cbiAgcmVwbGFjZVJvdXRlcyhyb3V0ZXM6IFdlYlNvY2tldFJvdXRlRGVmaW5pdGlvbltdKTogdm9pZCB7XG4gICAgdGhpcy5kZWxpdmVyeUVuZ2luZS5yZXBsYWNlUm91dGVzKHJvdXRlcyk7XG4gIH1cblxuICAvKipcbiAgICog7Jew6rKw7J2EIOuplOuqqOumrOyXkCDsponsi5wg65Ox66Gd7ZWY6rOgIHN0b3JlLnJlZ2lzdGVy6rCAIOuBneuCmOuptCByZXNvbHZl7ZWc64ukLlxuICAgKiBzdG9yZeqwgCDsi6TtjKjtlbTrj4Qg66mU66qo66asIOyghOyaqSDrk7HroZ3snLzroZwgcmVzb2x2Ze2VnOuLpC5cbiAgICovXG4gIGFzeW5jIHJlZ2lzdGVyKFxuICAgIGNvbm5lY3Rpb246IFdlYlNvY2tldEZyYW1lQ29ubmVjdGlvbixcbiAgICBhY3RpdmU6IGJvb2xlYW4gPSB0cnVlLFxuICApOiBQcm9taXNlPFdlYlNvY2tldENvbm5lY3Rpb25NZXRhPiB7XG4gICAgY29uc3QgcmVnaXN0cmF0aW9uID0ge1xuICAgICAgc2Vzc2lvbklkOiBjb25uZWN0aW9uLmlkLFxuICAgICAgbm9kZUlkOiB0aGlzLm5vZGVJZCxcbiAgICAgIG5hbWVzcGFjZTogY29ubmVjdGlvbi5uYW1lc3BhY2UsXG4gICAgICBhY3RpdmUsXG4gICAgICBjb25uZWN0ZWRBdDogbmV3IERhdGUoKSxcbiAgICB9O1xuICAgIHRoaXMubG9jYWxDb25uZWN0aW9ucy5yZWdpc3Rlcihjb25uZWN0aW9uKTtcbiAgICB0aGlzLm1lbW9yeS5yZWdpc3RlcihyZWdpc3RyYXRpb24pO1xuICAgIHRoaXMudGVsZW1ldHJ5Q29udHJvbGxlci5lbWl0KHtcbiAgICAgIG5hbWU6IFwid3MuY29ubmVjdGlvbi5yZWdpc3RlcmVkXCIsXG4gICAgICBsZXZlbDogXCJpbmZvXCIsXG4gICAgICBjb25uZWN0aW9uSWQ6IGNvbm5lY3Rpb24uaWQsXG4gICAgICBuYW1lc3BhY2U6IGNvbm5lY3Rpb24ubmFtZXNwYWNlLFxuICAgICAgdXNlcklkOiBjb25uZWN0aW9uLnVzZXJJZCxcbiAgICAgIC4uLmdldENvbm5lY3Rpb25UZWxlbWV0cnlDb250ZXh0KGNvbm5lY3Rpb24pLFxuICAgIH0pO1xuICAgIHRoaXMudGVsZW1ldHJ5Q29udHJvbGxlci5yZWNvcmRNZXRyaWMoe1xuICAgICAgbmFtZTogXCJzb25hbXUud3MuY29ubmVjdGlvbnNcIixcbiAgICAgIGtpbmQ6IFwiY291bnRlclwiLFxuICAgICAgdmFsdWU6IDEsXG4gICAgICB1bml0OiBcIjFcIixcbiAgICAgIHRhZ3M6IHsgb3V0Y29tZTogXCJyZWdpc3RlcmVkXCIsIG5hbWVzcGFjZTogY29ubmVjdGlvbi5uYW1lc3BhY2UgfSxcbiAgICAgIHVzZXJJZDogY29ubmVjdGlvbi51c2VySWQsXG4gICAgfSk7XG5cbiAgICBhd2FpdCB0aGlzLmVucXVldWVTdG9yZU11dGF0aW9uKGNvbm5lY3Rpb24uaWQsIFwicmVnaXN0ZXJcIiwgKCkgPT5cbiAgICAgIHRoaXMucHJlc2VuY2VTdG9yZS5yZWdpc3RlcihyZWdpc3RyYXRpb24pLFxuICAgICk7XG4gICAgLy8g65Ox66GdIOuPhOykkSDri6vtmJTsnLzrqbQg66mU66qo66as7JeQ7IScIOydtOuvuCDruaDsoYzsnLzrr4DroZwg65Ox66GdIOyLnOygkCDqsJLsnYQg64+M66Ck7KSA64ukXG4gICAgcmV0dXJuIChcbiAgICAgIHRoaXMubWVtb3J5LmdldENvbm5lY3Rpb24oY29ubmVjdGlvbi5pZCkgPz8ge1xuICAgICAgICAuLi5yZWdpc3RyYXRpb24sXG4gICAgICAgIHJvb21zOiBuZXcgU2V0KCksXG4gICAgICAgIGxhc3RTZWVuQXQ6IHJlZ2lzdHJhdGlvbi5jb25uZWN0ZWRBdCxcbiAgICAgIH1cbiAgICApO1xuICB9XG5cbiAgYWN0aXZhdGUoY29ubmVjdGlvbklkOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoaXMubWVtb3J5Lmhhcyhjb25uZWN0aW9uSWQpKSB7XG4gICAgICB0aGlzLmVtaXRNdXRhdGlvblNraXBwZWQoY29ubmVjdGlvbklkLCB7IG9wZXJhdGlvbjogXCJhY3RpdmF0ZVwiIH0pO1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgIH1cblxuICAgIHRoaXMubWVtb3J5LmFjdGl2YXRlKGNvbm5lY3Rpb25JZCk7XG4gICAgY29uc3QgY29ubmVjdGlvbiA9IHRoaXMubG9jYWxDb25uZWN0aW9ucy5nZXRDb25uZWN0aW9uKGNvbm5lY3Rpb25JZCk7XG4gICAgdGhpcy50ZWxlbWV0cnlDb250cm9sbGVyLmVtaXQoe1xuICAgICAgbmFtZTogXCJ3cy5jb25uZWN0aW9uLmFjdGl2YXRlZFwiLFxuICAgICAgbGV2ZWw6IFwiaW5mb1wiLFxuICAgICAgY29ubmVjdGlvbklkLFxuICAgICAgdXNlcklkOiBjb25uZWN0aW9uPy51c2VySWQsXG4gICAgICAuLi5nZXRDb25uZWN0aW9uVGVsZW1ldHJ5Q29udGV4dChjb25uZWN0aW9uKSxcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcy5lbnF1ZXVlU3RvcmVNdXRhdGlvbihjb25uZWN0aW9uSWQsIFwiYWN0aXZhdGVcIiwgKCkgPT5cbiAgICAgIHRoaXMucHJlc2VuY2VTdG9yZS5hY3RpdmF0ZShjb25uZWN0aW9uSWQpLFxuICAgICk7XG4gIH1cblxuICB1bnJlZ2lzdGVyKGNvbm5lY3Rpb25JZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgY29ubmVjdGlvbiA9IHRoaXMubG9jYWxDb25uZWN0aW9ucy5nZXRDb25uZWN0aW9uKGNvbm5lY3Rpb25JZCk7XG4gICAgY29uc3QgdGVsZW1ldHJ5Q29udGV4dCA9IGdldENvbm5lY3Rpb25UZWxlbWV0cnlDb250ZXh0KGNvbm5lY3Rpb24pO1xuICAgIGNvbnN0IG1ldGEgPSB0aGlzLm1lbW9yeS51bnJlZ2lzdGVyKGNvbm5lY3Rpb25JZCk7XG4gICAgY29uc3QgdXNlcklkID0gY29ubmVjdGlvbj8udXNlcklkID8/IGZvcm1hdFVzZXJJZChtZXRhPy51c2VySWQpO1xuICAgIHRoaXMubG9jYWxDb25uZWN0aW9ucy51bnJlZ2lzdGVyKGNvbm5lY3Rpb25JZCk7XG4gICAgdGhpcy50ZWxlbWV0cnlDb250cm9sbGVyLmVtaXQoe1xuICAgICAgbmFtZTogXCJ3cy5jb25uZWN0aW9uLnVucmVnaXN0ZXJlZFwiLFxuICAgICAgbGV2ZWw6IFwiZGVidWdcIixcbiAgICAgIGNvbm5lY3Rpb25JZCxcbiAgICAgIG5hbWVzcGFjZTogbWV0YT8ubmFtZXNwYWNlLFxuICAgICAgdXNlcklkLFxuICAgICAgLi4udGVsZW1ldHJ5Q29udGV4dCxcbiAgICB9KTtcbiAgICBpZiAoIW1ldGEpIHtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICB9XG5cbiAgICB0aGlzLnRlbGVtZXRyeUNvbnRyb2xsZXIucmVjb3JkTWV0cmljKHtcbiAgICAgIG5hbWU6IFwic29uYW11LndzLmNvbm5lY3Rpb25zXCIsXG4gICAgICBraW5kOiBcImNvdW50ZXJcIixcbiAgICAgIHZhbHVlOiAxLFxuICAgICAgdW5pdDogXCIxXCIsXG4gICAgICB0YWdzOiB7IG91dGNvbWU6IFwidW5yZWdpc3RlcmVkXCIsIG5hbWVzcGFjZTogbWV0YS5uYW1lc3BhY2UgfSxcbiAgICAgIHVzZXJJZCxcbiAgICB9KTtcbiAgICAvLyDqsJnsnYAg7IS47IWYIO2BkOyXkCDsnbTslrQg67aZ7Jy866+A66GcIOynhO2WiSDspJHsnbggcmVnaXN0ZXLrs7Tri6Qg66i87KCAIHN0b3Jl7JeQIOuPhOuLrO2VmOyngCDslYrripTri6RcbiAgICByZXR1cm4gdGhpcy5lbnF1ZXVlU3RvcmVNdXRhdGlvbihjb25uZWN0aW9uSWQsIFwidW5yZWdpc3RlclwiLCAoKSA9PlxuICAgICAgdGhpcy5wcmVzZW5jZVN0b3JlLnVucmVnaXN0ZXIoY29ubmVjdGlvbklkKSxcbiAgICApO1xuICB9XG5cbiAgLy8gbGFzdFNlZW5BdOydgCDrqZTrqqjrpqzrp4wg6rCx7Iug7ZWc64ukLiBzdG9yZeyXkOuKlCDrp4jsp4Drp4kgbXV0YXRpb24g7Iuc7KCQIOqwkuydtCDrgqjripTri6RcbiAgdG91Y2goY29ubmVjdGlvbklkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLm1lbW9yeS50b3VjaChjb25uZWN0aW9uSWQpO1xuICB9XG5cbiAgc2V0VXNlcklkKGNvbm5lY3Rpb25JZDogc3RyaW5nLCB1c2VySWQ6IFdlYlNvY2tldFVzZXJJZCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IG1ldGEgPSB0aGlzLm1lbW9yeS5nZXRDb25uZWN0aW9uKGNvbm5lY3Rpb25JZCk7XG4gICAgaWYgKCFtZXRhKSB7XG4gICAgICB0aGlzLmVtaXRNdXRhdGlvblNraXBwZWQoY29ubmVjdGlvbklkLCB7IG9wZXJhdGlvbjogXCJzZXRVc2VySWRcIiwgdXNlcklkIH0pO1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgIH1cblxuICAgIHRoaXMubWVtb3J5LnNldFVzZXJJZChjb25uZWN0aW9uSWQsIHVzZXJJZCk7XG4gICAgdGhpcy50ZWxlbWV0cnlDb250cm9sbGVyLmVtaXQoe1xuICAgICAgbmFtZTogXCJ3cy51c2VyLmJvdW5kXCIsXG4gICAgICBsZXZlbDogXCJkZWJ1Z1wiLFxuICAgICAgY29ubmVjdGlvbklkLFxuICAgICAgbmFtZXNwYWNlOiBtZXRhLm5hbWVzcGFjZSxcbiAgICAgIHVzZXJJZDogU3RyaW5nKHVzZXJJZCksXG4gICAgICBkZXRhaWw6IHsgdXNlcklkIH0sXG4gICAgICAuLi5nZXRDb25uZWN0aW9uVGVsZW1ldHJ5Q29udGV4dCh0aGlzLmxvY2FsQ29ubmVjdGlvbnMuZ2V0Q29ubmVjdGlvbihjb25uZWN0aW9uSWQpKSxcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcy5lbnF1ZXVlU3RvcmVNdXRhdGlvbihjb25uZWN0aW9uSWQsIFwic2V0VXNlcklkXCIsICgpID0+XG4gICAgICB0aGlzLnByZXNlbmNlU3RvcmUuc2V0VXNlcklkKGNvbm5lY3Rpb25JZCwgdXNlcklkKSxcbiAgICApO1xuICB9XG5cbiAgY2xlYXJVc2VySWQoY29ubmVjdGlvbklkOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBtZXRhID0gdGhpcy5tZW1vcnkuZ2V0Q29ubmVjdGlvbihjb25uZWN0aW9uSWQpO1xuICAgIGlmICghbWV0YSkge1xuICAgICAgdGhpcy5lbWl0TXV0YXRpb25Ta2lwcGVkKGNvbm5lY3Rpb25JZCwgeyBvcGVyYXRpb246IFwiY2xlYXJVc2VySWRcIiB9KTtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICB9XG5cbiAgICBjb25zdCB1c2VySWQgPSBtZXRhLnVzZXJJZDtcbiAgICB0aGlzLm1lbW9yeS5jbGVhclVzZXJJZChjb25uZWN0aW9uSWQpO1xuICAgIHRoaXMudGVsZW1ldHJ5Q29udHJvbGxlci5lbWl0KHtcbiAgICAgIG5hbWU6IFwid3MudXNlci5jbGVhcmVkXCIsXG4gICAgICBsZXZlbDogXCJkZWJ1Z1wiLFxuICAgICAgY29ubmVjdGlvbklkLFxuICAgICAgbmFtZXNwYWNlOiBtZXRhLm5hbWVzcGFjZSxcbiAgICAgIHVzZXJJZDogZm9ybWF0VXNlcklkKHVzZXJJZCksXG4gICAgICBkZXRhaWw6IHVzZXJJZCAhPT0gdW5kZWZpbmVkID8geyB1c2VySWQgfSA6IHVuZGVmaW5lZCxcbiAgICAgIC4uLmdldENvbm5lY3Rpb25UZWxlbWV0cnlDb250ZXh0KHRoaXMubG9jYWxDb25uZWN0aW9ucy5nZXRDb25uZWN0aW9uKGNvbm5lY3Rpb25JZCkpLFxuICAgIH0pO1xuICAgIHJldHVybiB0aGlzLmVucXVldWVTdG9yZU11dGF0aW9uKGNvbm5lY3Rpb25JZCwgXCJjbGVhclVzZXJJZFwiLCAoKSA9PlxuICAgICAgdGhpcy5wcmVzZW5jZVN0b3JlLmNsZWFyVXNlcklkKGNvbm5lY3Rpb25JZCksXG4gICAgKTtcbiAgfVxuXG4gIGpvaW4oY29ubmVjdGlvbklkOiBzdHJpbmcsIHJvb21JZDogV2ViU29ja2V0Um9vbUlkKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgbWV0YSA9IHRoaXMubWVtb3J5LmdldENvbm5lY3Rpb24oY29ubmVjdGlvbklkKTtcbiAgICBpZiAoIW1ldGEpIHtcbiAgICAgIHRoaXMuZW1pdE11dGF0aW9uU2tpcHBlZChjb25uZWN0aW9uSWQsIHsgb3BlcmF0aW9uOiBcImpvaW5cIiwgcm9vbUlkIH0pO1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgIH1cblxuICAgIHRoaXMubWVtb3J5LmpvaW4oY29ubmVjdGlvbklkLCByb29tSWQpO1xuICAgIGNvbnN0IGNvbm5lY3Rpb24gPSB0aGlzLmxvY2FsQ29ubmVjdGlvbnMuZ2V0Q29ubmVjdGlvbihjb25uZWN0aW9uSWQpO1xuICAgIHRoaXMudGVsZW1ldHJ5Q29udHJvbGxlci5lbWl0KHtcbiAgICAgIG5hbWU6IFwid3Mucm9vbS5qb2luZWRcIixcbiAgICAgIGxldmVsOiBcImRlYnVnXCIsXG4gICAgICBjb25uZWN0aW9uSWQsXG4gICAgICBuYW1lc3BhY2U6IG1ldGEubmFtZXNwYWNlLFxuICAgICAgdXNlcklkOiBjb25uZWN0aW9uPy51c2VySWQgPz8gZm9ybWF0VXNlcklkKG1ldGEudXNlcklkKSxcbiAgICAgIGRldGFpbDogeyByb29tSWQgfSxcbiAgICAgIC4uLmdldENvbm5lY3Rpb25UZWxlbWV0cnlDb250ZXh0KGNvbm5lY3Rpb24pLFxuICAgIH0pO1xuICAgIHJldHVybiB0aGlzLmVucXVldWVTdG9yZU11dGF0aW9uKGNvbm5lY3Rpb25JZCwgXCJqb2luXCIsICgpID0+XG4gICAgICB0aGlzLnByZXNlbmNlU3RvcmUuam9pbihjb25uZWN0aW9uSWQsIHJvb21JZCksXG4gICAgKTtcbiAgfVxuXG4gIGxlYXZlKGNvbm5lY3Rpb25JZDogc3RyaW5nLCByb29tSWQ6IFdlYlNvY2tldFJvb21JZCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IG1ldGEgPSB0aGlzLm1lbW9yeS5nZXRDb25uZWN0aW9uKGNvbm5lY3Rpb25JZCk7XG4gICAgaWYgKCFtZXRhKSB7XG4gICAgICB0aGlzLmVtaXRNdXRhdGlvblNraXBwZWQoY29ubmVjdGlvbklkLCB7IG9wZXJhdGlvbjogXCJsZWF2ZVwiLCByb29tSWQgfSk7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7XG4gICAgfVxuXG4gICAgdGhpcy5tZW1vcnkubGVhdmUoY29ubmVjdGlvbklkLCByb29tSWQpO1xuICAgIGNvbnN0IGNvbm5lY3Rpb24gPSB0aGlzLmxvY2FsQ29ubmVjdGlvbnMuZ2V0Q29ubmVjdGlvbihjb25uZWN0aW9uSWQpO1xuICAgIHRoaXMudGVsZW1ldHJ5Q29udHJvbGxlci5lbWl0KHtcbiAgICAgIG5hbWU6IFwid3Mucm9vbS5sZWZ0XCIsXG4gICAgICBsZXZlbDogXCJkZWJ1Z1wiLFxuICAgICAgY29ubmVjdGlvbklkLFxuICAgICAgbmFtZXNwYWNlOiBtZXRhLm5hbWVzcGFjZSxcbiAgICAgIHVzZXJJZDogY29ubmVjdGlvbj8udXNlcklkID8/IGZvcm1hdFVzZXJJZChtZXRhLnVzZXJJZCksXG4gICAgICBkZXRhaWw6IHsgcm9vbUlkIH0sXG4gICAgICAuLi5nZXRDb25uZWN0aW9uVGVsZW1ldHJ5Q29udGV4dChjb25uZWN0aW9uKSxcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcy5lbnF1ZXVlU3RvcmVNdXRhdGlvbihjb25uZWN0aW9uSWQsIFwibGVhdmVcIiwgKCkgPT5cbiAgICAgIHRoaXMucHJlc2VuY2VTdG9yZS5sZWF2ZShjb25uZWN0aW9uSWQsIHJvb21JZCksXG4gICAgKTtcbiAgfVxuXG4gIGJyb2FkY2FzdDxEYXRhPihldmVudDogc3RyaW5nLCBkYXRhOiBEYXRhLCBuYW1lc3BhY2U/OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gdGhpcy5wdWJsaXNoVG9BdWRpZW5jZShXZWJTb2NrZXRBdWRpZW5jZS5hbGwobmFtZXNwYWNlKSwgZXZlbnQsIGRhdGEpO1xuICB9XG5cbiAgcHVibGlzaFRvUm9vbTxEYXRhPihcbiAgICByb29tSWQ6IFdlYlNvY2tldFJvb21JZCxcbiAgICBldmVudDogc3RyaW5nLFxuICAgIGRhdGE6IERhdGEsXG4gICAgbmFtZXNwYWNlPzogc3RyaW5nLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gdGhpcy5wdWJsaXNoVG9BdWRpZW5jZShXZWJTb2NrZXRBdWRpZW5jZS5yb29tKHJvb21JZCwgbmFtZXNwYWNlKSwgZXZlbnQsIGRhdGEpO1xuICB9XG5cbiAgcHVibGlzaFRvVXNlcjxEYXRhPihcbiAgICB1c2VySWQ6IFdlYlNvY2tldFVzZXJJZCxcbiAgICBldmVudDogc3RyaW5nLFxuICAgIGRhdGE6IERhdGEsXG4gICAgbmFtZXNwYWNlPzogc3RyaW5nLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gdGhpcy5wdWJsaXNoVG9BdWRpZW5jZShXZWJTb2NrZXRBdWRpZW5jZS51c2VyKHVzZXJJZCwgbmFtZXNwYWNlKSwgZXZlbnQsIGRhdGEpO1xuICB9XG5cbiAgcHVibGlzaFRvQXVkaWVuY2U8RGF0YT4oXG4gICAgYXVkaWVuY2U6IFdlYlNvY2tldEF1ZGllbmNlU3BlYyxcbiAgICBldmVudDogc3RyaW5nLFxuICAgIGRhdGE6IERhdGEsXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLmRlbGl2ZXJ5RW5naW5lLnB1Ymxpc2hUb0F1ZGllbmNlKGF1ZGllbmNlLCBldmVudCwgZGF0YSk7XG4gIH1cblxuICAvLyDslYTrnpgg7J296riwIEFQSeuKlCDrhbjrk5wg66Gc7LusIHNuYXBzaG90KOuzteyCrOuzuCnsnbTri6RcbiAgZ2V0Q29ubmVjdGlvbihjb25uZWN0aW9uSWQ6IHN0cmluZyk6IFdlYlNvY2tldENvbm5lY3Rpb25NZXRhIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5tZW1vcnkuZ2V0Q29ubmVjdGlvbihjb25uZWN0aW9uSWQpO1xuICB9XG5cbiAgZ2V0Q29ubmVjdGlvbkNvdW50KG5hbWVzcGFjZT86IHN0cmluZyk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubWVtb3J5LmdldENvbm5lY3Rpb25Db3VudChuYW1lc3BhY2UpO1xuICB9XG5cbiAgZ2V0Um9vbU1lbWJlcnMocm9vbUlkOiBXZWJTb2NrZXRSb29tSWQsIG5hbWVzcGFjZT86IHN0cmluZyk6IFdlYlNvY2tldENvbm5lY3Rpb25NZXRhW10ge1xuICAgIHJldHVybiB0aGlzLm1lbW9yeS5nZXRSb29tTWVtYmVycyhyb29tSWQsIG5hbWVzcGFjZSk7XG4gIH1cblxuICBnZXRTdGF0cygpOiBXZWJTb2NrZXRSZWdpc3RyeVN0YXRzIHtcbiAgICByZXR1cm4gdGhpcy5tZW1vcnkuZ2V0U3RhdHMoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiDtgbTrn6zsiqTthLAg7KCE7LK07J2YIO2ZnOyEsSDrsKkg7J247JuQ7IiYLiBzdG9yZeqwgCDsi6TtjKjtlZjrqbQg64W465OcIOuhnOy7rCDsiJjsl5AgcGFydGlhbDogdHJ1ZeulvCDrtpnsl6wg67CY7ZmY7ZWY66mwIHJlamVjdO2VmOyngCDslYrripTri6QuXG4gICAqL1xuICBhc3luYyBnZXRSb29tTWVtYmVyQ291bnQoXG4gICAgcm9vbUlkOiBXZWJTb2NrZXRSb29tSWQsXG4gICAgbmFtZXNwYWNlPzogc3RyaW5nLFxuICApOiBQcm9taXNlPFdlYlNvY2tldFJvb21NZW1iZXJDb3VudD4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjb3VudCA9IGF3YWl0IGNhbGxTdG9yZSgoKSA9PiB0aGlzLnByZXNlbmNlU3RvcmUuZ2V0Um9vbU1lbWJlckNvdW50KHJvb21JZCwgbmFtZXNwYWNlKSk7XG4gICAgICByZXR1cm4geyBjb3VudCwgcGFydGlhbDogZmFsc2UgfTtcbiAgICB9IGNhdGNoIChjYXVzZSkge1xuICAgICAgdGhpcy50ZWxlbWV0cnlDb250cm9sbGVyLmVtaXQoe1xuICAgICAgICBuYW1lOiBcIndzLnJlZ2lzdHJ5LnJlYWQuZmFpbGVkXCIsXG4gICAgICAgIGxldmVsOiBcIndhcm5cIixcbiAgICAgICAgZGV0YWlsOiB7IG9wZXJhdGlvbjogXCJnZXRSb29tTWVtYmVyQ291bnRcIiwgcm9vbUlkLCBlcnJvclR5cGU6IGRlc2NyaWJlRXJyb3IoY2F1c2UpIH0sXG4gICAgICB9KTtcbiAgICAgIHJldHVybiB7IGNvdW50OiB0aGlzLm1lbW9yeS5nZXRSb29tTWVtYmVyQ291bnQocm9vbUlkLCBuYW1lc3BhY2UpLCBwYXJ0aWFsOiB0cnVlIH07XG4gICAgfVxuICB9XG5cbiAgY2xvc2VBbGwoY29kZT86IG51bWJlciwgcmVhc29uPzogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5sb2NhbENvbm5lY3Rpb25zLmNsb3NlQWxsKGNvZGUsIHJlYXNvbik7XG4gIH1cblxuICAvKipcbiAgICog66Gc7LusIOyXsOqysOydhCDri6vqs6AsIOynhO2WiSDspJHsnbggc3RvcmUgbXV0YXRpb27qs7wgcHVibGlzaOulvCBkcmFpblRpbWVvdXRNc+q5jOyngCDquLDri6TrprAg65KkIHN0b3Jl7JmAIGJ1c+ulvCDsooXro4ztlZzri6QuXG4gICAqL1xuICBhc3luYyBzaHV0ZG93bihjb2RlPzogbnVtYmVyLCByZWFzb24/OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aGlzLmNsb3NlQWxsKGNvZGUsIHJlYXNvbik7XG5cbiAgICBsZXQgdGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgdW5kZWZpbmVkO1xuICAgIGNvbnN0IGRlYWRsaW5lID0gbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUpID0+IHtcbiAgICAgIHRpbWVyID0gc2V0VGltZW91dChyZXNvbHZlLCB0aGlzLmRyYWluVGltZW91dE1zKTtcbiAgICB9KTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgUHJvbWlzZS5yYWNlKFtcbiAgICAgICAgUHJvbWlzZS5hbGwoWy4uLnRoaXMubXV0YXRpb25RdWV1ZXMudmFsdWVzKCksIHRoaXMuZGVsaXZlcnlFbmdpbmUuZHJhaW5QdWJsaXNoZXMoKV0pLFxuICAgICAgICBkZWFkbGluZSxcbiAgICAgIF0pO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBjbGVhclRpbWVvdXQodGltZXIpO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCBjYWxsU3RvcmUoKCkgPT4gdGhpcy5wcmVzZW5jZVN0b3JlLnNodXRkb3duPy4oKSk7XG4gICAgfSBjYXRjaCAoY2F1c2UpIHtcbiAgICAgIHRoaXMudGVsZW1ldHJ5Q29udHJvbGxlci5lbWl0KHtcbiAgICAgICAgbmFtZTogXCJ3cy5yZWdpc3RyeS5zaHV0ZG93bi5mYWlsZWRcIixcbiAgICAgICAgbGV2ZWw6IFwiZXJyb3JcIixcbiAgICAgICAgZGV0YWlsOiB7IGVycm9yVHlwZTogZGVzY3JpYmVFcnJvcihjYXVzZSkgfSxcbiAgICAgIH0pO1xuICAgIH1cbiAgICAvLyDqtazrj4Ug7ZW07KCc64qUIGRyYWlu7J20IOuBneuCrOycvOuvgOuhnCDsponsi5wg7Y+s6riw7ZWgIOyImCDsnojqsowg7J2066+4IOuBneuCnCBkZWFkbGluZeydhCDrhJjquLTri6RcbiAgICBhd2FpdCB0aGlzLmRlbGl2ZXJ5RW5naW5lLnNodXRkb3duKFByb21pc2UucmVzb2x2ZSgpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiDshLjshZjrs4Qg7YGQIOuSpOyXkCBzdG9yZSDtmLjstpzsnYQg7J207Ja0IOu2meyduOuLpC4g7Iuk7Yyo64qUIHRlbGVtZXRyeeuhnOunjCDquLDroZ3tlZjqs6AsIOuwmO2ZmO2VnCBwcm9taXNl64qUIHJlamVjdO2VmOyngCDslYrripTri6QuXG4gICAqL1xuICBwcml2YXRlIGVucXVldWVTdG9yZU11dGF0aW9uKFxuICAgIHNlc3Npb25JZDogc3RyaW5nLFxuICAgIG9wZXJhdGlvbjogU3RvcmVNdXRhdGlvbk9wZXJhdGlvbixcbiAgICBjYWxsOiAoKSA9PiBNYXliZVByb21pc2U8dm9pZD4sXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHByZXZpb3VzID0gdGhpcy5tdXRhdGlvblF1ZXVlcy5nZXQoc2Vzc2lvbklkKSA/PyBQcm9taXNlLnJlc29sdmUoKTtcbiAgICBjb25zdCBuZXh0OiBQcm9taXNlPHZvaWQ+ID0gcHJldmlvdXNcbiAgICAgIC50aGVuKGNhbGwpXG4gICAgICAudGhlbihcbiAgICAgICAgKCkgPT4gdW5kZWZpbmVkLFxuICAgICAgICAoY2F1c2U6IHVua25vd24pID0+IHtcbiAgICAgICAgICB0aGlzLnRlbGVtZXRyeUNvbnRyb2xsZXIuZW1pdCh7XG4gICAgICAgICAgICBuYW1lOiBcIndzLnJlZ2lzdHJ5Lm11dGF0aW9uLmZhaWxlZFwiLFxuICAgICAgICAgICAgbGV2ZWw6IFwid2FyblwiLFxuICAgICAgICAgICAgY29ubmVjdGlvbklkOiBzZXNzaW9uSWQsXG4gICAgICAgICAgICBkZXRhaWw6IHsgb3BlcmF0aW9uLCBlcnJvclR5cGU6IGRlc2NyaWJlRXJyb3IoY2F1c2UpIH0sXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0sXG4gICAgICApXG4gICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgIC8vIOuniOyngOuniSBtdXRhdGlvbuydtCDrgZ3rgpjrqbQg7YGQ66W8IOu5hOybjCDshLjshZgg7IiY66eM7YG8IHByb21pc2XqsIAg7IyT7J207KeAIOyViuqyjCDtlZzri6RcbiAgICAgICAgaWYgKHRoaXMubXV0YXRpb25RdWV1ZXMuZ2V0KHNlc3Npb25JZCkgPT09IG5leHQpIHtcbiAgICAgICAgICB0aGlzLm11dGF0aW9uUXVldWVzLmRlbGV0ZShzZXNzaW9uSWQpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB0aGlzLm11dGF0aW9uUXVldWVzLnNldChzZXNzaW9uSWQsIG5leHQpO1xuICAgIHJldHVybiBuZXh0O1xuICB9XG5cbiAgcHJpdmF0ZSBlbWl0TXV0YXRpb25Ta2lwcGVkKFxuICAgIGNvbm5lY3Rpb25JZDogc3RyaW5nLFxuICAgIGRldGFpbDoge1xuICAgICAgb3BlcmF0aW9uOiBcImFjdGl2YXRlXCIgfCBcInNldFVzZXJJZFwiIHwgXCJjbGVhclVzZXJJZFwiIHwgXCJqb2luXCIgfCBcImxlYXZlXCI7XG4gICAgICByb29tSWQ/OiBXZWJTb2NrZXRSb29tSWQ7XG4gICAgICB1c2VySWQ/OiBXZWJTb2NrZXRVc2VySWQ7XG4gICAgfSxcbiAgKTogdm9pZCB7XG4gICAgdGhpcy50ZWxlbWV0cnlDb250cm9sbGVyLmVtaXQoe1xuICAgICAgbmFtZTogXCJ3cy5yZWdpc3RyeS5tdXRhdGlvbi5za2lwcGVkXCIsXG4gICAgICBsZXZlbDogXCJkZWJ1Z1wiLFxuICAgICAgY29ubmVjdGlvbklkLFxuICAgICAgZGV0YWlsOiB7IC4uLmRldGFpbCwgcmVhc29uOiBcImNvbm5lY3Rpb25NaXNzaW5nXCIgfSxcbiAgICB9KTtcbiAgfVxufVxuXG4vLyBzdG9yZSDtmLjstpzsnZgg64+Z6riwIHRocm9366W8IHJlamVjdGlvbuycvOuhnCDrsJTqvrzri6RcbmZ1bmN0aW9uIGNhbGxTdG9yZTxUPihjYWxsOiAoKSA9PiBNYXliZVByb21pc2U8VD4pOiBQcm9taXNlPFQ+IHtcbiAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oY2FsbCk7XG59XG5cbmZ1bmN0aW9uIGFzc2VydE1hdGNoaW5nTm9kZUlkKFxuICBzb3VyY2U6IFwicHJlc2VuY2VTdG9yZVwiIHwgXCJjbHVzdGVyQnVzXCIsXG4gIHNvdXJjZU5vZGVJZDogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICBub2RlSWQ6IHN0cmluZyxcbik6IHZvaWQge1xuICBpZiAoc291cmNlTm9kZUlkICE9PSB1bmRlZmluZWQgJiYgc291cmNlTm9kZUlkICE9PSBub2RlSWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgV2ViU29ja2V0ICR7c291cmNlfS5ub2RlSWQgKCR7c291cmNlTm9kZUlkfSkgbXVzdCBtYXRjaCB0aGUgcnVudGltZSBub2RlSWQgKCR7bm9kZUlkfSkuYCxcbiAgICApO1xuICB9XG59XG5cbmZ1bmN0aW9uIGRlc2NyaWJlRXJyb3IoY2F1c2U6IHVua25vd24pOiBzdHJpbmcge1xuICByZXR1cm4gY2F1c2UgaW5zdGFuY2VvZiBFcnJvciA/IGNhdXNlLm5hbWUgOiBydW50aW1lVHlwZU9mKGNhdXNlKTtcbn1cblxuZnVuY3Rpb24gZ2V0Q29ubmVjdGlvblRlbGVtZXRyeUNvbnRleHQoXG4gIGNvbm5lY3Rpb246IE1hbmFnZWRXZWJTb2NrZXRDb25uZWN0aW9uIHwgdW5kZWZpbmVkLFxuKTogV2ViU29ja2V0VGVsZW1ldHJ5Q29ubmVjdGlvbkNvbnRleHQge1xuICBpZiAoIWNvbm5lY3Rpb24gfHwgIWlzVGVsZW1ldHJ5Q29udGV4dFByb3ZpZGVyKGNvbm5lY3Rpb24pKSB7XG4gICAgcmV0dXJuIHt9O1xuICB9XG5cbiAgcmV0dXJuIGNvbm5lY3Rpb24uZ2V0VGVsZW1ldHJ5Q29udGV4dCgpO1xufVxuXG4vLyB0ZWxlbWV0cnkgcmVjb3Jk7J2YIHVzZXJJZOuKlCBzdHJpbmcg7KCV6rec7ZmUIOKAlCBwcmVzZW5jZeuKlCBudW1iZXIgfCBzdHJpbmcg6re464yA66GcIOuztOq0gO2VqFxuZnVuY3Rpb24gZm9ybWF0VXNlcklkKHVzZXJJZDogV2ViU29ja2V0VXNlcklkIHwgdW5kZWZpbmVkKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgcmV0dXJuIHVzZXJJZCA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogU3RyaW5nKHVzZXJJZCk7XG59XG5cbmZ1bmN0aW9uIGlzVGVsZW1ldHJ5Q29udGV4dFByb3ZpZGVyKFxuICBjb25uZWN0aW9uOiBNYW5hZ2VkV2ViU29ja2V0Q29ubmVjdGlvbixcbik6IGNvbm5lY3Rpb24gaXMgTWFuYWdlZFdlYlNvY2tldENvbm5lY3Rpb24gJiBUZWxlbWV0cnlDb250ZXh0UHJvdmlkZXIge1xuICByZXR1cm4gXCJnZXRUZWxlbWV0cnlDb250ZXh0XCIgaW4gY29ubmVjdGlvbiAmJiBpc0Z1bmN0aW9uVmFsdWUoY29ubmVjdGlvbi5nZXRUZWxlbWV0cnlDb250ZXh0KTtcbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O0FBMmRBLFNBQVMsVUFBYSxNQUF5QztDQUM3RCxPQUFPLFFBQVEsUUFBUSxDQUFDLENBQUMsS0FBSyxJQUFJO0FBQ3BDO0FBRUEsU0FBUyxxQkFDUCxRQUNBLGNBQ0EsUUFDTTtDQUNOLElBQUksaUJBQWlCLFVBQWEsaUJBQWlCLFFBQ2pELE1BQU0sSUFBSSxNQUNSLGFBQWEsT0FBTyxXQUFXLGFBQWEsbUNBQW1DLE9BQU8sR0FDeEY7QUFFSjtBQUVBLFNBQVMsY0FBYyxPQUF3QjtDQUM3QyxPQUFPLGlCQUFpQixRQUFRLE1BQU0sT0FBTyxjQUFjLEtBQUs7QUFDbEU7QUFFQSxTQUFTLDhCQUNQLFlBQ3FDO0NBQ3JDLElBQUksQ0FBQyxjQUFjLENBQUMsMkJBQTJCLFVBQVUsR0FDdkQsT0FBTyxDQUFDO0NBR1YsT0FBTyxXQUFXLG9CQUFvQjtBQUN4QztBQUdBLFNBQVMsYUFBYSxRQUF5RDtDQUM3RSxPQUFPLFdBQVcsU0FBWSxTQUFZLE9BQU8sTUFBTTtBQUN6RDtBQUVBLFNBQVMsMkJBQ1AsWUFDcUU7Q0FDckUsT0FBTyx5QkFBeUIsY0FBYyxnQkFBZ0IsV0FBVyxtQkFBbUI7QUFDOUY7OztDQWhnQitDLGtCQUFBO0NBQ1MsbUJBQUE7Q0FDMEMsaUJBQUE7Q0FDaEMsMEJBQUE7Q0FDa0Isb0JBQUE7Q0FTRSxpQkFBQTtDQUNYLCtCQUFBO0NBQ2YsdUJBQUE7Q0FLaEMsdUJBQUE7Q0FNTCxrQkFBQTtDQWVqQiwyQkFBMkI7Q0F5QnBCLG9CQUFiLE1BQStCO0VBQzdCO0VBQ0EsbUJBQTRCLElBQUksOEJBQThCO0VBQzlEO0VBQ0E7RUFDQTtFQUNBLFNBQTBCLElBQUksdUJBQXVCO0VBQ3JEO0VBQ0E7RUFFQSxpQ0FBa0MsSUFBSSxJQUEyQjtFQUVqRSxZQUFZLFNBQW1DO0dBQzdDLEtBQUssU0FBUyxRQUFRO0dBQ3RCLEtBQUssZ0JBQWdCLFFBQVEsaUJBQWlCLElBQUksK0JBQStCO0dBQ2pGLEtBQUssYUFBYSxRQUFRLGNBQWMsSUFBSSx3QkFBd0I7R0FDcEUsS0FBSyxpQkFBaUIsUUFBUSxrQkFBa0I7R0FDaEQscUJBQXFCLGlCQUFpQixLQUFLLGNBQWMsUUFBUSxLQUFLLE1BQU07R0FDNUUscUJBQXFCLGNBQWMsS0FBSyxXQUFXLFFBQVEsS0FBSyxNQUFNO0dBQ3RFLEtBQUssc0JBQ0gsUUFBUSx1QkFBdUIsSUFBSSxpQ0FBaUM7R0FDdEUsS0FBSyxpQkFBaUIsSUFBSSx3QkFBd0I7SUFDaEQsUUFBUSxLQUFLO0lBQ2Isa0JBQWtCLEtBQUs7SUFDdkIseUJBQXlCLGFBQ3ZCLEtBQUssT0FBTyxjQUFjLFFBQVEsQ0FBQyxDQUFDLEtBQUssWUFBWSxRQUFRLFNBQVM7SUFDeEUsa0JBQWtCLElBQUksMEJBQTBCO0tBQzlDLFFBQVEsS0FBSztLQUNiLGVBQWUsS0FBSztJQUN0QixDQUFDO0lBQ0QsWUFBWSxLQUFLO0lBQ2pCLHFCQUFxQixLQUFLO0dBQzVCLENBQUM7R0FHRCxLQUFLLG9CQUFvQixxQkFBcUIsRUFDNUMsVUFBVSxTQUFTO0lBQ2pCLE1BQU0sUUFBUSxLQUFLLE9BQU8sU0FBUztJQUNuQyxNQUFNLGdCQUFnQixLQUFLLGlCQUFpQixxQkFBcUI7SUFDakUsT0FBTztLQUNMLG1CQUFtQixNQUFNO0tBQ3pCLDhCQUE4QixNQUFNO0tBQ3BDLFdBQVcsTUFBTTtLQUNqQix3QkFBd0IsY0FBYztLQUN0Qyx5QkFBeUIsY0FBYztLQUN2QyxxQkFBcUIsY0FBYztJQUNyQztHQUNGLEVBQ0YsQ0FBQztFQUNIO0VBRUEsY0FBYyxVQUFrQixXQUE4QjtHQUM1RCxLQUFLLGVBQWUsY0FBYyxVQUFVLFNBQVM7RUFDdkQ7RUFFQSxjQUFjLFFBQTBDO0dBQ3RELEtBQUssZUFBZSxjQUFjLE1BQU07RUFDMUM7Ozs7O0VBTUEsTUFBTSxTQUNKLFlBQ0EsU0FBa0IsTUFDZ0I7R0FDbEMsTUFBTSxlQUFlO0lBQ25CLFdBQVcsV0FBVztJQUN0QixRQUFRLEtBQUs7SUFDYixXQUFXLFdBQVc7SUFDdEI7SUFDQSw2QkFBYSxJQUFJLEtBQUs7R0FDeEI7R0FDQSxLQUFLLGlCQUFpQixTQUFTLFVBQVU7R0FDekMsS0FBSyxPQUFPLFNBQVMsWUFBWTtHQUNqQyxLQUFLLG9CQUFvQixLQUFLO0lBQzVCLE1BQU07SUFDTixPQUFPO0lBQ1AsY0FBYyxXQUFXO0lBQ3pCLFdBQVcsV0FBVztJQUN0QixRQUFRLFdBQVc7SUFDbkIsR0FBRyw4QkFBOEIsVUFBVTtHQUM3QyxDQUFDO0dBQ0QsS0FBSyxvQkFBb0IsYUFBYTtJQUNwQyxNQUFNO0lBQ04sTUFBTTtJQUNOLE9BQU87SUFDUCxNQUFNO0lBQ04sTUFBTTtLQUFFLFNBQVM7S0FBYyxXQUFXLFdBQVc7SUFBVTtJQUMvRCxRQUFRLFdBQVc7R0FDckIsQ0FBQztHQUVELE1BQU0sS0FBSyxxQkFBcUIsV0FBVyxJQUFJLGtCQUM3QyxLQUFLLGNBQWMsU0FBUyxZQUFZLENBQzFDO0dBRUEsT0FDRSxLQUFLLE9BQU8sY0FBYyxXQUFXLEVBQUUsS0FBSztJQUMxQyxHQUFHO0lBQ0gsdUJBQU8sSUFBSSxJQUFJO0lBQ2YsWUFBWSxhQUFhO0dBQzNCO0VBRUo7RUFFQSxTQUFTLGNBQXFDO0dBQzVDLElBQUksQ0FBQyxLQUFLLE9BQU8sSUFBSSxZQUFZLEdBQUc7SUFDbEMsS0FBSyxvQkFBb0IsY0FBYyxFQUFFLFdBQVcsV0FBVyxDQUFDO0lBQ2hFLE9BQU8sUUFBUSxRQUFRO0dBQ3pCO0dBRUEsS0FBSyxPQUFPLFNBQVMsWUFBWTtHQUNqQyxNQUFNLGFBQWEsS0FBSyxpQkFBaUIsY0FBYyxZQUFZO0dBQ25FLEtBQUssb0JBQW9CLEtBQUs7SUFDNUIsTUFBTTtJQUNOLE9BQU87SUFDUDtJQUNBLFFBQVEsWUFBWTtJQUNwQixHQUFHLDhCQUE4QixVQUFVO0dBQzdDLENBQUM7R0FDRCxPQUFPLEtBQUsscUJBQXFCLGNBQWMsa0JBQzdDLEtBQUssY0FBYyxTQUFTLFlBQVksQ0FDMUM7RUFDRjtFQUVBLFdBQVcsY0FBcUM7R0FDOUMsTUFBTSxhQUFhLEtBQUssaUJBQWlCLGNBQWMsWUFBWTtHQUNuRSxNQUFNLG1CQUFtQiw4QkFBOEIsVUFBVTtHQUNqRSxNQUFNLE9BQU8sS0FBSyxPQUFPLFdBQVcsWUFBWTtHQUNoRCxNQUFNLFNBQVMsWUFBWSxVQUFVLGFBQWEsTUFBTSxNQUFNO0dBQzlELEtBQUssaUJBQWlCLFdBQVcsWUFBWTtHQUM3QyxLQUFLLG9CQUFvQixLQUFLO0lBQzVCLE1BQU07SUFDTixPQUFPO0lBQ1A7SUFDQSxXQUFXLE1BQU07SUFDakI7SUFDQSxHQUFHO0dBQ0wsQ0FBQztHQUNELElBQUksQ0FBQyxNQUNILE9BQU8sUUFBUSxRQUFRO0dBR3pCLEtBQUssb0JBQW9CLGFBQWE7SUFDcEMsTUFBTTtJQUNOLE1BQU07SUFDTixPQUFPO0lBQ1AsTUFBTTtJQUNOLE1BQU07S0FBRSxTQUFTO0tBQWdCLFdBQVcsS0FBSztJQUFVO0lBQzNEO0dBQ0YsQ0FBQztHQUVELE9BQU8sS0FBSyxxQkFBcUIsY0FBYyxvQkFDN0MsS0FBSyxjQUFjLFdBQVcsWUFBWSxDQUM1QztFQUNGO0VBR0EsTUFBTSxjQUE0QjtHQUNoQyxLQUFLLE9BQU8sTUFBTSxZQUFZO0VBQ2hDO0VBRUEsVUFBVSxjQUFzQixRQUF3QztHQUN0RSxNQUFNLE9BQU8sS0FBSyxPQUFPLGNBQWMsWUFBWTtHQUNuRCxJQUFJLENBQUMsTUFBTTtJQUNULEtBQUssb0JBQW9CLGNBQWM7S0FBRSxXQUFXO0tBQWE7SUFBTyxDQUFDO0lBQ3pFLE9BQU8sUUFBUSxRQUFRO0dBQ3pCO0dBRUEsS0FBSyxPQUFPLFVBQVUsY0FBYyxNQUFNO0dBQzFDLEtBQUssb0JBQW9CLEtBQUs7SUFDNUIsTUFBTTtJQUNOLE9BQU87SUFDUDtJQUNBLFdBQVcsS0FBSztJQUNoQixRQUFRLE9BQU8sTUFBTTtJQUNyQixRQUFRLEVBQUUsT0FBTztJQUNqQixHQUFHLDhCQUE4QixLQUFLLGlCQUFpQixjQUFjLFlBQVksQ0FBQztHQUNwRixDQUFDO0dBQ0QsT0FBTyxLQUFLLHFCQUFxQixjQUFjLG1CQUM3QyxLQUFLLGNBQWMsVUFBVSxjQUFjLE1BQU0sQ0FDbkQ7RUFDRjtFQUVBLFlBQVksY0FBcUM7R0FDL0MsTUFBTSxPQUFPLEtBQUssT0FBTyxjQUFjLFlBQVk7R0FDbkQsSUFBSSxDQUFDLE1BQU07SUFDVCxLQUFLLG9CQUFvQixjQUFjLEVBQUUsV0FBVyxjQUFjLENBQUM7SUFDbkUsT0FBTyxRQUFRLFFBQVE7R0FDekI7R0FFQSxNQUFNLFNBQVMsS0FBSztHQUNwQixLQUFLLE9BQU8sWUFBWSxZQUFZO0dBQ3BDLEtBQUssb0JBQW9CLEtBQUs7SUFDNUIsTUFBTTtJQUNOLE9BQU87SUFDUDtJQUNBLFdBQVcsS0FBSztJQUNoQixRQUFRLGFBQWEsTUFBTTtJQUMzQixRQUFRLFdBQVcsU0FBWSxFQUFFLE9BQU8sSUFBSTtJQUM1QyxHQUFHLDhCQUE4QixLQUFLLGlCQUFpQixjQUFjLFlBQVksQ0FBQztHQUNwRixDQUFDO0dBQ0QsT0FBTyxLQUFLLHFCQUFxQixjQUFjLHFCQUM3QyxLQUFLLGNBQWMsWUFBWSxZQUFZLENBQzdDO0VBQ0Y7RUFFQSxLQUFLLGNBQXNCLFFBQXdDO0dBQ2pFLE1BQU0sT0FBTyxLQUFLLE9BQU8sY0FBYyxZQUFZO0dBQ25ELElBQUksQ0FBQyxNQUFNO0lBQ1QsS0FBSyxvQkFBb0IsY0FBYztLQUFFLFdBQVc7S0FBUTtJQUFPLENBQUM7SUFDcEUsT0FBTyxRQUFRLFFBQVE7R0FDekI7R0FFQSxLQUFLLE9BQU8sS0FBSyxjQUFjLE1BQU07R0FDckMsTUFBTSxhQUFhLEtBQUssaUJBQWlCLGNBQWMsWUFBWTtHQUNuRSxLQUFLLG9CQUFvQixLQUFLO0lBQzVCLE1BQU07SUFDTixPQUFPO0lBQ1A7SUFDQSxXQUFXLEtBQUs7SUFDaEIsUUFBUSxZQUFZLFVBQVUsYUFBYSxLQUFLLE1BQU07SUFDdEQsUUFBUSxFQUFFLE9BQU87SUFDakIsR0FBRyw4QkFBOEIsVUFBVTtHQUM3QyxDQUFDO0dBQ0QsT0FBTyxLQUFLLHFCQUFxQixjQUFjLGNBQzdDLEtBQUssY0FBYyxLQUFLLGNBQWMsTUFBTSxDQUM5QztFQUNGO0VBRUEsTUFBTSxjQUFzQixRQUF3QztHQUNsRSxNQUFNLE9BQU8sS0FBSyxPQUFPLGNBQWMsWUFBWTtHQUNuRCxJQUFJLENBQUMsTUFBTTtJQUNULEtBQUssb0JBQW9CLGNBQWM7S0FBRSxXQUFXO0tBQVM7SUFBTyxDQUFDO0lBQ3JFLE9BQU8sUUFBUSxRQUFRO0dBQ3pCO0dBRUEsS0FBSyxPQUFPLE1BQU0sY0FBYyxNQUFNO0dBQ3RDLE1BQU0sYUFBYSxLQUFLLGlCQUFpQixjQUFjLFlBQVk7R0FDbkUsS0FBSyxvQkFBb0IsS0FBSztJQUM1QixNQUFNO0lBQ04sT0FBTztJQUNQO0lBQ0EsV0FBVyxLQUFLO0lBQ2hCLFFBQVEsWUFBWSxVQUFVLGFBQWEsS0FBSyxNQUFNO0lBQ3RELFFBQVEsRUFBRSxPQUFPO0lBQ2pCLEdBQUcsOEJBQThCLFVBQVU7R0FDN0MsQ0FBQztHQUNELE9BQU8sS0FBSyxxQkFBcUIsY0FBYyxlQUM3QyxLQUFLLGNBQWMsTUFBTSxjQUFjLE1BQU0sQ0FDL0M7RUFDRjtFQUVBLFVBQWdCLE9BQWUsTUFBWSxXQUFtQztHQUM1RSxPQUFPLEtBQUssa0JBQWtCLGtCQUFrQixJQUFJLFNBQVMsR0FBRyxPQUFPLElBQUk7RUFDN0U7RUFFQSxjQUNFLFFBQ0EsT0FDQSxNQUNBLFdBQ2U7R0FDZixPQUFPLEtBQUssa0JBQWtCLGtCQUFrQixLQUFLLFFBQVEsU0FBUyxHQUFHLE9BQU8sSUFBSTtFQUN0RjtFQUVBLGNBQ0UsUUFDQSxPQUNBLE1BQ0EsV0FDZTtHQUNmLE9BQU8sS0FBSyxrQkFBa0Isa0JBQWtCLEtBQUssUUFBUSxTQUFTLEdBQUcsT0FBTyxJQUFJO0VBQ3RGO0VBRUEsa0JBQ0UsVUFDQSxPQUNBLE1BQ2U7R0FDZixPQUFPLEtBQUssZUFBZSxrQkFBa0IsVUFBVSxPQUFPLElBQUk7RUFDcEU7RUFHQSxjQUFjLGNBQTJEO0dBQ3ZFLE9BQU8sS0FBSyxPQUFPLGNBQWMsWUFBWTtFQUMvQztFQUVBLG1CQUFtQixXQUE0QjtHQUM3QyxPQUFPLEtBQUssT0FBTyxtQkFBbUIsU0FBUztFQUNqRDtFQUVBLGVBQWUsUUFBeUIsV0FBK0M7R0FDckYsT0FBTyxLQUFLLE9BQU8sZUFBZSxRQUFRLFNBQVM7RUFDckQ7RUFFQSxXQUFtQztHQUNqQyxPQUFPLEtBQUssT0FBTyxTQUFTO0VBQzlCOzs7O0VBS0EsTUFBTSxtQkFDSixRQUNBLFdBQ21DO0dBQ25DLElBQUk7SUFFRixPQUFPO0tBQUUsYUFEVyxnQkFBZ0IsS0FBSyxjQUFjLG1CQUFtQixRQUFRLFNBQVMsQ0FBQztLQUM1RSxTQUFTO0lBQU07R0FDakMsU0FBUyxPQUFPO0lBQ2QsS0FBSyxvQkFBb0IsS0FBSztLQUM1QixNQUFNO0tBQ04sT0FBTztLQUNQLFFBQVE7TUFBRSxXQUFXO01BQXNCO01BQVEsV0FBVyxjQUFjLEtBQUs7S0FBRTtJQUNyRixDQUFDO0lBQ0QsT0FBTztLQUFFLE9BQU8sS0FBSyxPQUFPLG1CQUFtQixRQUFRLFNBQVM7S0FBRyxTQUFTO0lBQUs7R0FDbkY7RUFDRjtFQUVBLFNBQVMsTUFBZSxRQUF1QjtHQUM3QyxLQUFLLGlCQUFpQixTQUFTLE1BQU0sTUFBTTtFQUM3Qzs7OztFQUtBLE1BQU0sU0FBUyxNQUFlLFFBQWdDO0dBQzVELEtBQUssU0FBUyxNQUFNLE1BQU07R0FFMUIsSUFBSTtHQUNKLE1BQU0sV0FBVyxJQUFJLFNBQWUsWUFBWTtJQUM5QyxRQUFRLFdBQVcsU0FBUyxLQUFLLGNBQWM7R0FDakQsQ0FBQztHQUNELElBQUk7SUFDRixNQUFNLFFBQVEsS0FBSyxDQUNqQixRQUFRLElBQUksQ0FBQyxHQUFHLEtBQUssZUFBZSxPQUFPLEdBQUcsS0FBSyxlQUFlLGVBQWUsQ0FBQyxDQUFDLEdBQ25GLFFBQ0YsQ0FBQztHQUNILFVBQVU7SUFDUixhQUFhLEtBQUs7R0FDcEI7R0FFQSxJQUFJO0lBQ0YsTUFBTSxnQkFBZ0IsS0FBSyxjQUFjLFdBQVcsQ0FBQztHQUN2RCxTQUFTLE9BQU87SUFDZCxLQUFLLG9CQUFvQixLQUFLO0tBQzVCLE1BQU07S0FDTixPQUFPO0tBQ1AsUUFBUSxFQUFFLFdBQVcsY0FBYyxLQUFLLEVBQUU7SUFDNUMsQ0FBQztHQUNIO0dBRUEsTUFBTSxLQUFLLGVBQWUsU0FBUyxRQUFRLFFBQVEsQ0FBQztFQUN0RDs7OztFQUtBLHFCQUNFLFdBQ0EsV0FDQSxNQUNlO0dBRWYsTUFBTSxRQURXLEtBQUssZUFBZSxJQUFJLFNBQVMsS0FBSyxRQUFRLFFBQVEsRUFDM0MsQ0FDekIsS0FBSyxJQUFJLENBQUMsQ0FDVixXQUNPLFNBQ0wsVUFBbUI7SUFDbEIsS0FBSyxvQkFBb0IsS0FBSztLQUM1QixNQUFNO0tBQ04sT0FBTztLQUNQLGNBQWM7S0FDZCxRQUFRO01BQUU7TUFBVyxXQUFXLGNBQWMsS0FBSztLQUFFO0lBQ3ZELENBQUM7R0FDSCxDQUNGLENBQUMsQ0FDQSxXQUFXO0lBRVYsSUFBSSxLQUFLLGVBQWUsSUFBSSxTQUFTLE1BQU0sTUFDekMsS0FBSyxlQUFlLE9BQU8sU0FBUztHQUV4QyxDQUFDO0dBQ0gsS0FBSyxlQUFlLElBQUksV0FBVyxJQUFJO0dBQ3ZDLE9BQU87RUFDVDtFQUVBLG9CQUNFLGNBQ0EsUUFLTTtHQUNOLEtBQUssb0JBQW9CLEtBQUs7SUFDNUIsTUFBTTtJQUNOLE9BQU87SUFDUDtJQUNBLFFBQVE7S0FBRSxHQUFHO0tBQVEsUUFBUTtJQUFvQjtHQUNuRCxDQUFDO0VBQ0g7Q0FDRiJ9
|