@dbx-tools/postgres 0.6.81 → 0.6.85

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/index.ts CHANGED
@@ -3,8 +3,10 @@
3
3
  // Hand edits are overwritten on the next watch; this file is read-only.
4
4
 
5
5
  export * as advisoryLock from "./src/advisory-lock.ts";
6
+ export * as persistence from "./src/persistence.ts";
6
7
  export * as topicBus from "./src/topic-bus.ts";
7
8
  export type { AdvisoryLockKey, PgPoolLike, PgQueryable } from "./src/advisory-lock.ts";
9
+ export type { DurationInput, ResolvedTopicBusPersistenceOptions } from "./src/persistence.ts";
8
10
  export { PostgresTopicBus } from "./src/topic-bus.ts";
9
11
  export type { TopicMetadata, TopicMessage, TopicPublishInput, TopicListener, TopicMetadataProvider, PostgresTopicBusOptions } from "./src/topic-bus.ts";
10
12
  export * from "./exports.ts";
package/lib/exports.d.ts CHANGED
@@ -1 +1,3 @@
1
1
  export { advisoryLockId, withAdvisoryLock, withAdvisoryTransactionLock, } from "./src/advisory-lock.ts";
2
+ export { messageBusGrantStatements, provisionMessageBusSchema, resolvePersistenceOptions } from "./src/persistence.ts";
3
+ export type { TopicPersistenceScope, TopicBusPersistenceOptions, StoredTopicMessage, TopicHistoryPage } from "./src/persistence.ts";
package/lib/exports.js CHANGED
@@ -3,4 +3,5 @@
3
3
  // functions to the package root. These are the call-site names, so they are
4
4
  // importable directly from `@dbx-tools/postgres`.
5
5
  export { advisoryLockId, withAdvisoryLock, withAdvisoryTransactionLock, } from "./src/advisory-lock.js";
6
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhwb3J0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL2V4cG9ydHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsZ0ZBQWdGO0FBQ2hGLDRFQUE0RTtBQUM1RSw0RUFBNEU7QUFDNUUsa0RBQWtEO0FBQ2xELE9BQU8sRUFDTCxjQUFjLEVBQ2QsZ0JBQWdCLEVBQ2hCLDJCQUEyQixHQUM1QixNQUFNLHdCQUF3QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gRmxhdCByZS1leHBvcnRzIGxheWVyZWQgb250byB0aGUgZ2VuZXJhdGVkIGBpbmRleC50c2AgYmFycmVsLCB3aGljaCBwdWJsaXNoZXNcbi8vIGVhY2ggbW9kdWxlIGFzIGEgbmFtZXNwYWNlIChgYWR2aXNvcnlMb2NrYCwgYHRvcGljQnVzYCkgYW5kIGRvZXMgbm90IGxpZnRcbi8vIGZ1bmN0aW9ucyB0byB0aGUgcGFja2FnZSByb290LiBUaGVzZSBhcmUgdGhlIGNhbGwtc2l0ZSBuYW1lcywgc28gdGhleSBhcmVcbi8vIGltcG9ydGFibGUgZGlyZWN0bHkgZnJvbSBgQGRieC10b29scy9wb3N0Z3Jlc2AuXG5leHBvcnQge1xuICBhZHZpc29yeUxvY2tJZCxcbiAgd2l0aEFkdmlzb3J5TG9jayxcbiAgd2l0aEFkdmlzb3J5VHJhbnNhY3Rpb25Mb2NrLFxufSBmcm9tIFwiLi9zcmMvYWR2aXNvcnktbG9jay50c1wiO1xuIl19
6
+ export { messageBusGrantStatements, provisionMessageBusSchema, resolvePersistenceOptions } from "./src/persistence.js";
7
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhwb3J0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL2V4cG9ydHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsZ0ZBQWdGO0FBQ2hGLDRFQUE0RTtBQUM1RSw0RUFBNEU7QUFDNUUsa0RBQWtEO0FBQ2xELE9BQU8sRUFDTCxjQUFjLEVBQ2QsZ0JBQWdCLEVBQ2hCLDJCQUEyQixHQUM1QixNQUFNLHdCQUF3QixDQUFDO0FBQ2hDLE9BQU8sRUFBRSx5QkFBeUIsRUFBRSx5QkFBeUIsRUFBRSx5QkFBeUIsRUFBRSxNQUFNLHNCQUFzQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gRmxhdCByZS1leHBvcnRzIGxheWVyZWQgb250byB0aGUgZ2VuZXJhdGVkIGBpbmRleC50c2AgYmFycmVsLCB3aGljaCBwdWJsaXNoZXNcbi8vIGVhY2ggbW9kdWxlIGFzIGEgbmFtZXNwYWNlIChgYWR2aXNvcnlMb2NrYCwgYHRvcGljQnVzYCkgYW5kIGRvZXMgbm90IGxpZnRcbi8vIGZ1bmN0aW9ucyB0byB0aGUgcGFja2FnZSByb290LiBUaGVzZSBhcmUgdGhlIGNhbGwtc2l0ZSBuYW1lcywgc28gdGhleSBhcmVcbi8vIGltcG9ydGFibGUgZGlyZWN0bHkgZnJvbSBgQGRieC10b29scy9wb3N0Z3Jlc2AuXG5leHBvcnQge1xuICBhZHZpc29yeUxvY2tJZCxcbiAgd2l0aEFkdmlzb3J5TG9jayxcbiAgd2l0aEFkdmlzb3J5VHJhbnNhY3Rpb25Mb2NrLFxufSBmcm9tIFwiLi9zcmMvYWR2aXNvcnktbG9jay50c1wiO1xuZXhwb3J0IHsgbWVzc2FnZUJ1c0dyYW50U3RhdGVtZW50cywgcHJvdmlzaW9uTWVzc2FnZUJ1c1NjaGVtYSwgcmVzb2x2ZVBlcnNpc3RlbmNlT3B0aW9ucyB9IGZyb20gXCIuL3NyYy9wZXJzaXN0ZW5jZS50c1wiO1xuZXhwb3J0IHR5cGUgeyBUb3BpY1BlcnNpc3RlbmNlU2NvcGUsIFRvcGljQnVzUGVyc2lzdGVuY2VPcHRpb25zLCBTdG9yZWRUb3BpY01lc3NhZ2UsIFRvcGljSGlzdG9yeVBhZ2UgfSBmcm9tIFwiLi9zcmMvcGVyc2lzdGVuY2UudHNcIjtcbiJdfQ==
package/lib/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  export * as advisoryLock from "./src/advisory-lock.ts";
2
+ export * as persistence from "./src/persistence.ts";
2
3
  export * as topicBus from "./src/topic-bus.ts";
3
4
  export type { AdvisoryLockKey, PgPoolLike, PgQueryable } from "./src/advisory-lock.ts";
5
+ export type { DurationInput, ResolvedTopicBusPersistenceOptions } from "./src/persistence.ts";
4
6
  export { PostgresTopicBus } from "./src/topic-bus.ts";
5
7
  export type { TopicMetadata, TopicMessage, TopicPublishInput, TopicListener, TopicMetadataProvider, PostgresTopicBusOptions } from "./src/topic-bus.ts";
6
8
  export * from "./exports.ts";
package/lib/index.js CHANGED
@@ -2,7 +2,8 @@
2
2
  // Regenerated from the exporting modules in ./src.
3
3
  // Hand edits are overwritten on the next watch; this file is read-only.
4
4
  export * as advisoryLock from "./src/advisory-lock.js";
5
+ export * as persistence from "./src/persistence.js";
5
6
  export * as topicBus from "./src/topic-bus.js";
6
7
  export { PostgresTopicBus } from "./src/topic-bus.js";
7
8
  export * from "./exports.js";
8
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwyQ0FBMkM7QUFDM0MsbURBQW1EO0FBQ25ELHdFQUF3RTtBQUV4RSxPQUFPLEtBQUssWUFBWSxNQUFNLHdCQUF3QixDQUFDO0FBQ3ZELE9BQU8sS0FBSyxRQUFRLE1BQU0sb0JBQW9CLENBQUM7QUFFL0MsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFFdEQsY0FBYyxjQUFjLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBHRU5FUkFURUQgYnkgcHJvamVuIHdhdGNoIC0gRE8gTk9UIEVESVQuXG4vLyBSZWdlbmVyYXRlZCBmcm9tIHRoZSBleHBvcnRpbmcgbW9kdWxlcyBpbiAuL3NyYy5cbi8vIEhhbmQgZWRpdHMgYXJlIG92ZXJ3cml0dGVuIG9uIHRoZSBuZXh0IHdhdGNoOyB0aGlzIGZpbGUgaXMgcmVhZC1vbmx5LlxuXG5leHBvcnQgKiBhcyBhZHZpc29yeUxvY2sgZnJvbSBcIi4vc3JjL2Fkdmlzb3J5LWxvY2sudHNcIjtcbmV4cG9ydCAqIGFzIHRvcGljQnVzIGZyb20gXCIuL3NyYy90b3BpYy1idXMudHNcIjtcbmV4cG9ydCB0eXBlIHsgQWR2aXNvcnlMb2NrS2V5LCBQZ1Bvb2xMaWtlLCBQZ1F1ZXJ5YWJsZSB9IGZyb20gXCIuL3NyYy9hZHZpc29yeS1sb2NrLnRzXCI7XG5leHBvcnQgeyBQb3N0Z3Jlc1RvcGljQnVzIH0gZnJvbSBcIi4vc3JjL3RvcGljLWJ1cy50c1wiO1xuZXhwb3J0IHR5cGUgeyBUb3BpY01ldGFkYXRhLCBUb3BpY01lc3NhZ2UsIFRvcGljUHVibGlzaElucHV0LCBUb3BpY0xpc3RlbmVyLCBUb3BpY01ldGFkYXRhUHJvdmlkZXIsIFBvc3RncmVzVG9waWNCdXNPcHRpb25zIH0gZnJvbSBcIi4vc3JjL3RvcGljLWJ1cy50c1wiO1xuZXhwb3J0ICogZnJvbSBcIi4vZXhwb3J0cy50c1wiO1xuIl19
9
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwyQ0FBMkM7QUFDM0MsbURBQW1EO0FBQ25ELHdFQUF3RTtBQUV4RSxPQUFPLEtBQUssWUFBWSxNQUFNLHdCQUF3QixDQUFDO0FBQ3ZELE9BQU8sS0FBSyxXQUFXLE1BQU0sc0JBQXNCLENBQUM7QUFDcEQsT0FBTyxLQUFLLFFBQVEsTUFBTSxvQkFBb0IsQ0FBQztBQUcvQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUV0RCxjQUFjLGNBQWMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIEdFTkVSQVRFRCBieSBwcm9qZW4gd2F0Y2ggLSBETyBOT1QgRURJVC5cbi8vIFJlZ2VuZXJhdGVkIGZyb20gdGhlIGV4cG9ydGluZyBtb2R1bGVzIGluIC4vc3JjLlxuLy8gSGFuZCBlZGl0cyBhcmUgb3ZlcndyaXR0ZW4gb24gdGhlIG5leHQgd2F0Y2g7IHRoaXMgZmlsZSBpcyByZWFkLW9ubHkuXG5cbmV4cG9ydCAqIGFzIGFkdmlzb3J5TG9jayBmcm9tIFwiLi9zcmMvYWR2aXNvcnktbG9jay50c1wiO1xuZXhwb3J0ICogYXMgcGVyc2lzdGVuY2UgZnJvbSBcIi4vc3JjL3BlcnNpc3RlbmNlLnRzXCI7XG5leHBvcnQgKiBhcyB0b3BpY0J1cyBmcm9tIFwiLi9zcmMvdG9waWMtYnVzLnRzXCI7XG5leHBvcnQgdHlwZSB7IEFkdmlzb3J5TG9ja0tleSwgUGdQb29sTGlrZSwgUGdRdWVyeWFibGUgfSBmcm9tIFwiLi9zcmMvYWR2aXNvcnktbG9jay50c1wiO1xuZXhwb3J0IHR5cGUgeyBEdXJhdGlvbklucHV0LCBSZXNvbHZlZFRvcGljQnVzUGVyc2lzdGVuY2VPcHRpb25zIH0gZnJvbSBcIi4vc3JjL3BlcnNpc3RlbmNlLnRzXCI7XG5leHBvcnQgeyBQb3N0Z3Jlc1RvcGljQnVzIH0gZnJvbSBcIi4vc3JjL3RvcGljLWJ1cy50c1wiO1xuZXhwb3J0IHR5cGUgeyBUb3BpY01ldGFkYXRhLCBUb3BpY01lc3NhZ2UsIFRvcGljUHVibGlzaElucHV0LCBUb3BpY0xpc3RlbmVyLCBUb3BpY01ldGFkYXRhUHJvdmlkZXIsIFBvc3RncmVzVG9waWNCdXNPcHRpb25zIH0gZnJvbSBcIi4vc3JjL3RvcGljLWJ1cy50c1wiO1xuZXhwb3J0ICogZnJvbSBcIi4vZXhwb3J0cy50c1wiO1xuIl19
@@ -0,0 +1,44 @@
1
+ import { object } from "@dbx-tools/shared-core";
2
+ import type { PgPoolLike, PgQueryable } from "./advisory-lock.ts";
3
+ import type { TopicMessage } from "./topic-bus.ts";
4
+ export type TopicPersistenceScope = "open" | "restricted";
5
+ export type DurationInput = string | number;
6
+ export interface TopicBusPersistenceOptions {
7
+ schema?: string;
8
+ scope?: TopicPersistenceScope;
9
+ tables?: Partial<Record<TopicPersistenceScope, string>>;
10
+ ttl?: DurationInput | false;
11
+ payload?: "envelope" | "pointer";
12
+ cleanupBatchSize?: number;
13
+ provision?: boolean;
14
+ }
15
+ export interface ResolvedTopicBusPersistenceOptions {
16
+ schema: string;
17
+ scope: TopicPersistenceScope;
18
+ tables: Record<TopicPersistenceScope, string>;
19
+ ttl: DurationInput | false;
20
+ payload: "envelope" | "pointer";
21
+ cleanupBatchSize: number;
22
+ provision: boolean;
23
+ }
24
+ export interface StoredTopicMessage<TBody extends object.SerializableValue = object.SerializableValue> {
25
+ cursor: string;
26
+ expiresAt: string | null;
27
+ scope: TopicPersistenceScope;
28
+ message: TopicMessage<TBody>;
29
+ }
30
+ export interface TopicHistoryPage<TBody extends object.SerializableValue = object.SerializableValue> {
31
+ messages: StoredTopicMessage<TBody>[];
32
+ nextCursor?: string;
33
+ }
34
+ export declare function resolvePersistenceOptions(value: true | TopicBusPersistenceOptions): ResolvedTopicBusPersistenceOptions;
35
+ export declare function provisionMessageBusSchema(pool: PgPoolLike, options: ResolvedTopicBusPersistenceOptions): Promise<void>;
36
+ export declare function messageBusGrantStatements(roles: string | readonly string[], scope: TopicPersistenceScope, options: ResolvedTopicBusPersistenceOptions): string[];
37
+ export declare function ttlMilliseconds(value: DurationInput | false): number | null;
38
+ export declare function cleanupExpired(queryable: PgQueryable, options: ResolvedTopicBusPersistenceOptions, scope: TopicPersistenceScope, limit?: number): Promise<number>;
39
+ export declare function history<TBody extends object.SerializableValue>(queryable: PgQueryable, channel: string, topic: string, options: ResolvedTopicBusPersistenceOptions, input?: {
40
+ after?: string;
41
+ limit?: number;
42
+ scope?: TopicPersistenceScope;
43
+ }): Promise<TopicHistoryPage<TBody>>;
44
+ export declare function persistedNotify(client: PgQueryable, channel: string, topic: string, message: TopicMessage, encoded: string, options: ResolvedTopicBusPersistenceOptions, scope: TopicPersistenceScope, ttl: DurationInput | false): Promise<void>;
@@ -0,0 +1,78 @@
1
+ import { object } from "@dbx-tools/shared-core";
2
+ import { withAdvisoryTransactionLock } from "./advisory-lock.js";
3
+ const DEFAULT_TTL = "24 hours";
4
+ const quote = (value) => `"${value.replaceAll('"', '""')}"`;
5
+ const table = (options, scope) => `${quote(options.schema)}.${quote(options.tables[scope])}`;
6
+ export function resolvePersistenceOptions(value) {
7
+ const configured = value === true ? {} : value;
8
+ const scope = configured.scope ?? "open";
9
+ if (scope !== "open" && scope !== "restricted")
10
+ throw new TypeError(`Unknown persistence scope: ${String(scope)}`);
11
+ return {
12
+ schema: configured.schema ?? "dbx_message_bus",
13
+ scope,
14
+ tables: { open: configured.tables?.open ?? "open_messages", restricted: configured.tables?.restricted ?? "restricted_messages" },
15
+ ttl: configured.ttl ?? DEFAULT_TTL,
16
+ payload: configured.payload ?? "envelope",
17
+ cleanupBatchSize: configured.cleanupBatchSize ?? 1000,
18
+ provision: configured.provision ?? true,
19
+ };
20
+ }
21
+ export async function provisionMessageBusSchema(pool, options) {
22
+ await withAdvisoryTransactionLock(pool, ["dbx_message_bus", "schema"], async (client) => {
23
+ await client.query(`CREATE SCHEMA IF NOT EXISTS ${quote(options.schema)}`);
24
+ await client.query(`CREATE TABLE IF NOT EXISTS ${quote(options.schema)}.${quote("schema_version")} (version INTEGER PRIMARY KEY)`);
25
+ for (const scope of ["open", "restricted"]) {
26
+ const name = table(options, scope);
27
+ await client.query(`CREATE TABLE IF NOT EXISTS ${name} (sequence BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, channel TEXT NOT NULL, topic TEXT NOT NULL, message_id TEXT NOT NULL, published_at TIMESTAMPTZ NOT NULL, expires_at TIMESTAMPTZ, xact_id XID8 NOT NULL DEFAULT pg_current_xact_id(), envelope JSONB NOT NULL, UNIQUE (channel, message_id), CHECK (jsonb_typeof(envelope) = 'object'))`);
28
+ await client.query(`CREATE INDEX IF NOT EXISTS ${quote(`${options.tables[scope]}_replay_idx`)} ON ${name} (channel, topic, sequence)`);
29
+ await client.query(`CREATE INDEX IF NOT EXISTS ${quote(`${options.tables[scope]}_expiry_idx`)} ON ${name} (expires_at) WHERE expires_at IS NOT NULL`);
30
+ }
31
+ await client.query(`INSERT INTO ${quote(options.schema)}.${quote("schema_version")} (version) VALUES (1) ON CONFLICT (version) DO NOTHING`);
32
+ });
33
+ }
34
+ export function messageBusGrantStatements(roles, scope, options) {
35
+ const selected = table(options, scope);
36
+ return (typeof roles === "string" ? [roles] : roles).flatMap((role) => [
37
+ `GRANT USAGE ON SCHEMA ${quote(options.schema)} TO ${quote(role)};`,
38
+ `GRANT SELECT, INSERT, DELETE ON TABLE ${selected} TO ${quote(role)};`,
39
+ `GRANT SELECT ON TABLE ${quote(options.schema)}.${quote("schema_version")} TO ${quote(role)};`,
40
+ ]);
41
+ }
42
+ function cursor(scope, sequence) {
43
+ return Buffer.from(JSON.stringify([scope, String(sequence)])).toString("base64url");
44
+ }
45
+ function after(value, scope) {
46
+ if (!value)
47
+ return "0";
48
+ const decoded = JSON.parse(Buffer.from(value, "base64url").toString());
49
+ if (decoded[0] !== scope)
50
+ throw new TypeError("History cursor belongs to another persistence scope");
51
+ return decoded[1];
52
+ }
53
+ export function ttlMilliseconds(value) {
54
+ if (value === false)
55
+ return null;
56
+ const milliseconds = object.toDuration(value);
57
+ if (milliseconds === undefined || milliseconds <= 0)
58
+ throw new TypeError(`Invalid persistence TTL: ${String(value)}`);
59
+ return milliseconds;
60
+ }
61
+ export async function cleanupExpired(queryable, options, scope, limit = options.cleanupBatchSize) {
62
+ const result = await queryable.query(`WITH expired AS (SELECT ctid FROM ${table(options, scope)} WHERE expires_at IS NOT NULL AND expires_at <= clock_timestamp() ORDER BY expires_at LIMIT $1) DELETE FROM ${table(options, scope)} AS messages USING expired WHERE messages.ctid = expired.ctid`, [limit]);
63
+ return result.rowCount ?? 0;
64
+ }
65
+ export async function history(queryable, channel, topic, options, input = {}) {
66
+ const scope = input.scope ?? options.scope;
67
+ const limit = input.limit ?? 100;
68
+ const result = await queryable.query(`SELECT sequence, expires_at, envelope FROM ${table(options, scope)} WHERE channel = $1 AND topic = $2 AND sequence > $3::bigint AND (expires_at IS NULL OR expires_at > clock_timestamp()) ORDER BY sequence LIMIT $4`, [channel, topic, after(input.after, scope), limit]);
69
+ const messages = result.rows.map((row) => ({ cursor: cursor(scope, row.sequence), expiresAt: row.expires_at === null ? null : new Date(row.expires_at).toISOString(), scope, message: row.envelope }));
70
+ return { messages, ...(messages.length === limit ? { nextCursor: messages.at(-1).cursor } : {}) };
71
+ }
72
+ export async function persistedNotify(client, channel, topic, message, encoded, options, scope, ttl) {
73
+ await cleanupExpired(client, options, scope);
74
+ const milliseconds = ttlMilliseconds(ttl);
75
+ await client.query(`INSERT INTO ${table(options, scope)} (channel, topic, message_id, published_at, expires_at, envelope) VALUES ($1, $2, $3, $4, CASE WHEN $5::bigint IS NULL THEN NULL ELSE clock_timestamp() + ($5::bigint * interval '1 millisecond') END, $6::jsonb)`, [channel, topic, message.id, message.publishedAt, milliseconds, encoded]);
76
+ await client.query("SELECT pg_notify($1, $2)", [channel, encoded]);
77
+ }
78
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVyc2lzdGVuY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcGVyc2lzdGVuY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBR2hELE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBa0NqRSxNQUFNLFdBQVcsR0FBRyxVQUFVLENBQUM7QUFDL0IsTUFBTSxLQUFLLEdBQUcsQ0FBQyxLQUFhLEVBQVUsRUFBRSxDQUFDLElBQUksS0FBSyxDQUFDLFVBQVUsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQztBQUM1RSxNQUFNLEtBQUssR0FBRyxDQUFDLE9BQTJDLEVBQUUsS0FBNEIsRUFBVSxFQUFFLENBQUMsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQztBQUVoSyxNQUFNLFVBQVUseUJBQXlCLENBQUMsS0FBd0M7SUFDaEYsTUFBTSxVQUFVLEdBQUcsS0FBSyxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7SUFDL0MsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLEtBQUssSUFBSSxNQUFNLENBQUM7SUFDekMsSUFBSSxLQUFLLEtBQUssTUFBTSxJQUFJLEtBQUssS0FBSyxZQUFZO1FBQUUsTUFBTSxJQUFJLFNBQVMsQ0FBQyw4QkFBOEIsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNuSCxPQUFPO1FBQ0wsTUFBTSxFQUFFLFVBQVUsQ0FBQyxNQUFNLElBQUksaUJBQWlCO1FBQzlDLEtBQUs7UUFDTCxNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsVUFBVSxDQUFDLE1BQU0sRUFBRSxJQUFJLElBQUksZUFBZSxFQUFF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Q3JHLENBQUM7QUFFRCxNQUFNLENBQUMsS0FBSyxVQUFVLGVBQWUsQ0FBQyxNQUFtQixFQUFFLE9BQWUsRUFBRSxLQUFhLEVBQUUsT0FBcUIsRUFBRSxPQUFlLEVBQUUsT0FBMkMsRUFBRSxLQUE0QixFQUFFLEdBQTBCO0lBQ3RPLE1BQU0sY0FBYyxDQUFDLE1BQU0sRUFBRSxPQUFPLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDN0MsTUFBTSxZQUFZLEdBQUcsZUFBZSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzFDLE1BQU0sTUFBTSxDQUFDLEtBQUssQ0FBQyxlQUFlLEtBQUssQ0FBQyxPQUFPLEVBQUUsS0FBSyxDQUFDLG1OQUFtTixFQUFFLENBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxPQUFPLENBQUMsRUFBRSxFQUFFLE9BQU8sQ0FBQyxXQUFXLEVBQUUsWUFBWSxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7SUFDdFYsTUFBTSxNQUFNLENBQUMsS0FBSyxDQUFDLDBCQUEwQixFQUFFLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7QUFDckUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IG9iamVjdCB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5pbXBvcnQgdHlwZSB7IFF1ZXJ5UmVzdWx0Um93IH0gZnJvbSBcInBnXCI7XG5pbXBvcnQgdHlwZSB7IFBnUG9vbExpa2UsIFBnUXVlcnlhYmxlIH0gZnJvbSBcIi4vYWR2aXNvcnktbG9jay50c1wiO1xuaW1wb3J0IHsgd2l0aEFkdmlzb3J5VHJhbnNhY3Rpb25Mb2NrIH0gZnJvbSBcIi4vYWR2aXNvcnktbG9jay50c1wiO1xuaW1wb3J0IHR5cGUgeyBUb3BpY01lc3NhZ2UgfSBmcm9tIFwiLi90b3BpYy1idXMudHNcIjtcblxuZXhwb3J0IHR5cGUgVG9waWNQZXJzaXN0ZW5jZVNjb3BlID0gXCJvcGVuXCIgfCBcInJlc3RyaWN0ZWRcIjtcbmV4cG9ydCB0eXBlIER1cmF0aW9uSW5wdXQgPSBzdHJpbmcgfCBudW1iZXI7XG5leHBvcnQgaW50ZXJmYWNlIFRvcGljQnVzUGVyc2lzdGVuY2VPcHRpb25zIHtcbiAgc2NoZW1hPzogc3RyaW5nO1xuICBzY29wZT86IFRvcGljUGVyc2lzdGVuY2VTY29wZTtcbiAgdGFibGVzPzogUGFydGlhbDxSZWNvcmQ8VG9waWNQZXJzaXN0ZW5jZVNjb3BlLCBzdHJpbmc+PjtcbiAgdHRsPzogRHVyYXRpb25JbnB1dCB8IGZhbHNlO1xuICBwYXlsb2FkPzogXCJlbnZlbG9wZVwiIHwgXCJwb2ludGVyXCI7XG4gIGNsZWFudXBCYXRjaFNpemU/OiBudW1iZXI7XG4gIHByb3Zpc2lvbj86IGJvb2xlYW47XG59XG5leHBvcnQgaW50ZXJmYWNlIFJlc29sdmVkVG9waWNCdXNQZXJzaXN0ZW5jZU9wdGlvbnMge1xuICBzY2hlbWE6IHN0cmluZztcbiAgc2NvcGU6IFRvcGljUGVyc2lzdGVuY2VTY29wZTtcbiAgdGFibGVzOiBSZWNvcmQ8VG9waWNQZXJzaXN0ZW5jZVNjb3BlLCBzdHJpbmc+O1xuICB0dGw6IER1cmF0aW9uSW5wdXQgfCBmYWxzZTtcbiAgcGF5bG9hZDogXCJlbnZlbG9wZVwiIHwgXCJwb2ludGVyXCI7XG4gIGNsZWFudXBCYXRjaFNpemU6IG51bWJlcjtcbiAgcHJvdmlzaW9uOiBib29sZWFuO1xufVxuZXhwb3J0IGludGVyZmFjZSBTdG9yZWRUb3BpY01lc3NhZ2U8VEJvZHkgZXh0ZW5kcyBvYmplY3QuU2VyaWFsaXphYmxlVmFsdWUgPSBvYmplY3QuU2VyaWFsaXphYmxlVmFsdWU+IHtcbiAgY3Vyc29yOiBzdHJpbmc7XG4gIGV4cGlyZXNBdDogc3RyaW5nIHwgbnVsbDtcbiAgc2NvcGU6IFRvcGljUGVyc2lzdGVuY2VTY29wZTtcbiAgbWVzc2FnZTogVG9waWNNZXNzYWdlPFRCb2R5Pjtcbn1cbmV4cG9ydCBpbnRlcmZhY2UgVG9waWNIaXN0b3J5UGFnZTxUQm9keSBleHRlbmRzIG9iamVjdC5TZXJpYWxpemFibGVWYWx1ZSA9IG9iamVjdC5TZXJpYWxpemFibGVWYWx1ZT4ge1xuICBtZXNzYWdlczogU3RvcmVkVG9waWNNZXNzYWdlPFRCb2R5PltdO1xuICBuZXh0Q3Vyc29yPzogc3RyaW5nO1xufVxuXG5jb25zdCBERUZBVUxUX1RUTCA9IFwiMjQgaG91cnNcIjtcbmNvbnN0IHF1b3RlID0gKHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcgPT4gYFwiJHt2YWx1ZS5yZXBsYWNlQWxsKCdcIicsICdcIlwiJyl9XCJgO1xuY29uc3QgdGFibGUgPSAob3B0aW9uczogUmVzb2x2ZWRUb3BpY0J1c1BlcnNpc3RlbmNlT3B0aW9ucywgc2NvcGU6IFRvcGljUGVyc2lzdGVuY2VTY29wZSk6IHN0cmluZyA9PiBgJHtxdW90ZShvcHRpb25zLnNjaGVtYSl9LiR7cXVvdGUob3B0aW9ucy50YWJsZXNbc2NvcGVdKX1gO1xuXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZVBlcnNpc3RlbmNlT3B0aW9ucyh2YWx1ZTogdHJ1ZSB8IFRvcGljQnVzUGVyc2lzdGVuY2VPcHRpb25zKTogUmVzb2x2ZWRUb3BpY0J1c1BlcnNpc3RlbmNlT3B0aW9ucyB7XG4gIGNvbnN0IGNvbmZpZ3VyZWQgPSB2YWx1ZSA9PT0gdHJ1ZSA/IHt9IDogdmFsdWU7XG4gIGNvbnN0IHNjb3BlID0gY29uZmlndXJlZC5zY29wZSA/PyBcIm9wZW5cIjtcbiAgaWYgKHNjb3BlICE9PSBcIm9wZW5cIiAmJiBzY29wZSAhPT0gXCJyZXN0cmljdGVkXCIpIHRocm93IG5ldyBUeXBlRXJyb3IoYFVua25vd24gcGVyc2lzdGVuY2Ugc2NvcGU6ICR7U3RyaW5nKHNjb3BlKX1gKTtcbiAgcmV0dXJuIHtcbiAgICBzY2hlbWE6IGNvbmZpZ3VyZWQuc2NoZW1hID8/IFwiZGJ4X21lc3NhZ2VfYnVzXCIsXG4gICAgc2NvcGUsXG4gICAgdGFibGVzOiB7IG9wZW46IGNvbmZpZ3VyZWQudGFibGVzPy5vcGVuID8/IFwib3Blbl9tZXNzYWdlc1wiLCByZXN0cmljdGVkOiBjb25maWd1cmVkLnRhYmxlcz8ucmVzdHJpY3RlZCA/PyBcInJlc3RyaWN0ZWRfbWVzc2FnZXNcIiB9LFxuICAgIHR0bDogY29uZmlndXJlZC50dGwgPz8gREVGQVVMVF9UVEwsXG4gICAgcGF5bG9hZDogY29uZmlndXJlZC5wYXlsb2FkID8/IFwiZW52ZWxvcGVcIixcbiAgICBjbGVhbnVwQmF0Y2hTaXplOiBjb25maWd1cmVkLmNsZWFudXBCYXRjaFNpemUgPz8gMTAwMCxcbiAgICBwcm92aXNpb246IGNvbmZpZ3VyZWQucHJvdmlzaW9uID8/IHRydWUsXG4gIH07XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBwcm92aXNpb25NZXNzYWdlQnVzU2NoZW1hKHBvb2w6IFBnUG9vbExpa2UsIG9wdGlvbnM6IFJlc29sdmVkVG9waWNCdXNQZXJzaXN0ZW5jZU9wdGlvbnMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgYXdhaXQgd2l0aEFkdmlzb3J5VHJhbnNhY3Rpb25Mb2NrKHBvb2wsIFtcImRieF9tZXNzYWdlX2J1c1wiLCBcInNjaGVtYVwiXSwgYXN5bmMgKGNsaWVudCkgPT4ge1xuICAgIGF3YWl0IGNsaWVudC5xdWVyeShgQ1JFQVRFIFNDSEVNQSBJRiBOT1QgRVhJU1RTICR7cXVvdGUob3B0aW9ucy5zY2hlbWEpfWApO1xuICAgIGF3YWl0IGNsaWVudC5xdWVyeShgQ1JFQVRFIFRBQkxFIElGIE5PVCBFWElTVFMgJHtxdW90ZShvcHRpb25zLnNjaGVtYSl9LiR7cXVvdGUoXCJzY2hlbWFfdmVyc2lvblwiKX0gKHZlcnNpb24gSU5URUdFUiBQUklNQVJZIEtFWSlgKTtcbiAgICBmb3IgKGNvbnN0IHNjb3BlIG9mIFtcIm9wZW5cIiwgXCJyZXN0cmljdGVkXCJdIGFzIGNvbnN0KSB7XG4gICAgICBjb25zdCBuYW1lID0gdGFibGUob3B0aW9ucywgc2NvcGUpO1xuICAgICAgYXdhaXQgY2xpZW50LnF1ZXJ5KGBDUkVBVEUgVEFCTEUgSUYgTk9UIEVYSVNUUyAke25hbWV9IChzZXF1ZW5jZSBCSUdJTlQgR0VORVJBVEVEIEFMV0FZUyBBUyBJREVOVElUWSBQUklNQVJZIEtFWSwgY2hhbm5lbCBURVhUIE5PVCBOVUxMLCB0b3BpYyBURVhUIE5PVCBOVUxMLCBtZXNzYWdlX2lkIFRFWFQgTk9UIE5VTEwsIHB1Ymxpc2hlZF9hdCBUSU1FU1RBTVBUWiBOT1QgTlVMTCwgZXhwaXJlc19hdCBUSU1FU1RBTVBUWiwgeGFjdF9pZCBYSUQ4IE5PVCBOVUxMIERFRkFVTFQgcGdfY3VycmVudF94YWN0X2lkKCksIGVudmVsb3BlIEpTT05CIE5PVCBOVUxMLCBVTklRVUUgKGNoYW5uZWwsIG1lc3NhZ2VfaWQpLCBDSEVDSyAoanNvbmJfdHlwZW9mKGVudmVsb3BlKSA9ICdvYmplY3QnKSlgKTtcbiAgICAgIGF3YWl0IGNsaWVudC5xdWVyeShgQ1JFQVRFIElOREVYIElGIE5PVCBFWElTVFMgJHtxdW90ZShgJHtvcHRpb25zLnRhYmxlc1tzY29wZV19X3JlcGxheV9pZHhgKX0gT04gJHtuYW1lfSAoY2hhbm5lbCwgdG9waWMsIHNlcXVlbmNlKWApO1xuICAgICAgYXdhaXQgY2xpZW50LnF1ZXJ5KGBDUkVBVEUgSU5ERVggSUYgTk9UIEVYSVNUUyAke3F1b3RlKGAke29wdGlvbnMudGFibGVzW3Njb3BlXX1fZXhwaXJ5X2lkeGApfSBPTiAke25hbWV9IChleHBpcmVzX2F0KSBXSEVSRSBleHBpcmVzX2F0IElTIE5PVCBOVUxMYCk7XG4gICAgfVxuICAgIGF3YWl0IGNsaWVudC5xdWVyeShgSU5TRVJUIElOVE8gJHtxdW90ZShvcHRpb25zLnNjaGVtYSl9LiR7cXVvdGUoXCJzY2hlbWFfdmVyc2lvblwiKX0gKHZlcnNpb24pIFZBTFVFUyAoMSkgT04gQ09ORkxJQ1QgKHZlcnNpb24pIERPIE5PVEhJTkdgKTtcbiAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBtZXNzYWdlQnVzR3JhbnRTdGF0ZW1lbnRzKHJvbGVzOiBzdHJpbmcgfCByZWFkb25seSBzdHJpbmdbXSwgc2NvcGU6IFRvcGljUGVyc2lzdGVuY2VTY29wZSwgb3B0aW9uczogUmVzb2x2ZWRUb3BpY0J1c1BlcnNpc3RlbmNlT3B0aW9ucyk6IHN0cmluZ1tdIHtcbiAgY29uc3Qgc2VsZWN0ZWQgPSB0YWJsZShvcHRpb25zLCBzY29wZSk7XG4gIHJldHVybiAodHlwZW9mIHJvbGVzID09PSBcInN0cmluZ1wiID8gW3JvbGVzXSA6IHJvbGVzKS5mbGF0TWFwKChyb2xlKSA9PiBbXG4gICAgYEdSQU5UIFVTQUdFIE9OIFNDSEVNQSAke3F1b3RlKG9wdGlvbnMuc2NoZW1hKX0gVE8gJHtxdW90ZShyb2xlKX07YCxcbiAgICBgR1JBTlQgU0VMRUNULCBJTlNFUlQsIERFTEVURSBPTiBUQUJMRSAke3NlbGVjdGVkfSBUTyAke3F1b3RlKHJvbGUpfTtgLFxuICAgIGBHUkFOVCBTRUxFQ1QgT04gVEFCTEUgJHtxdW90ZShvcHRpb25zLnNjaGVtYSl9LiR7cXVvdGUoXCJzY2hlbWFfdmVyc2lvblwiKX0gVE8gJHtxdW90ZShyb2xlKX07YCxcbiAgXSk7XG59XG5cbmZ1bmN0aW9uIGN1cnNvcihzY29wZTogVG9waWNQZXJzaXN0ZW5jZVNjb3BlLCBzZXF1ZW5jZTogc3RyaW5nIHwgbnVtYmVyKTogc3RyaW5nIHtcbiAgcmV0dXJuIEJ1ZmZlci5mcm9tKEpTT04uc3RyaW5naWZ5KFtzY29wZSwgU3RyaW5nKHNlcXVlbmNlKV0pKS50b1N0cmluZyhcImJhc2U2NHVybFwiKTtcbn1cbmZ1bmN0aW9uIGFmdGVyKHZhbHVlOiBzdHJpbmcgfCB1bmRlZmluZWQsIHNjb3BlOiBUb3BpY1BlcnNpc3RlbmNlU2NvcGUpOiBzdHJpbmcge1xuICBpZiAoIXZhbHVlKSByZXR1cm4gXCIwXCI7XG4gIGNvbnN0IGRlY29kZWQgPSBKU09OLnBhcnNlKEJ1ZmZlci5mcm9tKHZhbHVlLCBcImJhc2U2NHVybFwiKS50b1N0cmluZygpKSBhcyBbc3RyaW5nLCBzdHJpbmddO1xuICBpZiAoZGVjb2RlZFswXSAhPT0gc2NvcGUpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJIaXN0b3J5IGN1cnNvciBiZWxvbmdzIHRvIGFub3RoZXIgcGVyc2lzdGVuY2Ugc2NvcGVcIik7XG4gIHJldHVybiBkZWNvZGVkWzFdO1xufVxuZXhwb3J0IGZ1bmN0aW9uIHR0bE1pbGxpc2Vjb25kcyh2YWx1ZTogRHVyYXRpb25JbnB1dCB8IGZhbHNlKTogbnVtYmVyIHwgbnVsbCB7XG4gIGlmICh2YWx1ZSA9PT0gZmFsc2UpIHJldHVybiBudWxsO1xuICBjb25zdCBtaWxsaXNlY29uZHMgPSBvYmplY3QudG9EdXJhdGlvbih2YWx1ZSk7XG4gIGlmIChtaWxsaXNlY29uZHMgPT09IHVuZGVmaW5lZCB8fCBtaWxsaXNlY29uZHMgPD0gMCkgdGhyb3cgbmV3IFR5cGVFcnJvcihgSW52YWxpZCBwZXJzaXN0ZW5jZSBUVEw6ICR7U3RyaW5nKHZhbHVlKX1gKTtcbiAgcmV0dXJuIG1pbGxpc2Vjb25kcztcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFudXBFeHBpcmVkKHF1ZXJ5YWJsZTogUGdRdWVyeWFibGUsIG9wdGlvbnM6IFJlc29sdmVkVG9waWNCdXNQZXJzaXN0ZW5jZU9wdGlvbnMsIHNjb3BlOiBUb3BpY1BlcnNpc3RlbmNlU2NvcGUsIGxpbWl0ID0gb3B0aW9ucy5jbGVhbnVwQmF0Y2hTaXplKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcXVlcnlhYmxlLnF1ZXJ5KGBXSVRIIGV4cGlyZWQgQVMgKFNFTEVDVCBjdGlkIEZST00gJHt0YWJsZShvcHRpb25zLCBzY29wZSl9IFdIRVJFIGV4cGlyZXNfYXQgSVMgTk9UIE5VTEwgQU5EIGV4cGlyZXNfYXQgPD0gY2xvY2tfdGltZXN0YW1wKCkgT1JERVIgQlkgZXhwaXJlc19hdCBMSU1JVCAkMSkgREVMRVRFIEZST00gJHt0YWJsZShvcHRpb25zLCBzY29wZSl9IEFTIG1lc3NhZ2VzIFVTSU5HIGV4cGlyZWQgV0hFUkUgbWVzc2FnZXMuY3RpZCA9IGV4cGlyZWQuY3RpZGAsIFtsaW1pdF0pO1xuICByZXR1cm4gcmVzdWx0LnJvd0NvdW50ID8/IDA7XG59XG5cbnR5cGUgSGlzdG9yeVJvdyA9IFF1ZXJ5UmVzdWx0Um93ICYgeyBzZXF1ZW5jZTogc3RyaW5nOyBleHBpcmVzX2F0OiBEYXRlIHwgc3RyaW5nIHwgbnVsbDsgZW52ZWxvcGU6IFRvcGljTWVzc2FnZSB9O1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhpc3Rvcnk8VEJvZHkgZXh0ZW5kcyBvYmplY3QuU2VyaWFsaXphYmxlVmFsdWU+KHF1ZXJ5YWJsZTogUGdRdWVyeWFibGUsIGNoYW5uZWw6IHN0cmluZywgdG9waWM6IHN0cmluZywgb3B0aW9uczogUmVzb2x2ZWRUb3BpY0J1c1BlcnNpc3RlbmNlT3B0aW9ucywgaW5wdXQ6IHsgYWZ0ZXI/OiBzdHJpbmc7IGxpbWl0PzogbnVtYmVyOyBzY29wZT86IFRvcGljUGVyc2lzdGVuY2VTY29wZSB9ID0ge30pOiBQcm9taXNlPFRvcGljSGlzdG9yeVBhZ2U8VEJvZHk+PiB7XG4gIGNvbnN0IHNjb3BlID0gaW5wdXQuc2NvcGUgPz8gb3B0aW9ucy5zY29wZTtcbiAgY29uc3QgbGltaXQgPSBpbnB1dC5saW1pdCA/PyAxMDA7XG4gIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHF1ZXJ5YWJsZS5xdWVyeTxIaXN0b3J5Um93PihgU0VMRUNUIHNlcXVlbmNlLCBleHBpcmVzX2F0LCBlbnZlbG9wZSBGUk9NICR7dGFibGUob3B0aW9ucywgc2NvcGUpfSBXSEVSRSBjaGFubmVsID0gJDEgQU5EIHRvcGljID0gJDIgQU5EIHNlcXVlbmNlID4gJDM6OmJpZ2ludCBBTkQgKGV4cGlyZXNfYXQgSVMgTlVMTCBPUiBleHBpcmVzX2F0ID4gY2xvY2tfdGltZXN0YW1wKCkpIE9SREVSIEJZIHNlcXVlbmNlIExJTUlUICQ0YCwgW2NoYW5uZWwsIHRvcGljLCBhZnRlcihpbnB1dC5hZnRlciwgc2NvcGUpLCBsaW1pdF0pO1xuICBjb25zdCBtZXNzYWdlcyA9IHJlc3VsdC5yb3dzLm1hcCgocm93KSA9PiAoeyBjdXJzb3I6IGN1cnNvcihzY29wZSwgcm93LnNlcXVlbmNlKSwgZXhwaXJlc0F0OiByb3cuZXhwaXJlc19hdCA9PT0gbnVsbCA/IG51bGwgOiBuZXcgRGF0ZShyb3cuZXhwaXJlc19hdCkudG9JU09TdHJpbmcoKSwgc2NvcGUsIG1lc3NhZ2U6IHJvdy5lbnZlbG9wZSBhcyBUb3BpY01lc3NhZ2U8VEJvZHk+IH0pKTtcbiAgcmV0dXJuIHsgbWVzc2FnZXMsIC4uLihtZXNzYWdlcy5sZW5ndGggPT09IGxpbWl0ID8geyBuZXh0Q3Vyc29yOiBtZXNzYWdlcy5hdCgtMSkhLmN1cnNvciB9IDoge30pIH07XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBwZXJzaXN0ZWROb3RpZnkoY2xpZW50OiBQZ1F1ZXJ5YWJsZSwgY2hhbm5lbDogc3RyaW5nLCB0b3BpYzogc3RyaW5nLCBtZXNzYWdlOiBUb3BpY01lc3NhZ2UsIGVuY29kZWQ6IHN0cmluZywgb3B0aW9uczogUmVzb2x2ZWRUb3BpY0J1c1BlcnNpc3RlbmNlT3B0aW9ucywgc2NvcGU6IFRvcGljUGVyc2lzdGVuY2VTY29wZSwgdHRsOiBEdXJhdGlvbklucHV0IHwgZmFsc2UpOiBQcm9taXNlPHZvaWQ+IHtcbiAgYXdhaXQgY2xlYW51cEV4cGlyZWQoY2xpZW50LCBvcHRpb25zLCBzY29wZSk7XG4gIGNvbnN0IG1pbGxpc2Vjb25kcyA9IHR0bE1pbGxpc2Vjb25kcyh0dGwpO1xuICBhd2FpdCBjbGllbnQucXVlcnkoYElOU0VSVCBJTlRPICR7dGFibGUob3B0aW9ucywgc2NvcGUpfSAoY2hhbm5lbCwgdG9waWMsIG1lc3NhZ2VfaWQsIHB1Ymxpc2hlZF9hdCwgZXhwaXJlc19hdCwgZW52ZWxvcGUpIFZBTFVFUyAoJDEsICQyLCAkMywgJDQsIENBU0UgV0hFTiAkNTo6YmlnaW50IElTIE5VTEwgVEhFTiBOVUxMIEVMU0UgY2xvY2tfdGltZXN0YW1wKCkgKyAoJDU6OmJpZ2ludCAqIGludGVydmFsICcxIG1pbGxpc2Vjb25kJykgRU5ELCAkNjo6anNvbmIpYCwgW2NoYW5uZWwsIHRvcGljLCBtZXNzYWdlLmlkLCBtZXNzYWdlLnB1Ymxpc2hlZEF0LCBtaWxsaXNlY29uZHMsIGVuY29kZWRdKTtcbiAgYXdhaXQgY2xpZW50LnF1ZXJ5KFwiU0VMRUNUIHBnX25vdGlmeSgkMSwgJDIpXCIsIFtjaGFubmVsLCBlbmNvZGVkXSk7XG59XG4iXX0=
@@ -25,6 +25,7 @@
25
25
  */
26
26
  import { object } from "@dbx-tools/shared-core";
27
27
  import type { PgPoolLike, PgQueryable } from "./advisory-lock.ts";
28
+ import { type DurationInput, type TopicBusPersistenceOptions, type TopicHistoryPage, type TopicPersistenceScope } from "./persistence.ts";
28
29
  /**
29
30
  * `@dbx-tools/shared-core` owns the JSON-round-trip rule; this alias just keeps the
30
31
  * generic signatures below readable. Consumers import the type from shared-core.
@@ -78,6 +79,8 @@ export interface TopicPublishInput<TBody extends SerializableValue = Serializabl
78
79
  metadata?: TopicMetadata;
79
80
  /** The payload. Must satisfy `object.isSerializableValue`. */
80
81
  body: TBody;
82
+ scope?: TopicPersistenceScope;
83
+ ttl?: DurationInput | false;
81
84
  }
82
85
  /**
83
86
  * Subscriber callback. Invoked once per matching message on the notification
@@ -128,6 +131,7 @@ export interface PostgresTopicBusOptions {
128
131
  * swallowing them, so wire this to a logger in anything long-running.
129
132
  */
130
133
  onError?: (cause: unknown) => void;
134
+ persist?: boolean | TopicBusPersistenceOptions;
131
135
  }
132
136
  /**
133
137
  * Derive a legal Postgres channel name from whatever a caller used to identify
@@ -194,6 +198,8 @@ export declare class PostgresTopicBus {
194
198
  private reconnecting;
195
199
  private readonly reconnectAbort;
196
200
  private closed;
201
+ private readonly persistence?;
202
+ private provisioning?;
197
203
  constructor(pool: PgPoolLike & PgQueryable, options?: PostgresTopicBusOptions);
198
204
  /**
199
205
  * Open the dedicated notification connection and `LISTEN`.
@@ -220,6 +226,15 @@ export declare class PostgresTopicBus {
220
226
  * Throws if the bus is closed.
221
227
  */
222
228
  broadcast<TBody extends SerializableValue>(topic: string, input: TopicPublishInput<TBody>): Promise<TopicMessage<TBody>>;
229
+ history<TBody extends SerializableValue>(topic: string, options?: {
230
+ after?: string;
231
+ limit?: number;
232
+ scope?: TopicPersistenceScope;
233
+ }): Promise<TopicHistoryPage<TBody>>;
234
+ cleanupExpired(options?: {
235
+ scope?: TopicPersistenceScope;
236
+ limit?: number;
237
+ }): Promise<number>;
223
238
  /**
224
239
  * Subscribe to `topic`, returning the function that unsubscribes.
225
240
  *
@@ -25,6 +25,7 @@
25
25
  */
26
26
  import { hostname } from "node:os";
27
27
  import { async as asyncUtil, error, hash, json, object, string } from "@dbx-tools/shared-core";
28
+ import { cleanupExpired, history, persistedNotify, provisionMessageBusSchema, resolvePersistenceOptions } from "./persistence.js";
28
29
  /** Channel parts used when a caller names no channel of its own. */
29
30
  const DEFAULT_CHANNEL = "dbx_tools_topic_bus";
30
31
  /**
@@ -251,11 +252,14 @@ export class PostgresTopicBus {
251
252
  reconnecting;
252
253
  reconnectAbort = new AbortController();
253
254
  closed = false;
255
+ persistence;
256
+ provisioning;
254
257
  constructor(pool, options = {}) {
255
258
  this.pool = pool;
256
259
  this.channelName = channelName(options.channel === undefined ? DEFAULT_CHANNEL : options.channel);
257
260
  this.metadata = options.metadata;
258
261
  this.onError = options.onError ?? (() => undefined);
262
+ this.persistence = options.persist ? resolvePersistenceOptions(options.persist === true ? true : options.persist) : undefined;
259
263
  }
260
264
  /**
261
265
  * Open the dedicated notification connection and `LISTEN`.
@@ -320,12 +324,46 @@ export class PostgresTopicBus {
320
324
  if (!decode(encoded)) {
321
325
  throw new TypeError("Message type, metadata, and body must be JSON serializable");
322
326
  }
323
- if (Buffer.byteLength(encoded, "utf8") > MAX_NOTIFY_BYTES) {
327
+ if (Buffer.byteLength(encoded, "utf8") > MAX_NOTIFY_BYTES && this.persistence?.payload !== "pointer") {
324
328
  throw new RangeError(`Postgres notification exceeds ${MAX_NOTIFY_BYTES} bytes`);
325
329
  }
326
- await this.pool.query("SELECT pg_notify($1, $2)", [this.channelName, encoded]);
330
+ if (!this.persistence)
331
+ await this.pool.query("SELECT pg_notify($1, $2)", [this.channelName, encoded]);
332
+ else {
333
+ if (this.persistence.provision) {
334
+ this.provisioning ??= provisionMessageBusSchema(this.pool, this.persistence);
335
+ await this.provisioning;
336
+ }
337
+ const client = await this.pool.connect();
338
+ try {
339
+ await client.query("BEGIN");
340
+ await persistedNotify(client, this.channelName, topic, message, encoded, this.persistence, input.scope ?? this.persistence.scope, input.ttl ?? this.persistence.ttl);
341
+ await client.query("COMMIT");
342
+ }
343
+ catch (cause) {
344
+ await client.query("ROLLBACK").catch(() => undefined);
345
+ throw cause;
346
+ }
347
+ finally {
348
+ client.release();
349
+ }
350
+ }
327
351
  return message;
328
352
  }
353
+ async history(topic, options = {}) {
354
+ if (!this.persistence)
355
+ throw new Error("Postgres topic bus persistence is disabled");
356
+ if (this.persistence.provision) {
357
+ this.provisioning ??= provisionMessageBusSchema(this.pool, this.persistence);
358
+ await this.provisioning;
359
+ }
360
+ return history(this.pool, this.channelName, topic, this.persistence, options);
361
+ }
362
+ async cleanupExpired(options = {}) {
363
+ if (!this.persistence)
364
+ throw new Error("Postgres topic bus persistence is disabled");
365
+ return cleanupExpired(this.pool, this.persistence, options.scope ?? this.persistence.scope, options.limit);
366
+ }
329
367
  /**
330
368
  * Subscribe to `topic`, returning the function that unsubscribes.
331
369
  *
@@ -497,4 +535,4 @@ export class PostgresTopicBus {
497
535
  }
498
536
  }
499
537
  }
500
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9waWMtYnVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3RvcGljLWJ1cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBd0JHO0FBRUgsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUNuQyxPQUFPLEVBQUUsS0FBSyxJQUFJLFNBQVMsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFXL0Ysb0VBQW9FO0FBQ3BFLE1BQU0sZUFBZSxHQUFHLHFCQUFxQixDQUFDO0FBQzlDOzs7O0dBSUc7QUFDSCxNQUFNLGtCQUFrQixHQUFHLEVBQUUsQ0FBQztBQUM5QixxRkFBcUY7QUFDckYsTUFBTSxtQkFBbUIsR0FBRyxDQUFDLENBQUM7QUFDOUIsMEVBQTBFO0FBQzFFLE1BQU0sZ0JBQWdCLEdBQUcsS0FBSyxDQUFDO0FBQy9COzs7O0dBSUc7QUFDSCxNQUFNLGdCQUFnQixHQUFHLEtBQUssQ0FBQztBQUMvQixNQUFNLHNCQUFzQixHQUFHLEdBQUcsQ0FBQztBQUNuQyxNQUFNLHNCQUFzQixHQUFHLEtBQUssQ0FBQztBQWtCckM7Ozs7R0FJRztBQUNILElBQUksWUFBMkQsQ0FBQztBQTZHaEU7Ozs7R0FJRztBQUNILFNBQVMsZUFBZSxDQUFDLE1BQXFEO0lBQzVFLE9BQU8sTUFBTSxDQUFDLFdBQVcsQ0FDdkIsTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxLQUFLLEVBQXdDLEVBQUU7UUFDNUUsT0FBTyxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssU0FBUyxDQUFDO0lBQ2hDLENBQUMsQ0FBQyxDQUNILENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNILFNBQVMsZUFBZTtJQUN0QixPQUFPLGVBQWUsQ0FBQztR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U0FBUyxDQUFDLElBQUksR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUMvQyxJQUFJLEtBQUssR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDZCxJQUFJLENBQUM7b0JBQ0gsTUFBTSxTQUFTLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxDQUFDO2dCQUMzRCxDQUFDO2dCQUFDLE1BQU0sQ0FBQztvQkFDUCxPQUFPO2dCQUNULENBQUM7WUFDSCxDQUFDO1lBQ0QsSUFBSSxDQUFDO2dCQUNILE1BQU0sSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO2dCQUNuQixPQUFPO1lBQ1QsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YsSUFBSSxJQUFJLENBQUMsTUFBTTtvQkFBRSxPQUFPO2dCQUN4QixJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUNwQixLQUFLLEdBQUcsS0FBSyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsc0JBQXNCLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxHQUFHLENBQUMsRUFBRSxzQkFBc0IsQ0FBQyxDQUFDO1lBQzdGLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBUb3BpYyBmYW4tb3V0IG92ZXIgUG9zdGdyZVNRTCBgTElTVEVOYC9gTk9USUZZYCwgZm9yIHRlbGxpbmcgZXZlcnkgcnVubmluZ1xuICogaW5zdGFuY2Ugb2YgYW4gYXBwIHRoYXQgc29tZXRoaW5nIGhhcHBlbmVkLlxuICpcbiAqIFRoZSBzaWJsaW5nIGBhZHZpc29yeS1sb2NrYCBtb2R1bGUgaXMgYWJvdXQgbWFraW5nIHN1cmUgb25seSBPTkUgY29ubmVjdGlvblxuICogZG9lcyBhIHRoaW5nOyB0aGlzIG9uZSBpcyB0aGUgb3Bwb3NpdGUgLSBFVkVSWSBsaXN0ZW5pbmcgc2Vzc2lvbiBnZXRzIGV2ZXJ5XG4gKiBub3RpZmljYXRpb24uIFRoYXQgbWFrZXMgaXQgdGhlIHJpZ2h0IHByaW1pdGl2ZSBmb3IgbGl2ZSBVSSB1cGRhdGVzXG4gKiAoYW4gU1NFIHN0cmVhbSBwZXIgYnJvd3NlciB0YWIsIGEgY2FjaGUgaW52YWxpZGF0aW9uLCBhIHByZXNlbmNlIHBpbmcpIGFuZCB0aGVcbiAqIHdyb25nIG9uZSBmb3Igd29yayBkaXN0cmlidXRpb246IHRoZXJlIGFyZSBubyBjb21wZXRpbmcgY29uc3VtZXJzLCBubyBhY2tzLCBhbmRcbiAqIG5vIHJlcGxheS5cbiAqXG4gKiBEZWxpdmVyeSBpcyBiZXN0LWVmZm9ydCBhbmQgbGl2ZS4gYE5PVElGWWAgcmVhY2hlcyBzZXNzaW9ucyB0aGF0IGFyZSBsaXN0ZW5pbmdcbiAqIGF0IHRoZSBtb21lbnQgaXQgY29tbWl0cywgc28gYSBsaXN0ZW5lciB0aGF0IGNvbm5lY3RzIGEgc2Vjb25kIGxhdGVyIG5ldmVyIHNlZXNcbiAqIGl0LCBhbmQgYSBsaXN0ZW5lciB3aG9zZSBjb25uZWN0aW9uIGRyb3BzIG1pc3NlcyBldmVyeXRoaW5nIHVudGlsIHRoZSBidXNcbiAqIHJlY29ubmVjdHMuIFVzZSBhIHRhYmxlIG9yIGEgcXVldWUgd2hlbiBhIHN1YnNjcmliZXIgbmVlZHMgZHVyYWJpbGl0eS5cbiAqXG4gKiBPTkUgQ0hBTk5FTCwgTUFOWSBUT1BJQ1MuIEV2ZXJ5IGJ1cyBpbnN0YW5jZSBsaXN0ZW5zIG9uIGEgc2luZ2xlIFBvc3RncmVzXG4gKiBjaGFubmVsIChgY2hhbm5lbGAsIGRlZmF1bHQgYGRieF90b29sc190b3BpY19idXNgKSBhbmQgZmlsdGVycyBieSB0aGVcbiAqIGVudmVsb3BlJ3MgYHRvcGljYCBpbi1wcm9jZXNzLCBzbyBhZGRpbmcgYSB0b3BpYyBjb3N0cyBubyBjb25uZWN0aW9uIGFuZCBub1xuICogYExJU1RFTmAuIFRoZSB0cmFkZW9mZiBpcyB0aGF0IGV2ZXJ5IGxpc3RlbmluZyBzZXNzaW9uIGRlY29kZXMgZXZlcnkgbWVzc2FnZSBvblxuICogdGhlIGNoYW5uZWw7IGdpdmUgYSBnZW51aW5lbHkgaGlnaC12b2x1bWUsIHVucmVsYXRlZCBzdHJlYW0gaXRzIG93biBgY2hhbm5lbGBcbiAqIHJhdGhlciB0aGFuIGEgdG9waWMuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IGhvc3RuYW1lIH0gZnJvbSBcIm5vZGU6b3NcIjtcbmltcG9ydCB7IGFzeW5jIGFzIGFzeW5jVXRpbCwgZXJyb3IsIGhhc2gsIGpzb24sIG9iamVjdCwgc3RyaW5nIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB0eXBlIHsgTm90aWZpY2F0aW9uLCBQb29sQ2xpZW50IH0gZnJvbSBcInBnXCI7XG5cbmltcG9ydCB0eXBlIHsgUGdQb29sTGlrZSwgUGdRdWVyeWFibGUgfSBmcm9tIFwiLi9hZHZpc29yeS1sb2NrLnRzXCI7XG5cbi8qKlxuICogYEBkYngtdG9vbHMvc2hhcmVkLWNvcmVgIG93bnMgdGhlIEpTT04tcm91bmQtdHJpcCBydWxlOyB0aGlzIGFsaWFzIGp1c3Qga2VlcHMgdGhlXG4gKiBnZW5lcmljIHNpZ25hdHVyZXMgYmVsb3cgcmVhZGFibGUuIENvbnN1bWVycyBpbXBvcnQgdGhlIHR5cGUgZnJvbSBzaGFyZWQtY29yZS5cbiAqL1xudHlwZSBTZXJpYWxpemFibGVWYWx1ZSA9IG9iamVjdC5TZXJpYWxpemFibGVWYWx1ZTtcblxuLyoqIENoYW5uZWwgcGFydHMgdXNlZCB3aGVuIGEgY2FsbGVyIG5hbWVzIG5vIGNoYW5uZWwgb2YgaXRzIG93bi4gKi9cbmNvbnN0IERFRkFVTFRfQ0hBTk5FTCA9IFwiZGJ4X3Rvb2xzX3RvcGljX2J1c1wiO1xuLyoqXG4gKiBgTkFNRURBVEFMRU4gLSAxYC4gUG9zdGdyZXMgVFJVTkNBVEVTIGEgbG9uZ2VyIGNoYW5uZWwgbmFtZSByYXRoZXIgdGhhblxuICogcmVqZWN0aW5nIGl0LCB3aGljaCB3b3VsZCBzcGxpdCBwdWJsaXNoZXJzIGFuZCBsaXN0ZW5lcnMgb250byBkaWZmZXJlbnRcbiAqIGNoYW5uZWxzIHdoaWxlIGV2ZXJ5IGNhbGwgbG9va2VkIGxpa2UgaXQgc3VjY2VlZGVkLlxuICovXG5jb25zdCBNQVhfQ0hBTk5FTF9MRU5HVEggPSA2Mztcbi8qKiBCYXNlLTMyIGNoYXJzIG9mIHRoZSBjaGFubmVsJ3MgaWRlbnRpdHkgc3VmZml4LiBNYXggNyAtIHRoZSBkaWdlc3QgaXMgMzIgYml0cy4gKi9cbmNvbnN0IENIQU5ORUxfSEFTSF9MRU5HVEggPSA2O1xuLyoqIEJvZHkgdXNlZCB3aGVuIHRoZSBwYXJ0cyB0b2tlbml6ZSB0byBub3RoaW5nLCBvciBsZWFkIHdpdGggYSBkaWdpdC4gKi9cbmNvbnN0IENIQU5ORUxfRkFMTEJBQ0sgPSBcImJ1c1wiO1xuLyoqXG4gKiBFbmNvZGVkLWVudmVsb3BlIGNlaWxpbmcuIFBvc3RncmVTUUwgY2FwcyBhIGBOT1RJRllgIHBheWxvYWQgYXQgODAwMCBieXRlcyBhbmRcbiAqIGZhaWxzIHRoZSBzdGF0ZW1lbnQgcGFzdCB0aGF0LCBzbyB0aGUgYnVzIHJlamVjdHMgdGhlIG1lc3NhZ2UgZmlyc3Qgd2l0aCBhIHNpemVcbiAqIGl0IGNhbiBuYW1lLiBUaGUgbWFyZ2luIGJlbG93IDgwMDAgY292ZXJzIHRoZSBzZXJ2ZXIncyBvd24gYWNjb3VudGluZy5cbiAqL1xuY29uc3QgTUFYX05PVElGWV9CWVRFUyA9IDdfOTAwO1xuY29uc3QgTUlOX1JFQ09OTkVDVF9ERUxBWV9NUyA9IDI1MDtcbmNvbnN0IE1BWF9SRUNPTk5FQ1RfREVMQVlfTVMgPSA1XzAwMDtcblxuLyoqXG4gKiBUaGUgc3Vic2V0IG9mIEFwcEtpdCdzIHBlci1yZXF1ZXN0IGV4ZWN1dGlvbiBjb250ZXh0IHRoZSBidXMgcmVhZHMgZm9yIHNlbmRlclxuICogaWRlbnRpdHkuIEZpZWxkcyBhcmUgYHVua25vd25gIGJlY2F1c2UgdGhpcyBpcyBhIHN0cnVjdHVyYWwgdmlldyBvZiBhbiBPUFRJT05BTFxuICogcGVlcjogdGhlIHZhbHVlcyBhcmUgdHJpbW1lZCBhbmQgdmFsaWRhdGVkIHJhdGhlciB0aGFuIHRydXN0ZWQuXG4gKi9cbnR5cGUgQXBwS2l0RXhlY3V0aW9uQ29udGV4dCA9IHtcbiAgdXNlckVtYWlsPzogdW5rbm93bjtcbiAgdXNlcklkPzogdW5rbm93bjtcbiAgdXNlck5hbWU/OiB1bmtub3duO1xufTtcblxuLyoqIFN0cnVjdHVyYWwgdmlldyBvZiBgQGRhdGFicmlja3MvYXBwa2l0YCwgaW1wb3J0ZWQgbGF6aWx5IGFuZCBuZXZlciByZXF1aXJlZC4gKi9cbnR5cGUgQXBwS2l0TW9kdWxlID0ge1xuICBnZXRFeGVjdXRpb25Db250ZXh0KCk6IEFwcEtpdEV4ZWN1dGlvbkNvbnRleHQ7XG59O1xuXG4vKipcbiAqIENhY2hlZCByZXN1bHQgb2YgdGhlIG9uZSBvcHRpb25hbC1wZWVyIGltcG9ydCwgcmVzb2x2ZWQgdG8gYHVuZGVmaW5lZGAgd2hlblxuICogQXBwS2l0IGlzIG5vdCBpbnN0YWxsZWQuIE1lbW9pemVkIHNvIGEgYnVzIGluIGEgcGxhaW4gUG9zdGdyZXMgcHJvY2VzcyBwYXlzIGZvclxuICogdGhlIGZhaWxlZCByZXNvbHV0aW9uIG9uY2UgaW5zdGVhZCBvZiBwZXIgYnJvYWRjYXN0LlxuICovXG5sZXQgYXBwS2l0TW9kdWxlOiBQcm9taXNlPEFwcEtpdE1vZHVsZSB8IHVuZGVmaW5lZD4gfCB1bmRlZmluZWQ7XG5cbi8qKlxuICogRmxhdC1rZXllZCBjb250ZXh0IHRyYXZlbGxpbmcgYWxvbmdzaWRlIGEgbWVzc2FnZSBib2R5OiB3aG8gc2VudCBpdCwgZnJvbVxuICogd2hlcmUsIGluIHdoaWNoIGRlcGxveW1lbnQuIFZhbHVlcyBtYXkgbmVzdCwgYnV0IHRoZSBrZXlzIGFyZSB0aGUgYWRkcmVzc2FibGVcbiAqIHBhcnQgLSBhIGxpc3RlbmVyIGZpbHRlcmluZyBvciBsYWJlbGxpbmcgbWVzc2FnZXMgcmVhZHMgYG1ldGFkYXRhLnVzZXJgLCBub3QgYVxuICogcGF0aCBpbnRvIHRoZSBib2R5LlxuICovXG5leHBvcnQgdHlwZSBUb3BpY01ldGFkYXRhID0gUmVjb3JkPHN0cmluZywgU2VyaWFsaXphYmxlVmFsdWU+O1xuXG4vKipcbiAqIFRoZSB3aXJlIGVudmVsb3BlIGV2ZXJ5IHN1YnNjcmliZXIgcmVjZWl2ZXMsIGFuZCB3aGF0IHtAbGlua1xuICogUG9zdGdyZXNUb3BpY0J1cy5icm9hZGNhc3R9IHJldHVybnMgdG8gdGhlIHB1Ymxpc2hlci5cbiAqXG4gKiBgaWRgLCBgdG9waWNgLCBhbmQgYHB1Ymxpc2hlZEF0YCBhcmUgYXNzaWduZWQgYnkgdGhlIGJ1czsgYHR5cGVgLCBgbWV0YWRhdGFgLFxuICogYW5kIGBib2R5YCBjb21lIGZyb20gdGhlIGNhbGxlciAod2l0aCBhdXRvbWF0aWMgY29udGV4dCBtZXJnZWQgdW5kZXJcbiAqIGBtZXRhZGF0YWApLiBUaGUgc2hhcGUgaXMgc3RhYmxlIGVub3VnaCB0byBoYW5kIHN0cmFpZ2h0IHRvIGFuIFNTRSBgZGF0YTpgXG4gKiBmcmFtZS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBUb3BpY01lc3NhZ2U8VEJvZHkgZXh0ZW5kcyBTZXJpYWxpemFibGVWYWx1ZSA9IFNlcmlhbGl6YWJsZVZhbHVlPiB7XG4gIC8qKlxuICAgKiBQZXItbWVzc2FnZSBpZGVudGl0eSBnZW5lcmF0ZWQgYnkgdGhlIHB1Ymxpc2hlciwgdW5pcXVlIGFjcm9zcyBpbnN0YW5jZXMuXG4gICAqIFN1aXRhYmxlIGZvciBkZWR1cGUgd2hlbiBhIGNsaWVudCByZWNvbm5lY3RzIGFuZCBmb3IgYW4gU1NFIGBpZDpgIGZpZWxkLiBOb3RcbiAgICogb3JkZXJlZCwgYW5kIG5vdCBhIGRhdGFiYXNlIGtleS5cbiAgICovXG4gIGlkOiBzdHJpbmc7XG4gIC8qKiBUaGUgdG9waWMgdGhpcyB3YXMgYnJvYWRjYXN0IG9uOyBsaXN0ZW5lcnMgb24gb3RoZXIgdG9waWNzIG5ldmVyIHNlZSBpdC4gKi9cbiAgdG9waWM6IHN0cmluZztcbiAgLyoqIENhbGxlci1jaG9zZW4gZXZlbnQgbmFtZSwgZS5nLiBgb3JkZXIudXBkYXRlZGAuIE5ldmVyIGVtcHR5LiAqL1xuICB0eXBlOiBzdHJpbmc7XG4gIC8qKiBBdXRvbWF0aWMgY29udGV4dCBtZXJnZWQgd2l0aCBjYWxsZXIgbWV0YWRhdGEuIFNlZSB7QGxpbmsgVG9waWNNZXRhZGF0YX0uICovXG4gIG1ldGFkYXRhOiBUb3BpY01ldGFkYXRhO1xuICAvKiogVGhlIGNhbGxlcidzIHBheWxvYWQsIHVuY2hhbmdlZC4gKi9cbiAgYm9keTogVEJvZHk7XG4gIC8qKlxuICAgKiBJU08tODYwMSBwdWJsaXNoIHRpbWUgZnJvbSB0aGUgUFVCTElTSElORyBwcm9jZXNzJ3MgY2xvY2ssIG5vdCB0aGUgZGF0YWJhc2Uncy5cbiAgICogRmluZSBmb3IgZGlzcGxheTsgZG8gbm90IG9yZGVyIG1lc3NhZ2VzIGZyb20gZGlmZmVyZW50IGluc3RhbmNlcyBieSBpdC5cbiAgICovXG4gIHB1Ymxpc2hlZEF0OiBzdHJpbmc7XG59XG5cbi8qKiBXaGF0IGEgY2FsbGVyIHN1cHBsaWVzIHRvIHtAbGluayBQb3N0Z3Jlc1RvcGljQnVzLmJyb2FkY2FzdH0uICovXG5leHBvcnQgaW50ZXJmYWNlIFRvcGljUHVibGlzaElucHV0PFRCb2R5IGV4dGVuZHMgU2VyaWFsaXphYmxlVmFsdWUgPSBTZXJpYWxpemFibGVWYWx1ZT4ge1xuICAvKiogRXZlbnQgbmFtZSwgZS5nLiBgY2hhdC5tZXNzYWdlYC4gTXVzdCBiZSBub24tYmxhbmsuICovXG4gIHR5cGU6IHN0cmluZztcbiAgLyoqXG4gICAqIENvbnRleHQgdG8gYXR0YWNoLiBXaW5zIG92ZXIgYW55IGF1dG9tYXRpYyBrZXkgb2YgdGhlIHNhbWUgbmFtZSwgc28gYSBjYWxsZXJcbiAgICogY2FuIG92ZXJyaWRlIGEgbWFjaGluZSBkZWZhdWx0IChgcHJvamVjdGApIG9yIGFkZCBpdHMgb3duIChgdHJhY2VJZGApLlxuICAgKi9cbiAgbWV0YWRhdGE/OiBUb3BpY01ldGFkYXRhO1xuICAvKiogVGhlIHBheWxvYWQuIE11c3Qgc2F0aXNmeSBgb2JqZWN0LmlzU2VyaWFsaXphYmxlVmFsdWVgLiAqL1xuICBib2R5OiBUQm9keTtcbn1cblxuLyoqXG4gKiBTdWJzY3JpYmVyIGNhbGxiYWNrLiBJbnZva2VkIG9uY2UgcGVyIG1hdGNoaW5nIG1lc3NhZ2Ugb24gdGhlIG5vdGlmaWNhdGlvblxuICogY29ubmVjdGlvbidzIGNhbGxiYWNrLCBzbyBpdCBzaG91bGQgbm90IGJsb2NrOiBhIHJldHVybmVkIHByb21pc2UgaXMgYXdhaXRlZFxuICogb25seSB0byByb3V0ZSBhIHJlamVjdGlvbiB0byBgb25FcnJvcmAsIGFuZCBsaXN0ZW5lcnMgZm9yIG9uZSBtZXNzYWdlIHJ1blxuICogY29uY3VycmVudGx5IHJhdGhlciB0aGFuIGluIHJlZ2lzdHJhdGlvbiBvcmRlci5cbiAqXG4gKiBgVEJvZHlgIGlzIHVuY2hlY2tlZCBhdCBydW50aW1lLiBUaGUgYnVzIGd1YXJhbnRlZXMgdGhlIGJvZHkgaXMgc2VyaWFsaXphYmxlLFxuICogbm90IHRoYXQgaXQgbWF0Y2hlcyB0aGUgdHlwZSBwYXJhbWV0ZXIsIHNvIHZhbGlkYXRlIGFueXRoaW5nIGEgbGlzdGVuZXJcbiAqIGJyYW5jaGVzIG9uLlxuICovXG5leHBvcnQgdHlwZSBUb3BpY0xpc3RlbmVyPFRCb2R5IGV4dGVuZHMgU2VyaWFsaXphYmxlVmFsdWUgPSBTZXJpYWxpemFibGVWYWx1ZT4gPSAoXG4gIG1lc3NhZ2U6IFRvcGljTWVzc2FnZTxUQm9keT4sXG4pID0+IHZvaWQgfCBQcm9taXNlTGlrZTx2b2lkPjtcblxuLyoqXG4gKiBSZXNvbHZlcyBtZXRhZGF0YSBhdCBwdWJsaXNoIHRpbWUgaW5zdGVhZCBvZiBjb25zdHJ1Y3Rpb24gdGltZSwgZm9yIGNvbnRleHQgYVxuICogcHJvY2VzcyBsZWFybnMgbGF0ZSBvciBhc3luY2hyb25vdXNseSAtIGFuIGluc3RhbmNlIGlkIGZyb20gYSBjb250cm9sIHBsYW5lLCBhXG4gKiBkaXNjb3ZlcmVkIGFkZHJlc3MgYSBjYWxsZXIgY2hvb3NlcyB0byBhdHRhY2guIENhbGxlZCBvbiBldmVyeSBicm9hZGNhc3QsIHNvXG4gKiBtZW1vaXplIGFueXRoaW5nIGV4cGVuc2l2ZTsgYSByZWplY3Rpb24gZmFpbHMgdGhlIGJyb2FkY2FzdC5cbiAqL1xuZXhwb3J0IHR5cGUgVG9waWNNZXRhZGF0YVByb3ZpZGVyID0gKCkgPT4gVG9waWNNZXRhZGF0YSB8IFByb21pc2VMaWtlPFRvcGljTWV0YWRhdGE+O1xuXG4vKiogQ29uc3RydWN0aW9uIG9wdGlvbnMgZm9yIHtAbGluayBQb3N0Z3Jlc1RvcGljQnVzfS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUG9zdGdyZXNUb3BpY0J1c09wdGlvbnMge1xuICAvKipcbiAgICogV2hhdCBpZGVudGlmaWVzIHRoaXMgY2hhbm5lbCAtIGFueXRoaW5nLCBub3QganVzdCBhbiBpZGVudGlmaWVyOiBhIG5hbWUsIGFuXG4gICAqIGlkLCBhIGBbZW52LCBmZWF0dXJlXWAgcGFpciwgYSBjb25maWcgb2JqZWN0LiBUaGUgcGFydHMgYXJlIHRva2VuaXplZCBpbnRvIGFcbiAgICogbGVnYWwgUG9zdGdyZXMgY2hhbm5lbCBuYW1lIHdpdGggYSBzaG9ydCBoYXNoIG9mIHRoZSBvcmlnaW5hbHMgYXBwZW5kZWQsIHNvXG4gICAqIHRoZSBkZXJpdmF0aW9uIGlzIGRldGVybWluaXN0aWMgYW5kIG5vIGNhbGwgc2l0ZSBoYXMgdG8gc2FuaXRpemUuIFNlZVxuICAgKiB7QGxpbmsgUG9zdGdyZXNUb3BpY0J1cy5jaGFubmVsTmFtZX0gZm9yIHRoZSByZXNvbHZlZCBuYW1lLlxuICAgKlxuICAgKiBPbmUgdmFsdWUgb3IgbWFueTogYW4gYXJyYXkgaXMgcmVhZCBhcyBtdWx0aXBsZSBwYXJ0c1xuICAgKiAoe0BsaW5rIG9iamVjdC5PbmVPck1hbnl9KSwgYW55dGhpbmcgZWxzZSBhcyBhIHNpbmdsZSBwYXJ0LiBTb1xuICAgKiBgW1wiYmlsbGluZ1wiLCBcInByb2RcIl1gIGFuZCBgXCJiaWxsaW5nX3Byb2RcImAgYXJlIGRpZmZlcmVudCBjaGFubmVscywgc2luY2UgdGhlXG4gICAqIGhhc2ggc2VlcyBkaWZmZXJlbnQgc3RydWN0dXJlLlxuICAgKlxuICAgKiBFdmVyeSBwYXJ0aWNpcGF0aW5nIHByb2Nlc3MgbXVzdCBwYXNzIEVRVUlWQUxFTlQgcGFydHMsIHNpbmNlIGEgZGlmZmVyZW50XG4gICAqIHNwZWxsaW5nIGhhc2hlcyB0byBhIGRpZmZlcmVudCBjaGFubmVsLiBEZWZhdWx0cyB0byBhIHNoYXJlZFxuICAgKiBgZGJ4X3Rvb2xzX3RvcGljX2J1c2AgY2hhbm5lbC5cbiAgICovXG4gIGNoYW5uZWw/OiB1bmtub3duO1xuICAvKipcbiAgICogRXh0cmEgY29udGV4dCBhZGRlZCB0byBldmVyeSBtZXNzYWdlIHRoaXMgYnVzIHB1Ymxpc2hlcywgZWl0aGVyIGEgZml4ZWRcbiAgICogcmVjb3JkIG9yIGEge0BsaW5rIFRvcGljTWV0YWRhdGFQcm92aWRlcn0gY2FsbGVkIHBlciBicm9hZGNhc3QuIE92ZXJyaWRlc1xuICAgKiBhdXRvbWF0aWMgbWFjaGluZSBrZXlzOyBwZXItY2FsbCBgbWV0YWRhdGFgIG92ZXJyaWRlcyB0aGlzLlxuICAgKi9cbiAgbWV0YWRhdGE/OiBUb3BpY01ldGFkYXRhIHwgVG9waWNNZXRhZGF0YVByb3ZpZGVyO1xuICAvKipcbiAgICogU2luayBmb3IgZmFpbHVyZXMgdGhhdCBoYXZlIG5vIGNhbGxlciB0byB0aHJvdyB0bzogYSBsaXN0ZW5lciB0aGF0IHJlamVjdGVkLFxuICAgKiBhIGRyb3BwZWQgbm90aWZpY2F0aW9uIGNvbm5lY3Rpb24sIGEgZmFpbGVkIHJlY29ubmVjdCBhdHRlbXB0LiBEZWZhdWx0cyB0b1xuICAgKiBzd2FsbG93aW5nIHRoZW0sIHNvIHdpcmUgdGhpcyB0byBhIGxvZ2dlciBpbiBhbnl0aGluZyBsb25nLXJ1bm5pbmcuXG4gICAqL1xuICBvbkVycm9yPzogKGNhdXNlOiB1bmtub3duKSA9PiB2b2lkO1xufVxuXG4vKipcbiAqIERyb3Aga2V5cyB3aG9zZSB2YWx1ZSBpcyBgdW5kZWZpbmVkYCwgc28gYW4gdW5zZXQgZW52aXJvbm1lbnQgdmFyaWFibGUgbGVhdmVzXG4gKiB0aGUga2V5IEFCU0VOVCByYXRoZXIgdGhhbiBwcmVzZW50LWFuZC1udWxsLiBBYnNlbmNlIGlzIHdoYXQgbGV0cyBjYWxsZXJcbiAqIG1ldGFkYXRhIGFuZCBsYXRlciBtZXJnZSBsYXllcnMgc3VwcGx5IHRoZSBrZXkgaW5zdGVhZC5cbiAqL1xuZnVuY3Rpb24gZGVmaW5lZE1ldGFkYXRhKHZhbHVlczogUmVjb3JkPHN0cmluZywgU2VyaWFsaXphYmxlVmFsdWUgfCB1bmRlZmluZWQ+KTogVG9waWNNZXRhZGF0YSB7XG4gIHJldHVybiBPYmplY3QuZnJvbUVudHJpZXMoXG4gICAgT2JqZWN0LmVudHJpZXModmFsdWVzKS5maWx0ZXIoKGVudHJ5KTogZW50cnkgaXMgW3N0cmluZywgU2VyaWFsaXphYmxlVmFsdWVdID0+IHtcbiAgICAgIHJldHVybiBlbnRyeVsxXSAhPT0gdW5kZWZpbmVkO1xuICAgIH0pLFxuICApO1xufVxuXG4vKipcbiAqIENvbnRleHQgZXZlcnkgbWVzc2FnZSBnZXRzIGZvciBmcmVlOiB3aGljaCBwcm9qZWN0LCBob3N0LCBhbmQgZGVwbG95bWVudFxuICogcHVibGlzaGVkIGl0LlxuICpcbiAqIFJlYWQgZnJlc2ggcGVyIGJyb2FkY2FzdCByYXRoZXIgdGhhbiBjYWNoZWQsIGJlY2F1c2UgYSBsb25nLWxpdmVkIHByb2Nlc3MgY2FuXG4gKiBiZSByZS1wYXJlbnRlZCAoYSBkZXBsb3ltZW50IGlkIGFwcGVhcmluZyBhZnRlciBib290KS4gS2V5cyB0aGF0IHJlc29sdmUgdG9cbiAqIG5vdGhpbmcgYXJlIG9taXR0ZWQuXG4gKlxuICogRGVsaWJlcmF0ZWx5IE5PVCBpbmNsdWRlZDogcHVibGljL2NsaWVudCBJUCwgcHJvY2VzcyBpZCwgQ1BVIGFyY2hpdGVjdHVyZSxcbiAqIHJ1bnRpbWUgbmFtZSwgYW5kIHJ1bnRpbWUgdmVyc2lvbi4gSVBzIGFuZCBwaWRzIGFyZSBub2lzeSwgb2Z0ZW4gc2Vuc2l0aXZlLFxuICogYW5kIGJ1cm4gYE5PVElGWWAgcGF5bG9hZCBidWRnZXQ7IGFyY2hpdGVjdHVyZS9ydW50aW1lIGFyZSBjb25zdGFudCBwZXJcbiAqIGRlcGxveW1lbnQgYW5kIHBheSB0aGUgc2FtZSBjb3N0LiBBIHByb2Nlc3MgdGhhdCB3YW50cyBhbnkgb2YgdGhlbSBwYXNzZXMgYVxuICoge0BsaW5rIFRvcGljTWV0YWRhdGFQcm92aWRlcn0gb3IgcGVyLW1lc3NhZ2UgYG1ldGFkYXRhYC5cbiAqL1xuZnVuY3Rpb24gbWFjaGluZU1ldGFkYXRhKCk6IFRvcGljTWV0YWRhdGEge1xuICByZXR1cm4gZGVmaW5lZE1ldGFkYXRhKHtcbiAgICBwcm9qZWN0OlxuICAgICAgc3RyaW5nLmZpcnN0Tm9uRW1wdHkoW1xuICAgICAgICBwcm9jZXNzLmVudi5EQVRBQlJJQ0tTX0FQUF9OQU1FLFxuICAgICAgICBwcm9jZXNzLmVudi5EQVRBQlJJQ0tTX0JVTkRMRV9OQU1FLFxuICAgICAgICBwcm9jZXNzLmVudi5QUk9KRUNUX05BTUUsXG4gICAgICAgIHByb2Nlc3MuZW52Lm5wbV9wYWNrYWdlX25hbWUsXG4gICAgICBdKSA/PyB1bmRlZmluZWQsXG4gICAgaG9zdG5hbWU6IGhvc3RuYW1lKCksXG4gICAgcGxhdGZvcm06IHByb2Nlc3MucGxhdGZvcm0sXG4gICAgZW52aXJvbm1lbnQ6IHN0cmluZy50cmltVG9OdWxsKHByb2Nlc3MuZW52Lk5PREVfRU5WKSA/PyB1bmRlZmluZWQsXG4gICAgYXBwTmFtZTogc3RyaW5nLnRyaW1Ub051bGwocHJvY2Vzcy5lbnYuREFUQUJSSUNLU19BUFBfTkFNRSkgPz8gdW5kZWZpbmVkLFxuICAgIGRlcGxveW1lbnRJZDogc3RyaW5nLnRyaW1Ub051bGwocHJvY2Vzcy5lbnYuREFUQUJSSUNLU19BUFBfREVQTE9ZTUVOVF9JRCkgPz8gdW5kZWZpbmVkLFxuICAgIGRhdGFicmlja3NIb3N0OiBzdHJpbmcudHJpbVRvTnVsbChwcm9jZXNzLmVudi5EQVRBQlJJQ0tTX0hPU1QpID8/IHVuZGVmaW5lZCxcbiAgfSk7XG59XG5cbi8qKlxuICogSWRlbnRpdHkgb2YgdGhlIHNpZ25lZC1pbiB1c2VyIG9uIHdob3NlIGJlaGFsZiB0aGlzIGJyb2FkY2FzdCBoYXBwZW5zLCB3aGVuIHRoZVxuICogcHJvY2VzcyBjYW4gdGVsbC5cbiAqXG4gKiBgQGRhdGFicmlja3MvYXBwa2l0YCBpcyBhbiBPUFRJT05BTCBwZWVyLCBzbyB0aGUgaW1wb3J0IGlzIGxhenkgYW5kIGEgbWlzc2luZ1xuICogbW9kdWxlIGlzIG5vdCBhbiBlcnJvciAtIHRoaXMgaXMgYSBwbGFpbiBQb3N0Z3JlcyBwYWNrYWdlIHRoYXQgYWRkcyBzZW5kZXJcbiAqIGlkZW50aXR5IHdoZW4gaXQgaGFwcGVucyB0byBydW4gaW5zaWRlIGFuIEFwcEtpdCBhcHAuIE91dHNpZGUgYW4gYWN0aXZlXG4gKiBwZXItcmVxdWVzdCBleGVjdXRpb24gY29udGV4dCBBcHBLaXQgdGhyb3dzLCB3aGljaCBtZWFucyBcIm5vIHVzZXIgaGVyZVwiLCBzbyB0aGVcbiAqIHJlc3VsdCBpcyBlbXB0eSBtZXRhZGF0YSByYXRoZXIgdGhhbiBhIGZhaWxlZCBicm9hZGNhc3QuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHNlbmRlck1ldGFkYXRhKCk6IFByb21pc2U8VG9waWNNZXRhZGF0YT4ge1xuICBhcHBLaXRNb2R1bGUgPz89IGltcG9ydChcIkBkYXRhYnJpY2tzL2FwcGtpdFwiKVxuICAgIC50aGVuKChtb2R1bGUpID0+IG1vZHVsZSBhcyBBcHBLaXRNb2R1bGUpXG4gICAgLmNhdGNoKCgpID0+IHVuZGVmaW5lZCk7XG4gIGNvbnN0IGFwcGtpdCA9IGF3YWl0IGFwcEtpdE1vZHVsZTtcbiAgaWYgKCFhcHBraXQpIHJldHVybiB7fTtcbiAgdHJ5IHtcbiAgICBjb25zdCBjb250ZXh0ID0gYXBwa2l0LmdldEV4ZWN1dGlvbkNvbnRleHQoKTtcbiAgICByZXR1cm4gZGVmaW5lZE1ldGFkYXRhKHtcbiAgICAgIHNlbmRlcklkOiBzdHJpbmcudHJpbVRvTnVsbChjb250ZXh0LnVzZXJJZCkgPz8gdW5kZWZpbmVkLFxuICAgICAgc2VuZGVyTmFtZTogc3RyaW5nLnRyaW1Ub051bGwoY29udGV4dC51c2VyTmFtZSkgPz8gdW5kZWZpbmVkLFxuICAgICAgc2VuZGVyRW1haWw6IHN0cmluZy50cmltVG9OdWxsKGNvbnRleHQudXNlckVtYWlsKSA/PyB1bmRlZmluZWQsXG4gICAgfSk7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB7fTtcbiAgfVxufVxuXG4vKipcbiAqIERlcml2ZSBhIGxlZ2FsIFBvc3RncmVzIGNoYW5uZWwgbmFtZSBmcm9tIHdoYXRldmVyIGEgY2FsbGVyIHVzZWQgdG8gaWRlbnRpZnlcbiAqIHRoZSBjaGFubmVsLlxuICpcbiAqIENhbGxlcnMgdGhpbmsgaW4gdGVybXMgb2Ygd2hhdCB0aGUgY2hhbm5lbCBJUyAtIGFuIGFwcCBuYW1lLCBhIHRlbmFudCBpZCwgYVxuICogYFtlbnYsIGZlYXR1cmVdYCBwYWlyLCBhIGNvbmZpZyBvYmplY3QgLSBhbmQgbm9uZSBvZiB0aG9zZSBhcmUgaWRlbnRpZmllcnMuXG4gKiBSZWplY3RpbmcgdGhlbSBwdXNoZWQgdGhlIHNhbml0aXppbmcgb250byBldmVyeSBjYWxsIHNpdGUsIHdoaWNoIGlzIGhvdyB0d29cbiAqIHNlcnZpY2VzIGVuZCB1cCBkaXNhZ3JlZWluZyBhYm91dCB3aGV0aGVyIHRoZSBjaGFubmVsIGlzIGBteS1hcHBgLCBgbXlfYXBwYCxcbiAqIG9yIGBteUFwcGAgYW5kIHNpbGVudGx5IG5ldmVyIGhlYXIgZWFjaCBvdGhlci5cbiAqXG4gKiBUaGUgcGFydHMgYXJlIHRva2VuaXplZCBhbmQgam9pbmVkIGludG8gYW4gaWRlbnRpZmllciwgdGhlbiBhIHNob3J0IGhhc2ggb2YgdGhlXG4gKiBPUklHSU5BTCBwYXJ0cyBpcyBhcHBlbmRlZC4gVGhlIGhhc2ggaXMgd2hhdCBtYWtlcyB0aGUgbWFwcGluZyB0cnVzdHdvcnRoeTpcbiAqIHRva2VuaXppbmcgYWxvbmUgaXMgbG9zc3ksIHNvIGBteS1hcHBgIGFuZCBgbXlfYXBwYCBhbmQgYG15QXBwYCB3b3VsZCBjb2xsYXBzZVxuICogb250byBvbmUgY2hhbm5lbCwgYW5kIGEgbmFtZSBsb25nIGVub3VnaCB0byBoaXQgYE5BTUVEQVRBTEVOYCB3b3VsZCBjb2xsaWRlXG4gKiB3aXRoIGFueXRoaW5nIHNoYXJpbmcgaXRzIGxlYWRpbmcgdG9rZW5zLiBXaXRoIHRoZSBzdWZmaXgsIHRoZSByZWFkYWJsZSBwYXJ0XG4gKiBzdGF5cyByZWFkYWJsZSBhbmQgZGlzdGluY3QgaW5wdXRzIHN0YXkgZGlzdGluY3QuXG4gKlxuICogRGV0ZXJtaW5pc3RpYyBhY3Jvc3MgcHJvY2Vzc2VzIGFuZCBydW5zLCB3aGljaCBpcyB0aGUgd2hvbGUgcG9pbnQgLSB0d29cbiAqIHNlcnZpY2VzIGdpdmVuIHRoZSBzYW1lIHBhcnRzIG11c3QgbGFuZCBvbiB0aGUgc2FtZSBjaGFubmVsIHdpdGhvdXRcbiAqIGNvb3JkaW5hdGluZy4gSGFzaCBpbnB1dHMgYXJlIHN0cnVjdHVyZS1hd2FyZSwgc28gYFtcImFcIiwgXCJiXCJdYCBhbmQgYFtcImFfYlwiXWBcbiAqIGRpZmZlciwgYW5kIG9iamVjdCBrZXkgb3JkZXIgZG9lcyBub3QuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjaGFubmVsTmFtZSh2YWx1ZTogdW5rbm93bik6IHN0cmluZyB7XG4gIGNvbnN0IHBhcnRzID0gb2JqZWN0LnRvT25lT3JNYW55KHZhbHVlKTtcbiAgLy8gSGFzaCB0aGUgQ0FOT05JQ0FMIGZvcm0sIHRoZSBzYW1lIHJ1bGUgYGFkdmlzb3J5TG9ja0lkYCB1c2VzLCBzbyBzdHJ1Y3R1cmUgYW5kXG4gIC8vIHR5cGVzIGRlY2lkZSBpZGVudGl0eTogYFtcImFcIixcImJcIl1gIGRpZmZlcnMgZnJvbSBgW1wiYWJcIl1gLCBgMWAgZnJvbSBgXCIxXCJgLCBhbmRcbiAgLy8gb2JqZWN0IGtleSBvcmRlciBkb2VzIG5vdCBtYXR0ZXIuIEhhc2hpbmcgdGhlIHJhdyBwYXJ0cyB3b3VsZCBpbnN0ZWFkIGxlYW4gb25cbiAgLy8gdGhlIGhhc2ggbW9kdWxlJ3MgY2Fub25pY2FsaXplciwgd2hpY2ggZm9sZHMgZXZlcnkgYERhdGVgIG9udG8gb25lIHRva2VuLlxuICBjb25zdCBzdWZmaXggPSBoYXNoLmZudkhhc2hXaXRoT3B0aW9ucyhcbiAgICB7IGxlbmd0aDogQ0hBTk5FTF9IQVNIX0xFTkdUSCB9LFxuICAgIHBhcnRzLm1hcCgocGFydCkgPT4gb2JqZWN0LnRvU3RhYmxlS2V5KHBhcnQpKS5qb2luKFwiXFx1MDAwMFwiKSxcbiAgKTtcbiAgLy8gT25seSBwYXJ0cyB0aGF0IHN0cmluZ2lmeSB0byBzb21ldGhpbmcgYSByZWFkZXIgcmVjb2duaXplcyBjb250cmlidXRlIHRvIHRoZVxuICAvLyByZWFkYWJsZSBoYWxmLiBBbiBvYmplY3Qgd291bGQgdG9rZW5pemUgZnJvbSBgU3RyaW5nKHZhbHVlKWAgYXNcbiAgLy8gYG9iamVjdF9vYmplY3RgLCB3aGljaCBpcyBub2lzZSAtIGl0IHN0aWxsIHNoYXBlcyB0aGUgaGFzaCwgc28gaWRlbnRpdHkgaXNcbiAgLy8gdW5hZmZlY3RlZC5cbiAgY29uc3QgbGFiZWxsZWQgPSBwYXJ0cy5maWx0ZXIoKHBhcnQpID0+IHtcbiAgICBjb25zdCB0eXBlID0gdHlwZW9mIHBhcnQ7XG4gICAgcmV0dXJuIHR5cGUgPT09IFwic3RyaW5nXCIgfHwgdHlwZSA9PT0gXCJudW1iZXJcIiB8fCB0eXBlID09PSBcImJvb2xlYW5cIiB8fCB0eXBlID09PSBcImJpZ2ludFwiO1xuICB9KTtcbiAgLy8gVHJ1bmNhdGUgcmF0aGVyIHRoYW4gY2FwIHRocm91Z2ggdGhlIHRva2VuaXplcjogYHRyaW1gIHdvdWxkIERST1AgYSBzaW5nbGVcbiAgLy8gdG9rZW4gbG9uZ2VyIHRoYW4gdGhlIGJ1ZGdldCwgdHVybmluZyBvbmUgbG9uZyBuYW1lIGludG8gdGhlIGJhcmUgZmFsbGJhY2sgYW5kXG4gIC8vIG1ha2luZyBldmVyeSBsb25nIG5hbWUgbG9vayBhbGlrZS4gVGhlIGhhc2ggc3RpbGwgc2VwYXJhdGVzIHRoZW0sIGJ1dCB0aGVcbiAgLy8gY2hhbm5lbCBpcyB1bnJlYWRhYmxlIGluIGEgbG9nLlxuICBjb25zdCBib2R5ID0gc3RyaW5nXG4gICAgLnRvSWRlbnRpZmllcldpdGhPcHRpb25zKHsgZGVsaW1pdGVyOiBcIl9cIiB9LCAuLi5sYWJlbGxlZClcbiAgICAuc2xpY2UoMCwgTUFYX0NIQU5ORUxfTEVOR1RIIC0gc3VmZml4Lmxlbmd0aCAtIDEpXG4gICAgLnJlcGxhY2UoL18rJC8sIFwiXCIpO1xuICAvLyBBbiBpZGVudGlmaWVyIGNhbm5vdCBzdGFydCB3aXRoIGEgZGlnaXQgYW5kIHRoZSBoYXNoIGFscGhhYmV0IGlzXG4gIC8vIGRpZ2l0LWxlYWRpbmcsIHNvIGEgbnVtZXJpYyBvciBlbXB0eSBib2R5IG5lZWRzIGEgbGV0dGVyIGluIGZyb250LlxuICBjb25zdCBwcmVmaXggPSAvXltBLVphLXpfXS8udGVzdChib2R5KSA/IGJvZHkgOiBgJHtDSEFOTkVMX0ZBTExCQUNLfV8ke2JvZHl9YDtcbiAgcmV0dXJuIGAke3ByZWZpeH1fJHtzdWZmaXh9YC5yZXBsYWNlKC9fKy9nLCBcIl9cIik7XG59XG5cbi8qKiBRdW90ZSBhIHZhbGlkYXRlZCBjaGFubmVsIGZvciBgTElTVEVOYC9gVU5MSVNURU5gLCB3aGljaCB0YWtlIG5vIHBhcmFtZXRlcnMuICovXG5mdW5jdGlvbiBxdW90ZUlkZW50aWZpZXIodmFsdWU6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBgXCIke3ZhbHVlLnJlcGxhY2VBbGwoJ1wiJywgJ1wiXCInKX1cImA7XG59XG5cbi8qKlxuICogUGFyc2UgYSBgTk9USUZZYCBwYXlsb2FkIGludG8gYW4gZW52ZWxvcGUsIHJldHVybmluZyBgdW5kZWZpbmVkYCBmb3IgYW55dGhpbmdcbiAqIHRoYXQgaXMgbm90IG9uZS5cbiAqXG4gKiBUaGUgY2hhbm5lbCBpcyBzaGFyZWQgYW5kIGFueSBQb3N0Z3JlcyBzZXNzaW9uIGNhbiBgcGdfbm90aWZ5YCBvbiBpdCwgc28gYW5cbiAqIHVucmVjb2duaXplZCBwYXlsb2FkIGlzIGV4cGVjdGVkIGlucHV0LCBub3QgYW4gZXhjZXB0aW9uLiBQdWJsaXNoZXJzIHJ1biB0aGlzXG4gKiBvdmVyIHRoZWlyIG93biBlbmNvZGVkIG1lc3NhZ2UgdG9vLCB3aGljaCBpcyBob3cgYSBib2R5IHRoYXQgc3RyaW5naWZpZXMgYnV0XG4gKiBkb2VzIG5vdCByb3VuZC10cmlwIGlzIGNhdWdodCBiZWZvcmUgaXQgc2hpcHMuXG4gKi9cbmZ1bmN0aW9uIGRlY29kZSh2YWx1ZTogc3RyaW5nIHwgdW5kZWZpbmVkKTogVG9waWNNZXNzYWdlIHwgdW5kZWZpbmVkIHtcbiAgaWYgKCF2YWx1ZSkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgY29uc3QgcmVjb3JkID0ganNvbi5wYXJzZVJlY29yZCh2YWx1ZSk7XG4gIGlmIChcbiAgICAhcmVjb3JkIHx8XG4gICAgdHlwZW9mIHJlY29yZC5pZCAhPT0gXCJzdHJpbmdcIiB8fFxuICAgIHR5cGVvZiByZWNvcmQudG9waWMgIT09IFwic3RyaW5nXCIgfHxcbiAgICB0eXBlb2YgcmVjb3JkLnR5cGUgIT09IFwic3RyaW5nXCIgfHxcbiAgICB0eXBlb2YgcmVjb3JkLnB1Ymxpc2hlZEF0ICE9PSBcInN0cmluZ1wiIHx8XG4gICAgIXJlY29yZC5tZXRhZGF0YSB8fFxuICAgIHR5cGVvZiByZWNvcmQubWV0YWRhdGEgIT09IFwib2JqZWN0XCIgfHxcbiAgICBBcnJheS5pc0FycmF5KHJlY29yZC5tZXRhZGF0YSkgfHxcbiAgICAhKFwiYm9keVwiIGluIHJlY29yZCkgfHxcbiAgICAhb2JqZWN0LmlzU2VyaWFsaXphYmxlVmFsdWUocmVjb3JkLm1ldGFkYXRhKSB8fFxuICAgICFvYmplY3QuaXNTZXJpYWxpemFibGVWYWx1ZShyZWNvcmQuYm9keSlcbiAgKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuICByZXR1cm4ge1xuICAgIGlkOiByZWNvcmQuaWQsXG4gICAgdG9waWM6IHJlY29yZC50b3BpYyxcbiAgICB0eXBlOiByZWNvcmQudHlwZSxcbiAgICBtZXRhZGF0YTogcmVjb3JkLm1ldGFkYXRhIGFzIFRvcGljTWV0YWRhdGEsXG4gICAgYm9keTogcmVjb3JkLmJvZHkgYXMgU2VyaWFsaXphYmxlVmFsdWUsXG4gICAgcHVibGlzaGVkQXQ6IHJlY29yZC5wdWJsaXNoZWRBdCxcbiAgfTtcbn1cblxuLyoqXG4gKiBCcm9hZGNhc3RzIHN0cnVjdHVyZWQgbWVzc2FnZXMgYnkgdG9waWMgYW5kIGRlbGl2ZXJzIHRoZW0gdG8gZXZlcnkgcHJvY2Vzc1xuICogbGlzdGVuaW5nIG9uIHRoZSBzYW1lIGNoYW5uZWwuXG4gKlxuICogQ09OTkVDVElPTiBTSEFQRS4gUHVibGlzaGluZyBib3Jyb3dzIGEgcG9vbGVkIGNvbm5lY3Rpb24gcGVyIGNhbGwsIGxpa2UgYW55XG4gKiBvdGhlciBxdWVyeS4gTGlzdGVuaW5nIGNhbm5vdDogYExJU1RFTmAgaXMgc2Vzc2lvbiBzdGF0ZSwgc28gdGhlIGJ1cyBob2xkcyBPTkVcbiAqIGRlZGljYXRlZCBjbGllbnQgb3V0IG9mIHRoZSBwb29sIGZvciBhcyBsb25nIGFzIGl0IGhhcyBzdWJzY3JpYmVycywgbm8gbWF0dGVyXG4gKiBob3cgbWFueSB0b3BpY3Mgb3IgbGlzdGVuZXJzIGFyZSByZWdpc3RlcmVkLiBTaXplIHRoZSBwb29sIHdpdGggdGhhdCBvbmVcbiAqIGxvbmctbGl2ZWQgY2hlY2tvdXQgaW4gbWluZC5cbiAqXG4gKiBMSUZFQ1lDTEUuIENvbnN0cnVjdGlvbiBpcyBpbmVydCAtIG5vdGhpbmcgY29ubmVjdHMgdW50aWwgdGhlIGZpcnN0XG4gKiB7QGxpbmsgbGlzdGVufSAob3IgYW4gZXhwbGljaXQge0BsaW5rIHN0YXJ0fSkuIHtAbGluayBjbG9zZX0gaXMgcmVxdWlyZWQgdG8gZ2l2ZVxuICogdGhlIGNvbm5lY3Rpb24gYmFjazsgYSBjbG9zZWQgYnVzIHN0YXlzIGNsb3NlZCBhbmQgdGhyb3dzIG9uIGZ1cnRoZXIgdXNlIHJhdGhlclxuICogdGhhbiBzaWxlbnRseSByZWNvbm5lY3RpbmcuIFJlZ2lzdGVyIGl0IHdpdGggdGhlIGhvc3QncyBzaHV0ZG93biBob29rLlxuICpcbiAqIEZBSUxVUkUgSEFORExJTkcuIEEgbG9zdCBub3RpZmljYXRpb24gY29ubmVjdGlvbiByZWNvbm5lY3RzIG9uIGl0cyBvd24gd2l0aFxuICogYm91bmRlZCBiYWNrb2ZmIHdoaWxlIHN1YnNjcmliZXJzIHJlbWFpbiwgcmVwb3J0aW5nIGVhY2ggZmFpbGVkIGF0dGVtcHQgdGhyb3VnaFxuICogYG9uRXJyb3JgLiBNZXNzYWdlcyBwdWJsaXNoZWQgZHVyaW5nIHRoZSBnYXAgYXJlIGxvc3QgLSBgTk9USUZZYCBoYXMgbm8gcmVwbGF5LlxuICogQSB0aHJvd2luZyBvciByZWplY3RpbmcgbGlzdGVuZXIgbmV2ZXIgYWZmZWN0cyB0aGUgcHVibGlzaGVyIG9yIHRoZSBvdGhlclxuICogbGlzdGVuZXJzOyBpdHMgZmFpbHVyZSBnb2VzIHRvIGBvbkVycm9yYC5cbiAqXG4gKiBOb3Qgc2FmZSB0byBzaGFyZSBvbmUgaW5zdGFuY2UgYWNyb3NzIHVucmVsYXRlZCBjaGFubmVscyAtIGNvbnN0cnVjdCBvbmUgYnVzXG4gKiBwZXIgY2hhbm5lbC4gVGhlIGNoYW5uZWwgaXRzZWxmIGlzIERFUklWRUQgZnJvbSB0aGUgYGNoYW5uZWxgIG9wdGlvbiByYXRoZXJcbiAqIHRoYW4gdGFrZW4gbGl0ZXJhbGx5OyBzZWUge0BsaW5rIFBvc3RncmVzVG9waWNCdXNPcHRpb25zLmNoYW5uZWx9IGFuZFxuICoge0BsaW5rIFBvc3RncmVzVG9waWNCdXMuY2hhbm5lbE5hbWV9LlxuICovXG5leHBvcnQgY2xhc3MgUG9zdGdyZXNUb3BpY0J1cyB7XG4gIC8qKlxuICAgKiBUaGUgcmVzb2x2ZWQgUG9zdGdyZXMgY2hhbm5lbCB0aGlzIGJ1cyBsaXN0ZW5zIGFuZCBwdWJsaXNoZXMgb24sIGRlcml2ZWQgZnJvbVxuICAgKiB0aGUgYGNoYW5uZWxgIG9wdGlvbi4gUmVhZCBpdCB0byBjb25maXJtIHR3byBwcm9jZXNzZXMgYWdyZWUsIG9yIHRvIGxvZyB3aGF0IGFcbiAgICogc2V0IG9mIHBhcnRzIGFjdHVhbGx5IHJlc29sdmVkIHRvLlxuICAgKi9cbiAgcmVhZG9ubHkgY2hhbm5lbE5hbWU6IHN0cmluZztcbiAgcHJpdmF0ZSByZWFkb25seSBtZXRhZGF0YTogVG9waWNNZXRhZGF0YSB8IFRvcGljTWV0YWRhdGFQcm92aWRlciB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSByZWFkb25seSBvbkVycm9yOiAoY2F1c2U6IHVua25vd24pID0+IHZvaWQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgbGlzdGVuZXJzID0gbmV3IE1hcDxzdHJpbmcsIFNldDxUb3BpY0xpc3RlbmVyPj4oKTtcbiAgcHJpdmF0ZSBjbGllbnQ6IFBvb2xDbGllbnQgfCB1bmRlZmluZWQ7XG4gIHByaXZhdGUgc3RhcnRpbmc6IFByb21pc2U8dm9pZD4gfCB1bmRlZmluZWQ7XG4gIHByaXZhdGUgcmVjb25uZWN0aW5nOiBQcm9taXNlPHZvaWQ+IHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIHJlYWRvbmx5IHJlY29ubmVjdEFib3J0ID0gbmV3IEFib3J0Q29udHJvbGxlcigpO1xuICBwcml2YXRlIGNsb3NlZCA9IGZhbHNlO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgcG9vbDogUGdQb29sTGlrZSAmIFBnUXVlcnlhYmxlLFxuICAgIG9wdGlvbnM6IFBvc3RncmVzVG9waWNCdXNPcHRpb25zID0ge30sXG4gICkge1xuICAgIHRoaXMuY2hhbm5lbE5hbWUgPSBjaGFubmVsTmFtZShcbiAgICAgIG9wdGlvbnMuY2hhbm5lbCA9PT0gdW5kZWZpbmVkID8gREVGQVVMVF9DSEFOTkVMIDogb3B0aW9ucy5jaGFubmVsLFxuICAgICk7XG4gICAgdGhpcy5tZXRhZGF0YSA9IG9wdGlvbnMubWV0YWRhdGE7XG4gICAgdGhpcy5vbkVycm9yID0gb3B0aW9ucy5vbkVycm9yID8/ICgoKSA9PiB1bmRlZmluZWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIE9wZW4gdGhlIGRlZGljYXRlZCBub3RpZmljYXRpb24gY29ubmVjdGlvbiBhbmQgYExJU1RFTmAuXG4gICAqXG4gICAqIElkZW1wb3RlbnQsIGFuZCBzYWZlIHRvIGNhbGwgY29uY3VycmVudGx5IC0gb3ZlcmxhcHBpbmcgY2FsbHMgYXdhaXQgdGhlIHNhbWVcbiAgICogaW4tZmxpZ2h0IGNvbm5lY3QuIHtAbGluayBsaXN0ZW59IGNhbGxzIHRoaXMsIHNvIGl0IGlzIG9ubHkgbmVlZGVkIHRvIHN1cmZhY2VcbiAgICogYSBjb25uZWN0aW9uIHByb2JsZW0gYXQgc3RhcnR1cCByYXRoZXIgdGhhbiBvbiBmaXJzdCBzdWJzY3JpYmUuIFRocm93cyBpZiB0aGVcbiAgICogYnVzIGlzIGNsb3NlZCwgb3IgaWYgdGhlIHBvb2wgY2Fubm90IGhhbmQgb3V0IGEgY29ubmVjdGlvbi5cbiAgICovXG4gIGFzeW5jIHN0YXJ0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmNsaWVudCkgcmV0dXJuO1xuICAgIGlmICh0aGlzLmNsb3NlZCkgdGhyb3cgbmV3IEVycm9yKFwiUG9zdGdyZXMgdG9waWMgYnVzIGlzIGNsb3NlZFwiKTtcbiAgICB0aGlzLnN0YXJ0aW5nID8/PSB0aGlzLmNvbm5lY3QoKS5maW5hbGx5KCgpID0+IHtcbiAgICAgIHRoaXMuc3RhcnRpbmcgPSB1bmRlZmluZWQ7XG4gICAgfSk7XG4gICAgYXdhaXQgdGhpcy5zdGFydGluZztcbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaXNoIGEgbWVzc2FnZSB0byBgdG9waWNgLCByZXR1cm5pbmcgdGhlIGVudmVsb3BlIHRoYXQgd2FzIHNlbnQuXG4gICAqXG4gICAqIFJlc29sdmVzIG9uY2UgUG9zdGdyZXMgaGFzIGFjY2VwdGVkIHRoZSBgTk9USUZZYCwgd2hpY2ggc2F5cyBub3RoaW5nIGFib3V0XG4gICAqIGFueW9uZSByZWNlaXZpbmcgaXQ6IHNlc3Npb25zIG5vdCBsaXN0ZW5pbmcgYXQgdGhhdCBtb21lbnQgbWlzcyBpdC4gUHVibGlzaGluZ1xuICAgKiBuZWVkcyBubyB7QGxpbmsgc3RhcnR9IGFuZCBubyBzdWJzY3JpYmVycy5cbiAgICpcbiAgICogVmFsaWRhdGlvbiBpcyBkZWxpYmVyYXRlbHkgZnJvbnQtbG9hZGVkLCBzaW5jZSBhIG1lc3NhZ2UgdGhhdCBmYWlscyBvbiB0aGVcbiAgICogd2lyZSBpcyBmYXIgaGFyZGVyIHRvIGRpYWdub3NlIHRoYW4gb25lIHJlamVjdGVkIGF0IHRoZSBjYWxsOiBgVHlwZUVycm9yYCBmb3IgYVxuICAgKiBibGFuayB0b3BpYyBvciB0eXBlLCBvciBhIGJvZHkvbWV0YWRhdGEgdGhhdCB3b3VsZCBub3Qgcm91bmQtdHJpcCB0aHJvdWdoIEpTT05cbiAgICogdW5jaGFuZ2VkIChgb2JqZWN0LmlzU2VyaWFsaXphYmxlVmFsdWVgKTsgYFJhbmdlRXJyb3JgIHdoZW4gdGhlIGVuY29kZWRcbiAgICogZW52ZWxvcGUgZXhjZWVkcyB0aGUgYE5PVElGWWAgcGF5bG9hZCBsaW1pdCwgd2hpY2ggdGhlIGF1dG9tYXRpYyBtZXRhZGF0YVxuICAgKiBjb3VudHMgYWdhaW5zdCAtIHNlbmQgYSByZWZlcmVuY2UgYW5kIGxldCB0aGUgcmVjZWl2ZXIgZmV0Y2ggdGhlIHBheWxvYWQuXG4gICAqIFRocm93cyBpZiB0aGUgYnVzIGlzIGNsb3NlZC5cbiAgICovXG4gIGFzeW5jIGJyb2FkY2FzdDxUQm9keSBleHRlbmRzIFNlcmlhbGl6YWJsZVZhbHVlPihcbiAgICB0b3BpYzogc3RyaW5nLFxuICAgIGlucHV0OiBUb3BpY1B1Ymxpc2hJbnB1dDxUQm9keT4sXG4gICk6IFByb21pc2U8VG9waWNNZXNzYWdlPFRCb2R5Pj4ge1xuICAgIGlmICghdG9waWMudHJpbSgpKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiVG9waWMgbXVzdCBub3QgYmUgZW1wdHlcIik7XG4gICAgaWYgKCFpbnB1dC50eXBlLnRyaW0oKSkgdGhyb3cgbmV3IFR5cGVFcnJvcihcIk1lc3NhZ2UgdHlwZSBtdXN0IG5vdCBiZSBlbXB0eVwiKTtcbiAgICBpZiAoXG4gICAgICAhb2JqZWN0LmlzU2VyaWFsaXphYmxlVmFsdWUoaW5wdXQubWV0YWRhdGEgPz8ge30pIHx8XG4gICAgICAhb2JqZWN0LmlzU2VyaWFsaXphYmxlVmFsdWUoaW5wdXQuYm9keSlcbiAgICApIHtcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJNZXNzYWdlIG1ldGFkYXRhIGFuZCBib2R5IG11c3QgYmUgSlNPTiBzZXJpYWxpemFibGUgd2l0aG91dCBjb2VyY2lvblwiKTtcbiAgICB9XG4gICAgaWYgKHRoaXMuY2xvc2VkKSB0aHJvdyBuZXcgRXJyb3IoXCJQb3N0Z3JlcyB0b3BpYyBidXMgaXMgY2xvc2VkXCIpO1xuICAgIGNvbnN0IGF1dG9tYXRpYyA9IGF3YWl0IHRoaXMucmVzb2x2ZU1ldGFkYXRhKCk7XG4gICAgY29uc3QgbWVzc2FnZTogVG9waWNNZXNzYWdlPFRCb2R5PiA9IHtcbiAgICAgIGlkOiBoYXNoLmlkKCksXG4gICAgICB0b3BpYyxcbiAgICAgIHR5cGU6IGlucHV0LnR5cGUsXG4gICAgICBtZXRhZGF0YTogeyAuLi5hdXRvbWF0aWMsIC4uLmlucHV0Lm1ldGFkYXRhIH0sXG4gICAgICBib2R5OiBpbnB1dC5ib2R5LFxuICAgICAgcHVibGlzaGVkQXQ6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICB9O1xuICAgIGxldCBlbmNvZGVkOiBzdHJpbmc7XG4gICAgdHJ5IHtcbiAgICAgIGVuY29kZWQgPSBKU09OLnN0cmluZ2lmeShtZXNzYWdlKTtcbiAgICB9IGNhdGNoIChjYXVzZSkge1xuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihgTWVzc2FnZSBtdXN0IGJlIEpTT04gc2VyaWFsaXphYmxlOiAke2Vycm9yLmVycm9yTWVzc2FnZShjYXVzZSl9YCk7XG4gICAgfVxuICAgIGlmICghZGVjb2RlKGVuY29kZWQpKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiTWVzc2FnZSB0eXBlLCBtZXRhZGF0YSwgYW5kIGJvZHkgbXVzdCBiZSBKU09OIHNlcmlhbGl6YWJsZVwiKTtcbiAgICB9XG4gICAgaWYgKEJ1ZmZlci5ieXRlTGVuZ3RoKGVuY29kZWQsIFwidXRmOFwiKSA+IE1BWF9OT1RJRllfQllURVMpIHtcbiAgICAgIHRocm93IG5ldyBSYW5nZUVycm9yKGBQb3N0Z3JlcyBub3RpZmljYXRpb24gZXhjZWVkcyAke01BWF9OT1RJRllfQllURVN9IGJ5dGVzYCk7XG4gICAgfVxuICAgIGF3YWl0IHRoaXMucG9vbC5xdWVyeShcIlNFTEVDVCBwZ19ub3RpZnkoJDEsICQyKVwiLCBbdGhpcy5jaGFubmVsTmFtZSwgZW5jb2RlZF0pO1xuICAgIHJldHVybiBtZXNzYWdlO1xuICB9XG5cbiAgLyoqXG4gICAqIFN1YnNjcmliZSB0byBgdG9waWNgLCByZXR1cm5pbmcgdGhlIGZ1bmN0aW9uIHRoYXQgdW5zdWJzY3JpYmVzLlxuICAgKlxuICAgKiBDb25uZWN0cyBvbiBmaXJzdCB1c2UuIFNldmVyYWwgbGlzdGVuZXJzIG1heSBzaGFyZSBhIHRvcGljOyBlYWNoIGlzIGNhbGxlZFxuICAgKiBvbmNlIHBlciBtZXNzYWdlLiBPbmx5IG1lc3NhZ2VzIHB1Ymxpc2hlZCBBRlRFUiB0aGlzIHJlc29sdmVzIGFycml2ZSwgc29cbiAgICogc3Vic2NyaWJlIGJlZm9yZSB0cmlnZ2VyaW5nIHdoYXRldmVyIHlvdSBleHBlY3QgdG8gb2JzZXJ2ZS5cbiAgICpcbiAgICogVGhlIHJldHVybmVkIGZ1bmN0aW9uIHJlbW92ZXMganVzdCB0aGlzIGxpc3RlbmVyIGFuZCBpcyBzYWZlIHRvIGNhbGwgdHdpY2UuXG4gICAqIFRoZSBjb25uZWN0aW9uIHN0YXlzIG9wZW4gb25jZSB0aGUgbGFzdCBsaXN0ZW5lciBsZWF2ZXMgLSB7QGxpbmsgY2xvc2V9XG4gICAqIHJlbGVhc2VzIGl0IC0gc28gYSBidXMgdGhhdCBzdWJzY3JpYmVzIGFuZCB1bnN1YnNjcmliZXMgcGVyIHJlcXVlc3QgZG9lcyBub3RcbiAgICogY2h1cm4gY29ubmVjdGlvbnMuXG4gICAqL1xuICBhc3luYyBsaXN0ZW48VEJvZHkgZXh0ZW5kcyBTZXJpYWxpemFibGVWYWx1ZT4oXG4gICAgdG9waWM6IHN0cmluZyxcbiAgICBsaXN0ZW5lcjogVG9waWNMaXN0ZW5lcjxUQm9keT4sXG4gICk6IFByb21pc2U8KCkgPT4gUHJvbWlzZTx2b2lkPj4ge1xuICAgIGlmICghdG9waWMudHJpbSgpKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiVG9waWMgbXVzdCBub3QgYmUgZW1wdHlcIik7XG4gICAgYXdhaXQgdGhpcy5zdGFydCgpO1xuICAgIGNvbnN0IGxpc3RlbmVycyA9IHRoaXMubGlzdGVuZXJzLmdldCh0b3BpYykgPz8gbmV3IFNldDxUb3BpY0xpc3RlbmVyPigpO1xuICAgIGxpc3RlbmVycy5hZGQobGlzdGVuZXIgYXMgVG9waWNMaXN0ZW5lcik7XG4gICAgdGhpcy5saXN0ZW5lcnMuc2V0KHRvcGljLCBsaXN0ZW5lcnMpO1xuICAgIHJldHVybiBhc3luYyAoKSA9PiB7XG4gICAgICBsaXN0ZW5lcnMuZGVsZXRlKGxpc3RlbmVyIGFzIFRvcGljTGlzdGVuZXIpO1xuICAgICAgaWYgKGxpc3RlbmVycy5zaXplID09PSAwKSB0aGlzLmxpc3RlbmVycy5kZWxldGUodG9waWMpO1xuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQnVpbGQgdGhlIGF1dG9tYXRpYyBoYWxmIG9mIGEgbWVzc2FnZSdzIG1ldGFkYXRhLlxuICAgKlxuICAgKiBQcmVjZWRlbmNlLCB3ZWFrZXN0IGZpcnN0OiBtYWNoaW5lL3Byb2Nlc3MgY29udGV4dCwgdGhlbiBBcHBLaXQgc2VuZGVyXG4gICAqIGlkZW50aXR5LCB0aGVuIHRoaXMgYnVzJ3MgY29uZmlndXJlZCBtZXRhZGF0YS4gVGhlIGNhbGxlcidzIHBlci1tZXNzYWdlXG4gICAqIG1ldGFkYXRhIGlzIGxheWVyZWQgb3ZlciB0aGUgcmVzdWx0IGluIHtAbGluayBicm9hZGNhc3R9LCBzbyB0aGUgbW9zdCBzcGVjaWZpY1xuICAgKiBzb3VyY2UgYWx3YXlzIHdpbnMgYW5kIG5vdGhpbmcgaGVyZSBjYW4gb3ZlcndyaXRlIGFuIGV4cGxpY2l0IGtleS5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcmVzb2x2ZU1ldGFkYXRhKCk6IFByb21pc2U8VG9waWNNZXRhZGF0YT4ge1xuICAgIGNvbnN0IHNlbmRlciA9IGF3YWl0IHNlbmRlck1ldGFkYXRhKCk7XG4gICAgY29uc3QgY29uZmlndXJlZCA9XG4gICAgICB0eXBlb2YgdGhpcy5tZXRhZGF0YSA9PT0gXCJmdW5jdGlvblwiID8gYXdhaXQgdGhpcy5tZXRhZGF0YSgpIDogKHRoaXMubWV0YWRhdGEgPz8ge30pO1xuICAgIHJldHVybiB7IC4uLm1hY2hpbmVNZXRhZGF0YSgpLCAuLi5zZW5kZXIsIC4uLmNvbmZpZ3VyZWQgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWxlYXNlIHRoZSBub3RpZmljYXRpb24gY29ubmVjdGlvbiBhbmQgc3RvcCBkZWxpdmVyaW5nIG1lc3NhZ2VzLiBJZGVtcG90ZW50LlxuICAgKlxuICAgKiBDYW5jZWxzIGFueSBwZW5kaW5nIHJlY29ubmVjdCwgZHJvcHMgYWxsIGxpc3RlbmVycywgdGhlbiBgVU5MSVNURU5gcyBhbmRcbiAgICogcmV0dXJucyB0aGUgY2xpZW50IHRvIHRoZSBwb29sLiBBIGZhaWxlZCBgVU5MSVNURU5gIGlzIHJlcG9ydGVkIHRvIHRoZSBwb29sIGFzXG4gICAqIGEgcmVsZWFzZSBlcnJvciBzbyB0aGUgY29ubmVjdGlvbiBpcyBESVNDQVJERUQgcmF0aGVyIHRoYW4gaGFuZGVkIHRvIHRoZSBuZXh0XG4gICAqIGNhbGxlciBzdGlsbCBzdWJzY3JpYmVkIHRvIHRoZSBjaGFubmVsLiBEb2VzIG5vdCB0aHJvdzsgdGhlIGJ1cyBzdGF5cyBjbG9zZWQuXG4gICAqL1xuICBhc3luYyBjbG9zZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5jbG9zZWQpIHJldHVybjtcbiAgICB0aGlzLmNsb3NlZCA9IHRydWU7XG4gICAgdGhpcy5yZWNvbm5lY3RBYm9ydC5hYm9ydChuZXcgRXJyb3IoXCJQb3N0Z3JlcyB0b3BpYyBidXMgaXMgY2xvc2VkXCIpKTtcbiAgICBhd2FpdCB0aGlzLnN0YXJ0aW5nPy5jYXRjaCgoKSA9PiB1bmRlZmluZWQpO1xuICAgIGF3YWl0IHRoaXMucmVjb25uZWN0aW5nPy5jYXRjaCgoKSA9PiB1bmRlZmluZWQpO1xuICAgIGNvbnN0IGNsaWVudCA9IHRoaXMuY2xpZW50O1xuICAgIHRoaXMuY2xpZW50ID0gdW5kZWZpbmVkO1xuICAgIHRoaXMubGlzdGVuZXJzLmNsZWFyKCk7XG4gICAgaWYgKCFjbGllbnQpIHJldHVybjtcbiAgICBjbGllbnQucmVtb3ZlTGlzdGVuZXIoXCJub3RpZmljYXRpb25cIiwgdGhpcy5oYW5kbGVOb3RpZmljYXRpb24pO1xuICAgIGNsaWVudC5yZW1vdmVMaXN0ZW5lcihcImVycm9yXCIsIHRoaXMuaGFuZGxlQ2xpZW50RXJyb3IpO1xuICAgIGxldCByZWxlYXNlRXJyb3I6IEVycm9yIHwgdW5kZWZpbmVkO1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBjbGllbnQucXVlcnkoYFVOTElTVEVOICR7cXVvdGVJZGVudGlmaWVyKHRoaXMuY2hhbm5lbE5hbWUpfWApO1xuICAgIH0gY2F0Y2ggKGNhdXNlKSB7XG4gICAgICByZWxlYXNlRXJyb3IgPSBlcnJvci50b0Vycm9yKGNhdXNlKTtcbiAgICB9XG4gICAgY2xpZW50LnJlbGVhc2UocmVsZWFzZUVycm9yKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBvdXQgb25lIGNsaWVudCwgYXR0YWNoIHRoZSBoYW5kbGVycywgYW5kIGBMSVNURU5gLlxuICAgKlxuICAgKiBUaGUgaGFuZGxlcnMgYXJlIGF0dGFjaGVkIEJFRk9SRSB0aGUgYExJU1RFTmAgcm91bmQgdHJpcCBzbyBhIG5vdGlmaWNhdGlvbiBvclxuICAgKiBlcnJvciBhcnJpdmluZyBtaWQtc2V0dXAgaXMgbm90IG1pc3NlZC4gQW55IGZhaWx1cmUgLSBpbmNsdWRpbmcgdGhlIGJ1cyBiZWluZ1xuICAgKiBjbG9zZWQgd2hpbGUgdGhlIGNvbm5lY3Qgd2FzIGluIGZsaWdodCAtIGRldGFjaGVzIHRoZSBoYW5kbGVycyBhbmQgcmVsZWFzZXNcbiAgICogdGhlIGNsaWVudCBhcyBlcnJvcmVkLCBzbyBhIGhhbGYtY29uZmlndXJlZCBjb25uZWN0aW9uIG5ldmVyIHJldHVybnMgdG8gdGhlXG4gICAqIHBvb2wuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGNvbm5lY3QoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgY2xpZW50ID0gYXdhaXQgdGhpcy5wb29sLmNvbm5lY3QoKTtcbiAgICB0cnkge1xuICAgICAgY2xpZW50Lm9uKFwibm90aWZpY2F0aW9uXCIsIHRoaXMuaGFuZGxlTm90aWZpY2F0aW9uKTtcbiAgICAgIGNsaWVudC5vbihcImVycm9yXCIsIHRoaXMuaGFuZGxlQ2xpZW50RXJyb3IpO1xuICAgICAgYXdhaXQgY2xpZW50LnF1ZXJ5KGBMSVNURU4gJHtxdW90ZUlkZW50aWZpZXIodGhpcy5jaGFubmVsTmFtZSl9YCk7XG4gICAgICBpZiAodGhpcy5jbG9zZWQpIHRocm93IG5ldyBFcnJvcihcIlBvc3RncmVzIHRvcGljIGJ1cyBpcyBjbG9zZWRcIik7XG4gICAgICB0aGlzLmNsaWVudCA9IGNsaWVudDtcbiAgICB9IGNhdGNoIChjYXVzZSkge1xuICAgICAgY2xpZW50LnJlbW92ZUxpc3RlbmVyKFwibm90aWZpY2F0aW9uXCIsIHRoaXMuaGFuZGxlTm90aWZpY2F0aW9uKTtcbiAgICAgIGNsaWVudC5yZW1vdmVMaXN0ZW5lcihcImVycm9yXCIsIHRoaXMuaGFuZGxlQ2xpZW50RXJyb3IpO1xuICAgICAgY2xpZW50LnJlbGVhc2UoZXJyb3IudG9FcnJvcihjYXVzZSkpO1xuICAgICAgdGhyb3cgY2F1c2U7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJvdXRlIG9uZSBpbmJvdW5kIG5vdGlmaWNhdGlvbiB0byB0aGUgdG9waWMncyBsaXN0ZW5lcnMuXG4gICAqXG4gICAqIElnbm9yZXMgb3RoZXIgY2hhbm5lbHMgYW5kIHVuZGVjb2RhYmxlIHBheWxvYWRzIC0gdGhlIGNoYW5uZWwgaXMgc2hhcmVkLCBzb1xuICAgKiBib3RoIGFyZSBvcmRpbmFyeSB0cmFmZmljLiBMaXN0ZW5lcnMgYXJlIGludm9rZWQgY29uY3VycmVudGx5IGFuZCB0aGVpclxuICAgKiByZWplY3Rpb25zIGdvIHRvIGBvbkVycm9yYCwga2VlcGluZyBvbmUgc2xvdyBvciBicm9rZW4gc3Vic2NyaWJlciBmcm9tXG4gICAqIHN0YWxsaW5nIHRoZSBub3RpZmljYXRpb24gY29ubmVjdGlvbi5cbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgaGFuZGxlTm90aWZpY2F0aW9uID0gKG5vdGlmaWNhdGlvbjogTm90aWZpY2F0aW9uKTogdm9pZCA9PiB7XG4gICAgaWYgKG5vdGlmaWNhdGlvbi5jaGFubmVsICE9PSB0aGlzLmNoYW5uZWxOYW1lKSByZXR1cm47XG4gICAgY29uc3QgbWVzc2FnZSA9IGRlY29kZShub3RpZmljYXRpb24ucGF5bG9hZCk7XG4gICAgaWYgKCFtZXNzYWdlKSByZXR1cm47XG4gICAgZm9yIChjb25zdCBsaXN0ZW5lciBvZiB0aGlzLmxpc3RlbmVycy5nZXQobWVzc2FnZS50b3BpYykgPz8gW10pIHtcbiAgICAgIFByb21pc2UucmVzb2x2ZShsaXN0ZW5lcihtZXNzYWdlKSkuY2F0Y2godGhpcy5vbkVycm9yKTtcbiAgICB9XG4gIH07XG5cbiAgLyoqXG4gICAqIEhhbmRsZSB0aGUgbm90aWZpY2F0aW9uIGNvbm5lY3Rpb24gZHlpbmcsIHdoaWNoIGBwZ2AgcmVwb3J0cyBhcyBhbiBgZXJyb3JgXG4gICAqIGV2ZW50IHJhdGhlciB0aGFuIGEgcmVqZWN0ZWQgcXVlcnkuXG4gICAqXG4gICAqIFRoZSBjbGllbnQgaXMgdW51c2FibGUgYXQgdGhpcyBwb2ludCwgc28gaXQgaXMgZGV0YWNoZWQgYW5kIHJlbGVhc2VkIGFzXG4gICAqIGVycm9yZWQgKHdoaWNoIGRpc2NhcmRzIGl0KSBiZWZvcmUgYW55dGhpbmcgZWxzZS4gUmVjb25uZWN0aW9uIG9ubHkgc3RhcnRzXG4gICAqIHdoZW4gdGhlcmUgaXMgc3RpbGwgc29tZW9uZSB0byBkZWxpdmVyIHRvLCBzbyBhbiBpZGxlIG9yIGNsb3NpbmcgYnVzIGRvZXMgbm90XG4gICAqIGhvbGQgYSBjb25uZWN0aW9uIG9wZW4gY2hhc2luZyBhIGNoYW5uZWwgbm9ib2R5IHJlYWRzLlxuICAgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBoYW5kbGVDbGllbnRFcnJvciA9IChjYXVzZTogRXJyb3IpOiB2b2lkID0+IHtcbiAgICB0aGlzLm9uRXJyb3IoY2F1c2UpO1xuICAgIGNvbnN0IGNsaWVudCA9IHRoaXMuY2xpZW50O1xuICAgIGlmICghY2xpZW50KSByZXR1cm47XG4gICAgdGhpcy5jbGllbnQgPSB1bmRlZmluZWQ7XG4gICAgY2xpZW50LnJlbW92ZUxpc3RlbmVyKFwibm90aWZpY2F0aW9uXCIsIHRoaXMuaGFuZGxlTm90aWZpY2F0aW9uKTtcbiAgICBjbGllbnQucmVtb3ZlTGlzdGVuZXIoXCJlcnJvclwiLCB0aGlzLmhhbmRsZUNsaWVudEVycm9yKTtcbiAgICBjbGllbnQucmVsZWFzZShjYXVzZSk7XG4gICAgaWYgKHRoaXMuY2xvc2VkIHx8IHRoaXMubGlzdGVuZXJzLnNpemUgPT09IDApIHJldHVybjtcbiAgICB0aGlzLnJlY29ubmVjdGluZyA/Pz0gdGhpcy5yZWNvbm5lY3QoKS5maW5hbGx5KCgpID0+IHtcbiAgICAgIHRoaXMucmVjb25uZWN0aW5nID0gdW5kZWZpbmVkO1xuICAgIH0pO1xuICB9O1xuXG4gIC8qKlxuICAgKiBSZS1lc3RhYmxpc2ggdGhlIG5vdGlmaWNhdGlvbiBjb25uZWN0aW9uIHdpdGggYm91bmRlZCBleHBvbmVudGlhbCBiYWNrb2ZmLlxuICAgKlxuICAgKiBUaGUgZmlyc3QgYXR0ZW1wdCBpcyBpbW1lZGlhdGUsIHNpbmNlIHRoZSBjb21tb24gY2FzZSBpcyBhIHNpbmdsZSBkcm9wcGVkXG4gICAqIGNvbm5lY3Rpb24gdGhhdCByZWNvbm5lY3RzIGF0IG9uY2U7IHN1YnNlcXVlbnQgZGVsYXlzIGRvdWJsZSBmcm9tIDI1MG1zIHVwIHRvXG4gICAqIDVzIGFuZCBzdGF5IHRoZXJlLiBSZXRyaWVzIGluZGVmaW5pdGVseSByYXRoZXIgdGhhbiBnaXZpbmcgdXAsIGJlY2F1c2UgYSBQb3N0Z3JlcyByZXN0YXJ0XG4gICAqIG9yIGEgcm90YXRlZCBMYWtlYmFzZSBjcmVkZW50aWFsIGlzIGEgcmVjb3ZlcmFibGUgb3V0YWdlIGFuZCBhIHNpbGVudGx5IGRlYWRcbiAgICogbGlzdGVuZXIgaXMgd29yc2UgdGhhbiBhIG5vaXN5IG9uZS4gU3RvcHMgd2hlbiB0aGUgYnVzIGNsb3NlcyBvciB0aGUgbGFzdFxuICAgKiBsaXN0ZW5lciBsZWF2ZXMsIGFuZCByZXBvcnRzIGV2ZXJ5IGZhaWxlZCBhdHRlbXB0IHRocm91Z2ggYG9uRXJyb3JgLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyByZWNvbm5lY3QoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgbGV0IGRlbGF5ID0gMDtcbiAgICB3aGlsZSAoIXRoaXMuY2xvc2VkICYmIHRoaXMubGlzdGVuZXJzLnNpemUgPiAwKSB7XG4gICAgICBpZiAoZGVsYXkgPiAwKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYXdhaXQgYXN5bmNVdGlsLnNsZWVwKGRlbGF5LCB0aGlzLnJlY29ubmVjdEFib3J0LnNpZ25hbCk7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgdGhpcy5zdGFydCgpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9IGNhdGNoIChjYXVzZSkge1xuICAgICAgICBpZiAodGhpcy5jbG9zZWQpIHJldHVybjtcbiAgICAgICAgdGhpcy5vbkVycm9yKGNhdXNlKTtcbiAgICAgICAgZGVsYXkgPSBkZWxheSA9PT0gMCA/IE1JTl9SRUNPTk5FQ1RfREVMQVlfTVMgOiBNYXRoLm1pbihkZWxheSAqIDIsIE1BWF9SRUNPTk5FQ1RfREVMQVlfTVMpO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuIl19
538
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9waWMtYnVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3RvcGljLWJ1cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBd0JHO0FBRUgsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUNuQyxPQUFPLEVBQUUsS0FBSyxJQUFJLFNBQVMsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFJL0YsT0FBTyxFQUFFLGNBQWMsRUFBRSxPQUFPLEVBQUUsZUFBZSxFQUFFLHlCQUF5QixFQUFFLHlCQUF5QixFQUFtSixNQUFNLGtCQUFrQixDQUFDO0FBUW5SLG9FQUFvRTtBQUNwRSxNQUFNLGVBQWUsR0FBRyxxQkFBcUIsQ0FBQztBQUM5Qzs7OztHQUlHO0FBQ0gsTUFBTSxrQkFBa0IsR0FBRyxFQUFFLENBQUM7QUFDOUIscUZBQXFGO0FBQ3JGLE1BQU0sbUJBQW1CLEdBQUcsQ0FBQyxDQUFDO0FBQzlCLDBFQUEwRTtBQUMxRSxNQUFNLGdCQUFnQixHQUFHLEtBQUssQ0FBQztBQUMvQjs7OztHQUlHO0FBQ0gsTUFBTSxnQkFBZ0IsR0FBRyxLQUFLLENBQUM7QUFDL0IsTUFBTSxzQkFBc0IsR0FBRyxHQUFHLENBQUM7QUFDbkMsTUFBTSxzQkFBc0IsR0FBRyxLQUFLLENBQUM7QUFrQnJDOzs7O0dBSUc7QUFDSCxJQUFJLFlBQTJELENBQUM7QUFnSGhFOzs7O0dBSUc7QUFDSCxTQUFTLGVBQWUsQ0FBQyxNQUFxRDtJQUM1RSxPQUFPLE1BQU0sQ0FBQyxXQUFXLENBQ3ZCLE1BQU0sQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsS0FBSyxFQUF3QyxFQUFFO1FBQzVFLE9BQU8sS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLFNBQVMsQ0FBQztJQUNoQyxD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QyxTQUFTLENBQUMsSUFBSSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQy9DLElBQUksS0FBSyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNkLElBQUksQ0FBQztvQkFDSCxNQUFNLFNBQVMsQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQzNELENBQUM7Z0JBQUMsTUFBTSxDQUFDO29CQUNQLE9BQU87Z0JBQ1QsQ0FBQztZQUNILENBQUM7WUFDRCxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7Z0JBQ25CLE9BQU87WUFDVCxDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZixJQUFJLElBQUksQ0FBQyxNQUFNO29CQUFFLE9BQU87Z0JBQ3hCLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQ3BCLEtBQUssR0FBRyxLQUFLLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxFQUFFLHNCQUFzQixDQUFDLENBQUM7WUFDN0YsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFRvcGljIGZhbi1vdXQgb3ZlciBQb3N0Z3JlU1FMIGBMSVNURU5gL2BOT1RJRllgLCBmb3IgdGVsbGluZyBldmVyeSBydW5uaW5nXG4gKiBpbnN0YW5jZSBvZiBhbiBhcHAgdGhhdCBzb21ldGhpbmcgaGFwcGVuZWQuXG4gKlxuICogVGhlIHNpYmxpbmcgYGFkdmlzb3J5LWxvY2tgIG1vZHVsZSBpcyBhYm91dCBtYWtpbmcgc3VyZSBvbmx5IE9ORSBjb25uZWN0aW9uXG4gKiBkb2VzIGEgdGhpbmc7IHRoaXMgb25lIGlzIHRoZSBvcHBvc2l0ZSAtIEVWRVJZIGxpc3RlbmluZyBzZXNzaW9uIGdldHMgZXZlcnlcbiAqIG5vdGlmaWNhdGlvbi4gVGhhdCBtYWtlcyBpdCB0aGUgcmlnaHQgcHJpbWl0aXZlIGZvciBsaXZlIFVJIHVwZGF0ZXNcbiAqIChhbiBTU0Ugc3RyZWFtIHBlciBicm93c2VyIHRhYiwgYSBjYWNoZSBpbnZhbGlkYXRpb24sIGEgcHJlc2VuY2UgcGluZykgYW5kIHRoZVxuICogd3Jvbmcgb25lIGZvciB3b3JrIGRpc3RyaWJ1dGlvbjogdGhlcmUgYXJlIG5vIGNvbXBldGluZyBjb25zdW1lcnMsIG5vIGFja3MsIGFuZFxuICogbm8gcmVwbGF5LlxuICpcbiAqIERlbGl2ZXJ5IGlzIGJlc3QtZWZmb3J0IGFuZCBsaXZlLiBgTk9USUZZYCByZWFjaGVzIHNlc3Npb25zIHRoYXQgYXJlIGxpc3RlbmluZ1xuICogYXQgdGhlIG1vbWVudCBpdCBjb21taXRzLCBzbyBhIGxpc3RlbmVyIHRoYXQgY29ubmVjdHMgYSBzZWNvbmQgbGF0ZXIgbmV2ZXIgc2Vlc1xuICogaXQsIGFuZCBhIGxpc3RlbmVyIHdob3NlIGNvbm5lY3Rpb24gZHJvcHMgbWlzc2VzIGV2ZXJ5dGhpbmcgdW50aWwgdGhlIGJ1c1xuICogcmVjb25uZWN0cy4gVXNlIGEgdGFibGUgb3IgYSBxdWV1ZSB3aGVuIGEgc3Vic2NyaWJlciBuZWVkcyBkdXJhYmlsaXR5LlxuICpcbiAqIE9ORSBDSEFOTkVMLCBNQU5ZIFRPUElDUy4gRXZlcnkgYnVzIGluc3RhbmNlIGxpc3RlbnMgb24gYSBzaW5nbGUgUG9zdGdyZXNcbiAqIGNoYW5uZWwgKGBjaGFubmVsYCwgZGVmYXVsdCBgZGJ4X3Rvb2xzX3RvcGljX2J1c2ApIGFuZCBmaWx0ZXJzIGJ5IHRoZVxuICogZW52ZWxvcGUncyBgdG9waWNgIGluLXByb2Nlc3MsIHNvIGFkZGluZyBhIHRvcGljIGNvc3RzIG5vIGNvbm5lY3Rpb24gYW5kIG5vXG4gKiBgTElTVEVOYC4gVGhlIHRyYWRlb2ZmIGlzIHRoYXQgZXZlcnkgbGlzdGVuaW5nIHNlc3Npb24gZGVjb2RlcyBldmVyeSBtZXNzYWdlIG9uXG4gKiB0aGUgY2hhbm5lbDsgZ2l2ZSBhIGdlbnVpbmVseSBoaWdoLXZvbHVtZSwgdW5yZWxhdGVkIHN0cmVhbSBpdHMgb3duIGBjaGFubmVsYFxuICogcmF0aGVyIHRoYW4gYSB0b3BpYy5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgaG9zdG5hbWUgfSBmcm9tIFwibm9kZTpvc1wiO1xuaW1wb3J0IHsgYXN5bmMgYXMgYXN5bmNVdGlsLCBlcnJvciwgaGFzaCwganNvbiwgb2JqZWN0LCBzdHJpbmcgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHR5cGUgeyBOb3RpZmljYXRpb24sIFBvb2xDbGllbnQgfSBmcm9tIFwicGdcIjtcblxuaW1wb3J0IHR5cGUgeyBQZ1Bvb2xMaWtlLCBQZ1F1ZXJ5YWJsZSB9IGZyb20gXCIuL2Fkdmlzb3J5LWxvY2sudHNcIjtcbmltcG9ydCB7IGNsZWFudXBFeHBpcmVkLCBoaXN0b3J5LCBwZXJzaXN0ZWROb3RpZnksIHByb3Zpc2lvbk1lc3NhZ2VCdXNTY2hlbWEsIHJlc29sdmVQZXJzaXN0ZW5jZU9wdGlvbnMsIHR5cGUgRHVyYXRpb25JbnB1dCwgdHlwZSBSZXNvbHZlZFRvcGljQnVzUGVyc2lzdGVuY2VPcHRpb25zLCB0eXBlIFRvcGljQnVzUGVyc2lzdGVuY2VPcHRpb25zLCB0eXBlIFRvcGljSGlzdG9yeVBhZ2UsIHR5cGUgVG9waWNQZXJzaXN0ZW5jZVNjb3BlIH0gZnJvbSBcIi4vcGVyc2lzdGVuY2UudHNcIjtcblxuLyoqXG4gKiBgQGRieC10b29scy9zaGFyZWQtY29yZWAgb3ducyB0aGUgSlNPTi1yb3VuZC10cmlwIHJ1bGU7IHRoaXMgYWxpYXMganVzdCBrZWVwcyB0aGVcbiAqIGdlbmVyaWMgc2lnbmF0dXJlcyBiZWxvdyByZWFkYWJsZS4gQ29uc3VtZXJzIGltcG9ydCB0aGUgdHlwZSBmcm9tIHNoYXJlZC1jb3JlLlxuICovXG50eXBlIFNlcmlhbGl6YWJsZVZhbHVlID0gb2JqZWN0LlNlcmlhbGl6YWJsZVZhbHVlO1xuXG4vKiogQ2hhbm5lbCBwYXJ0cyB1c2VkIHdoZW4gYSBjYWxsZXIgbmFtZXMgbm8gY2hhbm5lbCBvZiBpdHMgb3duLiAqL1xuY29uc3QgREVGQVVMVF9DSEFOTkVMID0gXCJkYnhfdG9vbHNfdG9waWNfYnVzXCI7XG4vKipcbiAqIGBOQU1FREFUQUxFTiAtIDFgLiBQb3N0Z3JlcyBUUlVOQ0FURVMgYSBsb25nZXIgY2hhbm5lbCBuYW1lIHJhdGhlciB0aGFuXG4gKiByZWplY3RpbmcgaXQsIHdoaWNoIHdvdWxkIHNwbGl0IHB1Ymxpc2hlcnMgYW5kIGxpc3RlbmVycyBvbnRvIGRpZmZlcmVudFxuICogY2hhbm5lbHMgd2hpbGUgZXZlcnkgY2FsbCBsb29rZWQgbGlrZSBpdCBzdWNjZWVkZWQuXG4gKi9cbmNvbnN0IE1BWF9DSEFOTkVMX0xFTkdUSCA9IDYzO1xuLyoqIEJhc2UtMzIgY2hhcnMgb2YgdGhlIGNoYW5uZWwncyBpZGVudGl0eSBzdWZmaXguIE1heCA3IC0gdGhlIGRpZ2VzdCBpcyAzMiBiaXRzLiAqL1xuY29uc3QgQ0hBTk5FTF9IQVNIX0xFTkdUSCA9IDY7XG4vKiogQm9keSB1c2VkIHdoZW4gdGhlIHBhcnRzIHRva2VuaXplIHRvIG5vdGhpbmcsIG9yIGxlYWQgd2l0aCBhIGRpZ2l0LiAqL1xuY29uc3QgQ0hBTk5FTF9GQUxMQkFDSyA9IFwiYnVzXCI7XG4vKipcbiAqIEVuY29kZWQtZW52ZWxvcGUgY2VpbGluZy4gUG9zdGdyZVNRTCBjYXBzIGEgYE5PVElGWWAgcGF5bG9hZCBhdCA4MDAwIGJ5dGVzIGFuZFxuICogZmFpbHMgdGhlIHN0YXRlbWVudCBwYXN0IHRoYXQsIHNvIHRoZSBidXMgcmVqZWN0cyB0aGUgbWVzc2FnZSBmaXJzdCB3aXRoIGEgc2l6ZVxuICogaXQgY2FuIG5hbWUuIFRoZSBtYXJnaW4gYmVsb3cgODAwMCBjb3ZlcnMgdGhlIHNlcnZlcidzIG93biBhY2NvdW50aW5nLlxuICovXG5jb25zdCBNQVhfTk9USUZZX0JZVEVTID0gN185MDA7XG5jb25zdCBNSU5fUkVDT05ORUNUX0RFTEFZX01TID0gMjUwO1xuY29uc3QgTUFYX1JFQ09OTkVDVF9ERUxBWV9NUyA9IDVfMDAwO1xuXG4vKipcbiAqIFRoZSBzdWJzZXQgb2YgQXBwS2l0J3MgcGVyLXJlcXVlc3QgZXhlY3V0aW9uIGNvbnRleHQgdGhlIGJ1cyByZWFkcyBmb3Igc2VuZGVyXG4gKiBpZGVudGl0eS4gRmllbGRzIGFyZSBgdW5rbm93bmAgYmVjYXVzZSB0aGlzIGlzIGEgc3RydWN0dXJhbCB2aWV3IG9mIGFuIE9QVElPTkFMXG4gKiBwZWVyOiB0aGUgdmFsdWVzIGFyZSB0cmltbWVkIGFuZCB2YWxpZGF0ZWQgcmF0aGVyIHRoYW4gdHJ1c3RlZC5cbiAqL1xudHlwZSBBcHBLaXRFeGVjdXRpb25Db250ZXh0ID0ge1xuICB1c2VyRW1haWw/OiB1bmtub3duO1xuICB1c2VySWQ/OiB1bmtub3duO1xuICB1c2VyTmFtZT86IHVua25vd247XG59O1xuXG4vKiogU3RydWN0dXJhbCB2aWV3IG9mIGBAZGF0YWJyaWNrcy9hcHBraXRgLCBpbXBvcnRlZCBsYXppbHkgYW5kIG5ldmVyIHJlcXVpcmVkLiAqL1xudHlwZSBBcHBLaXRNb2R1bGUgPSB7XG4gIGdldEV4ZWN1dGlvbkNvbnRleHQoKTogQXBwS2l0RXhlY3V0aW9uQ29udGV4dDtcbn07XG5cbi8qKlxuICogQ2FjaGVkIHJlc3VsdCBvZiB0aGUgb25lIG9wdGlvbmFsLXBlZXIgaW1wb3J0LCByZXNvbHZlZCB0byBgdW5kZWZpbmVkYCB3aGVuXG4gKiBBcHBLaXQgaXMgbm90IGluc3RhbGxlZC4gTWVtb2l6ZWQgc28gYSBidXMgaW4gYSBwbGFpbiBQb3N0Z3JlcyBwcm9jZXNzIHBheXMgZm9yXG4gKiB0aGUgZmFpbGVkIHJlc29sdXRpb24gb25jZSBpbnN0ZWFkIG9mIHBlciBicm9hZGNhc3QuXG4gKi9cbmxldCBhcHBLaXRNb2R1bGU6IFByb21pc2U8QXBwS2l0TW9kdWxlIHwgdW5kZWZpbmVkPiB8IHVuZGVmaW5lZDtcblxuLyoqXG4gKiBGbGF0LWtleWVkIGNvbnRleHQgdHJhdmVsbGluZyBhbG9uZ3NpZGUgYSBtZXNzYWdlIGJvZHk6IHdobyBzZW50IGl0LCBmcm9tXG4gKiB3aGVyZSwgaW4gd2hpY2ggZGVwbG95bWVudC4gVmFsdWVzIG1heSBuZXN0LCBidXQgdGhlIGtleXMgYXJlIHRoZSBhZGRyZXNzYWJsZVxuICogcGFydCAtIGEgbGlzdGVuZXIgZmlsdGVyaW5nIG9yIGxhYmVsbGluZyBtZXNzYWdlcyByZWFkcyBgbWV0YWRhdGEudXNlcmAsIG5vdCBhXG4gKiBwYXRoIGludG8gdGhlIGJvZHkuXG4gKi9cbmV4cG9ydCB0eXBlIFRvcGljTWV0YWRhdGEgPSBSZWNvcmQ8c3RyaW5nLCBTZXJpYWxpemFibGVWYWx1ZT47XG5cbi8qKlxuICogVGhlIHdpcmUgZW52ZWxvcGUgZXZlcnkgc3Vic2NyaWJlciByZWNlaXZlcywgYW5kIHdoYXQge0BsaW5rXG4gKiBQb3N0Z3Jlc1RvcGljQnVzLmJyb2FkY2FzdH0gcmV0dXJucyB0byB0aGUgcHVibGlzaGVyLlxuICpcbiAqIGBpZGAsIGB0b3BpY2AsIGFuZCBgcHVibGlzaGVkQXRgIGFyZSBhc3NpZ25lZCBieSB0aGUgYnVzOyBgdHlwZWAsIGBtZXRhZGF0YWAsXG4gKiBhbmQgYGJvZHlgIGNvbWUgZnJvbSB0aGUgY2FsbGVyICh3aXRoIGF1dG9tYXRpYyBjb250ZXh0IG1lcmdlZCB1bmRlclxuICogYG1ldGFkYXRhYCkuIFRoZSBzaGFwZSBpcyBzdGFibGUgZW5vdWdoIHRvIGhhbmQgc3RyYWlnaHQgdG8gYW4gU1NFIGBkYXRhOmBcbiAqIGZyYW1lLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFRvcGljTWVzc2FnZTxUQm9keSBleHRlbmRzIFNlcmlhbGl6YWJsZVZhbHVlID0gU2VyaWFsaXphYmxlVmFsdWU+IHtcbiAgLyoqXG4gICAqIFBlci1tZXNzYWdlIGlkZW50aXR5IGdlbmVyYXRlZCBieSB0aGUgcHVibGlzaGVyLCB1bmlxdWUgYWNyb3NzIGluc3RhbmNlcy5cbiAgICogU3VpdGFibGUgZm9yIGRlZHVwZSB3aGVuIGEgY2xpZW50IHJlY29ubmVjdHMgYW5kIGZvciBhbiBTU0UgYGlkOmAgZmllbGQuIE5vdFxuICAgKiBvcmRlcmVkLCBhbmQgbm90IGEgZGF0YWJhc2Uga2V5LlxuICAgKi9cbiAgaWQ6IHN0cmluZztcbiAgLyoqIFRoZSB0b3BpYyB0aGlzIHdhcyBicm9hZGNhc3Qgb247IGxpc3RlbmVycyBvbiBvdGhlciB0b3BpY3MgbmV2ZXIgc2VlIGl0LiAqL1xuICB0b3BpYzogc3RyaW5nO1xuICAvKiogQ2FsbGVyLWNob3NlbiBldmVudCBuYW1lLCBlLmcuIGBvcmRlci51cGRhdGVkYC4gTmV2ZXIgZW1wdHkuICovXG4gIHR5cGU6IHN0cmluZztcbiAgLyoqIEF1dG9tYXRpYyBjb250ZXh0IG1lcmdlZCB3aXRoIGNhbGxlciBtZXRhZGF0YS4gU2VlIHtAbGluayBUb3BpY01ldGFkYXRhfS4gKi9cbiAgbWV0YWRhdGE6IFRvcGljTWV0YWRhdGE7XG4gIC8qKiBUaGUgY2FsbGVyJ3MgcGF5bG9hZCwgdW5jaGFuZ2VkLiAqL1xuICBib2R5OiBUQm9keTtcbiAgLyoqXG4gICAqIElTTy04NjAxIHB1Ymxpc2ggdGltZSBmcm9tIHRoZSBQVUJMSVNISU5HIHByb2Nlc3MncyBjbG9jaywgbm90IHRoZSBkYXRhYmFzZSdzLlxuICAgKiBGaW5lIGZvciBkaXNwbGF5OyBkbyBub3Qgb3JkZXIgbWVzc2FnZXMgZnJvbSBkaWZmZXJlbnQgaW5zdGFuY2VzIGJ5IGl0LlxuICAgKi9cbiAgcHVibGlzaGVkQXQ6IHN0cmluZztcbn1cblxuLyoqIFdoYXQgYSBjYWxsZXIgc3VwcGxpZXMgdG8ge0BsaW5rIFBvc3RncmVzVG9waWNCdXMuYnJvYWRjYXN0fS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVG9waWNQdWJsaXNoSW5wdXQ8VEJvZHkgZXh0ZW5kcyBTZXJpYWxpemFibGVWYWx1ZSA9IFNlcmlhbGl6YWJsZVZhbHVlPiB7XG4gIC8qKiBFdmVudCBuYW1lLCBlLmcuIGBjaGF0Lm1lc3NhZ2VgLiBNdXN0IGJlIG5vbi1ibGFuay4gKi9cbiAgdHlwZTogc3RyaW5nO1xuICAvKipcbiAgICogQ29udGV4dCB0byBhdHRhY2guIFdpbnMgb3ZlciBhbnkgYXV0b21hdGljIGtleSBvZiB0aGUgc2FtZSBuYW1lLCBzbyBhIGNhbGxlclxuICAgKiBjYW4gb3ZlcnJpZGUgYSBtYWNoaW5lIGRlZmF1bHQgKGBwcm9qZWN0YCkgb3IgYWRkIGl0cyBvd24gKGB0cmFjZUlkYCkuXG4gICAqL1xuICBtZXRhZGF0YT86IFRvcGljTWV0YWRhdGE7XG4gIC8qKiBUaGUgcGF5bG9hZC4gTXVzdCBzYXRpc2Z5IGBvYmplY3QuaXNTZXJpYWxpemFibGVWYWx1ZWAuICovXG4gIGJvZHk6IFRCb2R5O1xuICBzY29wZT86IFRvcGljUGVyc2lzdGVuY2VTY29wZTtcbiAgdHRsPzogRHVyYXRpb25JbnB1dCB8IGZhbHNlO1xufVxuXG4vKipcbiAqIFN1YnNjcmliZXIgY2FsbGJhY2suIEludm9rZWQgb25jZSBwZXIgbWF0Y2hpbmcgbWVzc2FnZSBvbiB0aGUgbm90aWZpY2F0aW9uXG4gKiBjb25uZWN0aW9uJ3MgY2FsbGJhY2ssIHNvIGl0IHNob3VsZCBub3QgYmxvY2s6IGEgcmV0dXJuZWQgcHJvbWlzZSBpcyBhd2FpdGVkXG4gKiBvbmx5IHRvIHJvdXRlIGEgcmVqZWN0aW9uIHRvIGBvbkVycm9yYCwgYW5kIGxpc3RlbmVycyBmb3Igb25lIG1lc3NhZ2UgcnVuXG4gKiBjb25jdXJyZW50bHkgcmF0aGVyIHRoYW4gaW4gcmVnaXN0cmF0aW9uIG9yZGVyLlxuICpcbiAqIGBUQm9keWAgaXMgdW5jaGVja2VkIGF0IHJ1bnRpbWUuIFRoZSBidXMgZ3VhcmFudGVlcyB0aGUgYm9keSBpcyBzZXJpYWxpemFibGUsXG4gKiBub3QgdGhhdCBpdCBtYXRjaGVzIHRoZSB0eXBlIHBhcmFtZXRlciwgc28gdmFsaWRhdGUgYW55dGhpbmcgYSBsaXN0ZW5lclxuICogYnJhbmNoZXMgb24uXG4gKi9cbmV4cG9ydCB0eXBlIFRvcGljTGlzdGVuZXI8VEJvZHkgZXh0ZW5kcyBTZXJpYWxpemFibGVWYWx1ZSA9IFNlcmlhbGl6YWJsZVZhbHVlPiA9IChcbiAgbWVzc2FnZTogVG9waWNNZXNzYWdlPFRCb2R5PixcbikgPT4gdm9pZCB8IFByb21pc2VMaWtlPHZvaWQ+O1xuXG4vKipcbiAqIFJlc29sdmVzIG1ldGFkYXRhIGF0IHB1Ymxpc2ggdGltZSBpbnN0ZWFkIG9mIGNvbnN0cnVjdGlvbiB0aW1lLCBmb3IgY29udGV4dCBhXG4gKiBwcm9jZXNzIGxlYXJucyBsYXRlIG9yIGFzeW5jaHJvbm91c2x5IC0gYW4gaW5zdGFuY2UgaWQgZnJvbSBhIGNvbnRyb2wgcGxhbmUsIGFcbiAqIGRpc2NvdmVyZWQgYWRkcmVzcyBhIGNhbGxlciBjaG9vc2VzIHRvIGF0dGFjaC4gQ2FsbGVkIG9uIGV2ZXJ5IGJyb2FkY2FzdCwgc29cbiAqIG1lbW9pemUgYW55dGhpbmcgZXhwZW5zaXZlOyBhIHJlamVjdGlvbiBmYWlscyB0aGUgYnJvYWRjYXN0LlxuICovXG5leHBvcnQgdHlwZSBUb3BpY01ldGFkYXRhUHJvdmlkZXIgPSAoKSA9PiBUb3BpY01ldGFkYXRhIHwgUHJvbWlzZUxpa2U8VG9waWNNZXRhZGF0YT47XG5cbi8qKiBDb25zdHJ1Y3Rpb24gb3B0aW9ucyBmb3Ige0BsaW5rIFBvc3RncmVzVG9waWNCdXN9LiAqL1xuZXhwb3J0IGludGVyZmFjZSBQb3N0Z3Jlc1RvcGljQnVzT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBXaGF0IGlkZW50aWZpZXMgdGhpcyBjaGFubmVsIC0gYW55dGhpbmcsIG5vdCBqdXN0IGFuIGlkZW50aWZpZXI6IGEgbmFtZSwgYW5cbiAgICogaWQsIGEgYFtlbnYsIGZlYXR1cmVdYCBwYWlyLCBhIGNvbmZpZyBvYmplY3QuIFRoZSBwYXJ0cyBhcmUgdG9rZW5pemVkIGludG8gYVxuICAgKiBsZWdhbCBQb3N0Z3JlcyBjaGFubmVsIG5hbWUgd2l0aCBhIHNob3J0IGhhc2ggb2YgdGhlIG9yaWdpbmFscyBhcHBlbmRlZCwgc29cbiAgICogdGhlIGRlcml2YXRpb24gaXMgZGV0ZXJtaW5pc3RpYyBhbmQgbm8gY2FsbCBzaXRlIGhhcyB0byBzYW5pdGl6ZS4gU2VlXG4gICAqIHtAbGluayBQb3N0Z3Jlc1RvcGljQnVzLmNoYW5uZWxOYW1lfSBmb3IgdGhlIHJlc29sdmVkIG5hbWUuXG4gICAqXG4gICAqIE9uZSB2YWx1ZSBvciBtYW55OiBhbiBhcnJheSBpcyByZWFkIGFzIG11bHRpcGxlIHBhcnRzXG4gICAqICh7QGxpbmsgb2JqZWN0Lk9uZU9yTWFueX0pLCBhbnl0aGluZyBlbHNlIGFzIGEgc2luZ2xlIHBhcnQuIFNvXG4gICAqIGBbXCJiaWxsaW5nXCIsIFwicHJvZFwiXWAgYW5kIGBcImJpbGxpbmdfcHJvZFwiYCBhcmUgZGlmZmVyZW50IGNoYW5uZWxzLCBzaW5jZSB0aGVcbiAgICogaGFzaCBzZWVzIGRpZmZlcmVudCBzdHJ1Y3R1cmUuXG4gICAqXG4gICAqIEV2ZXJ5IHBhcnRpY2lwYXRpbmcgcHJvY2VzcyBtdXN0IHBhc3MgRVFVSVZBTEVOVCBwYXJ0cywgc2luY2UgYSBkaWZmZXJlbnRcbiAgICogc3BlbGxpbmcgaGFzaGVzIHRvIGEgZGlmZmVyZW50IGNoYW5uZWwuIERlZmF1bHRzIHRvIGEgc2hhcmVkXG4gICAqIGBkYnhfdG9vbHNfdG9waWNfYnVzYCBjaGFubmVsLlxuICAgKi9cbiAgY2hhbm5lbD86IHVua25vd247XG4gIC8qKlxuICAgKiBFeHRyYSBjb250ZXh0IGFkZGVkIHRvIGV2ZXJ5IG1lc3NhZ2UgdGhpcyBidXMgcHVibGlzaGVzLCBlaXRoZXIgYSBmaXhlZFxuICAgKiByZWNvcmQgb3IgYSB7QGxpbmsgVG9waWNNZXRhZGF0YVByb3ZpZGVyfSBjYWxsZWQgcGVyIGJyb2FkY2FzdC4gT3ZlcnJpZGVzXG4gICAqIGF1dG9tYXRpYyBtYWNoaW5lIGtleXM7IHBlci1jYWxsIGBtZXRhZGF0YWAgb3ZlcnJpZGVzIHRoaXMuXG4gICAqL1xuICBtZXRhZGF0YT86IFRvcGljTWV0YWRhdGEgfCBUb3BpY01ldGFkYXRhUHJvdmlkZXI7XG4gIC8qKlxuICAgKiBTaW5rIGZvciBmYWlsdXJlcyB0aGF0IGhhdmUgbm8gY2FsbGVyIHRvIHRocm93IHRvOiBhIGxpc3RlbmVyIHRoYXQgcmVqZWN0ZWQsXG4gICAqIGEgZHJvcHBlZCBub3RpZmljYXRpb24gY29ubmVjdGlvbiwgYSBmYWlsZWQgcmVjb25uZWN0IGF0dGVtcHQuIERlZmF1bHRzIHRvXG4gICAqIHN3YWxsb3dpbmcgdGhlbSwgc28gd2lyZSB0aGlzIHRvIGEgbG9nZ2VyIGluIGFueXRoaW5nIGxvbmctcnVubmluZy5cbiAgICovXG4gIG9uRXJyb3I/OiAoY2F1c2U6IHVua25vd24pID0+IHZvaWQ7XG4gIHBlcnNpc3Q/OiBib29sZWFuIHwgVG9waWNCdXNQZXJzaXN0ZW5jZU9wdGlvbnM7XG59XG5cbi8qKlxuICogRHJvcCBrZXlzIHdob3NlIHZhbHVlIGlzIGB1bmRlZmluZWRgLCBzbyBhbiB1bnNldCBlbnZpcm9ubWVudCB2YXJpYWJsZSBsZWF2ZXNcbiAqIHRoZSBrZXkgQUJTRU5UIHJhdGhlciB0aGFuIHByZXNlbnQtYW5kLW51bGwuIEFic2VuY2UgaXMgd2hhdCBsZXRzIGNhbGxlclxuICogbWV0YWRhdGEgYW5kIGxhdGVyIG1lcmdlIGxheWVycyBzdXBwbHkgdGhlIGtleSBpbnN0ZWFkLlxuICovXG5mdW5jdGlvbiBkZWZpbmVkTWV0YWRhdGEodmFsdWVzOiBSZWNvcmQ8c3RyaW5nLCBTZXJpYWxpemFibGVWYWx1ZSB8IHVuZGVmaW5lZD4pOiBUb3BpY01ldGFkYXRhIHtcbiAgcmV0dXJuIE9iamVjdC5mcm9tRW50cmllcyhcbiAgICBPYmplY3QuZW50cmllcyh2YWx1ZXMpLmZpbHRlcigoZW50cnkpOiBlbnRyeSBpcyBbc3RyaW5nLCBTZXJpYWxpemFibGVWYWx1ZV0gPT4ge1xuICAgICAgcmV0dXJuIGVudHJ5WzFdICE9PSB1bmRlZmluZWQ7XG4gICAgfSksXG4gICk7XG59XG5cbi8qKlxuICogQ29udGV4dCBldmVyeSBtZXNzYWdlIGdldHMgZm9yIGZyZWU6IHdoaWNoIHByb2plY3QsIGhvc3QsIGFuZCBkZXBsb3ltZW50XG4gKiBwdWJsaXNoZWQgaXQuXG4gKlxuICogUmVhZCBmcmVzaCBwZXIgYnJvYWRjYXN0IHJhdGhlciB0aGFuIGNhY2hlZCwgYmVjYXVzZSBhIGxvbmctbGl2ZWQgcHJvY2VzcyBjYW5cbiAqIGJlIHJlLXBhcmVudGVkIChhIGRlcGxveW1lbnQgaWQgYXBwZWFyaW5nIGFmdGVyIGJvb3QpLiBLZXlzIHRoYXQgcmVzb2x2ZSB0b1xuICogbm90aGluZyBhcmUgb21pdHRlZC5cbiAqXG4gKiBEZWxpYmVyYXRlbHkgTk9UIGluY2x1ZGVkOiBwdWJsaWMvY2xpZW50IElQLCBwcm9jZXNzIGlkLCBDUFUgYXJjaGl0ZWN0dXJlLFxuICogcnVudGltZSBuYW1lLCBhbmQgcnVudGltZSB2ZXJzaW9uLiBJUHMgYW5kIHBpZHMgYXJlIG5vaXN5LCBvZnRlbiBzZW5zaXRpdmUsXG4gKiBhbmQgYnVybiBgTk9USUZZYCBwYXlsb2FkIGJ1ZGdldDsgYXJjaGl0ZWN0dXJlL3J1bnRpbWUgYXJlIGNvbnN0YW50IHBlclxuICogZGVwbG95bWVudCBhbmQgcGF5IHRoZSBzYW1lIGNvc3QuIEEgcHJvY2VzcyB0aGF0IHdhbnRzIGFueSBvZiB0aGVtIHBhc3NlcyBhXG4gKiB7QGxpbmsgVG9waWNNZXRhZGF0YVByb3ZpZGVyfSBvciBwZXItbWVzc2FnZSBgbWV0YWRhdGFgLlxuICovXG5mdW5jdGlvbiBtYWNoaW5lTWV0YWRhdGEoKTogVG9waWNNZXRhZGF0YSB7XG4gIHJldHVybiBkZWZpbmVkTWV0YWRhdGEoe1xuICAgIHByb2plY3Q6XG4gICAgICBzdHJpbmcuZmlyc3ROb25FbXB0eShbXG4gICAgICAgIHByb2Nlc3MuZW52LkRBVEFCUklDS1NfQVBQX05BTUUsXG4gICAgICAgIHByb2Nlc3MuZW52LkRBVEFCUklDS1NfQlVORExFX05BTUUsXG4gICAgICAgIHByb2Nlc3MuZW52LlBST0pFQ1RfTkFNRSxcbiAgICAgICAgcHJvY2Vzcy5lbnYubnBtX3BhY2thZ2VfbmFtZSxcbiAgICAgIF0pID8/IHVuZGVmaW5lZCxcbiAgICBob3N0bmFtZTogaG9zdG5hbWUoKSxcbiAgICBwbGF0Zm9ybTogcHJvY2Vzcy5wbGF0Zm9ybSxcbiAgICBlbnZpcm9ubWVudDogc3RyaW5nLnRyaW1Ub051bGwocHJvY2Vzcy5lbnYuTk9ERV9FTlYpID8/IHVuZGVmaW5lZCxcbiAgICBhcHBOYW1lOiBzdHJpbmcudHJpbVRvTnVsbChwcm9jZXNzLmVudi5EQVRBQlJJQ0tTX0FQUF9OQU1FKSA/PyB1bmRlZmluZWQsXG4gICAgZGVwbG95bWVudElkOiBzdHJpbmcudHJpbVRvTnVsbChwcm9jZXNzLmVudi5EQVRBQlJJQ0tTX0FQUF9ERVBMT1lNRU5UX0lEKSA/PyB1bmRlZmluZWQsXG4gICAgZGF0YWJyaWNrc0hvc3Q6IHN0cmluZy50cmltVG9OdWxsKHByb2Nlc3MuZW52LkRBVEFCUklDS1NfSE9TVCkgPz8gdW5kZWZpbmVkLFxuICB9KTtcbn1cblxuLyoqXG4gKiBJZGVudGl0eSBvZiB0aGUgc2lnbmVkLWluIHVzZXIgb24gd2hvc2UgYmVoYWxmIHRoaXMgYnJvYWRjYXN0IGhhcHBlbnMsIHdoZW4gdGhlXG4gKiBwcm9jZXNzIGNhbiB0ZWxsLlxuICpcbiAqIGBAZGF0YWJyaWNrcy9hcHBraXRgIGlzIGFuIE9QVElPTkFMIHBlZXIsIHNvIHRoZSBpbXBvcnQgaXMgbGF6eSBhbmQgYSBtaXNzaW5nXG4gKiBtb2R1bGUgaXMgbm90IGFuIGVycm9yIC0gdGhpcyBpcyBhIHBsYWluIFBvc3RncmVzIHBhY2thZ2UgdGhhdCBhZGRzIHNlbmRlclxuICogaWRlbnRpdHkgd2hlbiBpdCBoYXBwZW5zIHRvIHJ1biBpbnNpZGUgYW4gQXBwS2l0IGFwcC4gT3V0c2lkZSBhbiBhY3RpdmVcbiAqIHBlci1yZXF1ZXN0IGV4ZWN1dGlvbiBjb250ZXh0IEFwcEtpdCB0aHJvd3MsIHdoaWNoIG1lYW5zIFwibm8gdXNlciBoZXJlXCIsIHNvIHRoZVxuICogcmVzdWx0IGlzIGVtcHR5IG1ldGFkYXRhIHJhdGhlciB0aGFuIGEgZmFpbGVkIGJyb2FkY2FzdC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gc2VuZGVyTWV0YWRhdGEoKTogUHJvbWlzZTxUb3BpY01ldGFkYXRhPiB7XG4gIGFwcEtpdE1vZHVsZSA/Pz0gaW1wb3J0KFwiQGRhdGFicmlja3MvYXBwa2l0XCIpXG4gICAgLnRoZW4oKG1vZHVsZSkgPT4gbW9kdWxlIGFzIEFwcEtpdE1vZHVsZSlcbiAgICAuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgY29uc3QgYXBwa2l0ID0gYXdhaXQgYXBwS2l0TW9kdWxlO1xuICBpZiAoIWFwcGtpdCkgcmV0dXJuIHt9O1xuICB0cnkge1xuICAgIGNvbnN0IGNvbnRleHQgPSBhcHBraXQuZ2V0RXhlY3V0aW9uQ29udGV4dCgpO1xuICAgIHJldHVybiBkZWZpbmVkTWV0YWRhdGEoe1xuICAgICAgc2VuZGVySWQ6IHN0cmluZy50cmltVG9OdWxsKGNvbnRleHQudXNlcklkKSA/PyB1bmRlZmluZWQsXG4gICAgICBzZW5kZXJOYW1lOiBzdHJpbmcudHJpbVRvTnVsbChjb250ZXh0LnVzZXJOYW1lKSA/PyB1bmRlZmluZWQsXG4gICAgICBzZW5kZXJFbWFpbDogc3RyaW5nLnRyaW1Ub051bGwoY29udGV4dC51c2VyRW1haWwpID8/IHVuZGVmaW5lZCxcbiAgICB9KTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHt9O1xuICB9XG59XG5cbi8qKlxuICogRGVyaXZlIGEgbGVnYWwgUG9zdGdyZXMgY2hhbm5lbCBuYW1lIGZyb20gd2hhdGV2ZXIgYSBjYWxsZXIgdXNlZCB0byBpZGVudGlmeVxuICogdGhlIGNoYW5uZWwuXG4gKlxuICogQ2FsbGVycyB0aGluayBpbiB0ZXJtcyBvZiB3aGF0IHRoZSBjaGFubmVsIElTIC0gYW4gYXBwIG5hbWUsIGEgdGVuYW50IGlkLCBhXG4gKiBgW2VudiwgZmVhdHVyZV1gIHBhaXIsIGEgY29uZmlnIG9iamVjdCAtIGFuZCBub25lIG9mIHRob3NlIGFyZSBpZGVudGlmaWVycy5cbiAqIFJlamVjdGluZyB0aGVtIHB1c2hlZCB0aGUgc2FuaXRpemluZyBvbnRvIGV2ZXJ5IGNhbGwgc2l0ZSwgd2hpY2ggaXMgaG93IHR3b1xuICogc2VydmljZXMgZW5kIHVwIGRpc2FncmVlaW5nIGFib3V0IHdoZXRoZXIgdGhlIGNoYW5uZWwgaXMgYG15LWFwcGAsIGBteV9hcHBgLFxuICogb3IgYG15QXBwYCBhbmQgc2lsZW50bHkgbmV2ZXIgaGVhciBlYWNoIG90aGVyLlxuICpcbiAqIFRoZSBwYXJ0cyBhcmUgdG9rZW5pemVkIGFuZCBqb2luZWQgaW50byBhbiBpZGVudGlmaWVyLCB0aGVuIGEgc2hvcnQgaGFzaCBvZiB0aGVcbiAqIE9SSUdJTkFMIHBhcnRzIGlzIGFwcGVuZGVkLiBUaGUgaGFzaCBpcyB3aGF0IG1ha2VzIHRoZSBtYXBwaW5nIHRydXN0d29ydGh5OlxuICogdG9rZW5pemluZyBhbG9uZSBpcyBsb3NzeSwgc28gYG15LWFwcGAgYW5kIGBteV9hcHBgIGFuZCBgbXlBcHBgIHdvdWxkIGNvbGxhcHNlXG4gKiBvbnRvIG9uZSBjaGFubmVsLCBhbmQgYSBuYW1lIGxvbmcgZW5vdWdoIHRvIGhpdCBgTkFNRURBVEFMRU5gIHdvdWxkIGNvbGxpZGVcbiAqIHdpdGggYW55dGhpbmcgc2hhcmluZyBpdHMgbGVhZGluZyB0b2tlbnMuIFdpdGggdGhlIHN1ZmZpeCwgdGhlIHJlYWRhYmxlIHBhcnRcbiAqIHN0YXlzIHJlYWRhYmxlIGFuZCBkaXN0aW5jdCBpbnB1dHMgc3RheSBkaXN0aW5jdC5cbiAqXG4gKiBEZXRlcm1pbmlzdGljIGFjcm9zcyBwcm9jZXNzZXMgYW5kIHJ1bnMsIHdoaWNoIGlzIHRoZSB3aG9sZSBwb2ludCAtIHR3b1xuICogc2VydmljZXMgZ2l2ZW4gdGhlIHNhbWUgcGFydHMgbXVzdCBsYW5kIG9uIHRoZSBzYW1lIGNoYW5uZWwgd2l0aG91dFxuICogY29vcmRpbmF0aW5nLiBIYXNoIGlucHV0cyBhcmUgc3RydWN0dXJlLWF3YXJlLCBzbyBgW1wiYVwiLCBcImJcIl1gIGFuZCBgW1wiYV9iXCJdYFxuICogZGlmZmVyLCBhbmQgb2JqZWN0IGtleSBvcmRlciBkb2VzIG5vdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNoYW5uZWxOYW1lKHZhbHVlOiB1bmtub3duKTogc3RyaW5nIHtcbiAgY29uc3QgcGFydHMgPSBvYmplY3QudG9PbmVPck1hbnkodmFsdWUpO1xuICAvLyBIYXNoIHRoZSBDQU5PTklDQUwgZm9ybSwgdGhlIHNhbWUgcnVsZSBgYWR2aXNvcnlMb2NrSWRgIHVzZXMsIHNvIHN0cnVjdHVyZSBhbmRcbiAgLy8gdHlwZXMgZGVjaWRlIGlkZW50aXR5OiBgW1wiYVwiLFwiYlwiXWAgZGlmZmVycyBmcm9tIGBbXCJhYlwiXWAsIGAxYCBmcm9tIGBcIjFcImAsIGFuZFxuICAvLyBvYmplY3Qga2V5IG9yZGVyIGRvZXMgbm90IG1hdHRlci4gSGFzaGluZyB0aGUgcmF3IHBhcnRzIHdvdWxkIGluc3RlYWQgbGVhbiBvblxuICAvLyB0aGUgaGFzaCBtb2R1bGUncyBjYW5vbmljYWxpemVyLCB3aGljaCBmb2xkcyBldmVyeSBgRGF0ZWAgb250byBvbmUgdG9rZW4uXG4gIGNvbnN0IHN1ZmZpeCA9IGhhc2guZm52SGFzaFdpdGhPcHRpb25zKFxuICAgIHsgbGVuZ3RoOiBDSEFOTkVMX0hBU0hfTEVOR1RIIH0sXG4gICAgcGFydHMubWFwKChwYXJ0KSA9PiBvYmplY3QudG9TdGFibGVLZXkocGFydCkpLmpvaW4oXCJcXHUwMDAwXCIpLFxuICApO1xuICAvLyBPbmx5IHBhcnRzIHRoYXQgc3RyaW5naWZ5IHRvIHNvbWV0aGluZyBhIHJlYWRlciByZWNvZ25pemVzIGNvbnRyaWJ1dGUgdG8gdGhlXG4gIC8vIHJlYWRhYmxlIGhhbGYuIEFuIG9iamVjdCB3b3VsZCB0b2tlbml6ZSBmcm9tIGBTdHJpbmcodmFsdWUpYCBhc1xuICAvLyBgb2JqZWN0X29iamVjdGAsIHdoaWNoIGlzIG5vaXNlIC0gaXQgc3RpbGwgc2hhcGVzIHRoZSBoYXNoLCBzbyBpZGVudGl0eSBpc1xuICAvLyB1bmFmZmVjdGVkLlxuICBjb25zdCBsYWJlbGxlZCA9IHBhcnRzLmZpbHRlcigocGFydCkgPT4ge1xuICAgIGNvbnN0IHR5cGUgPSB0eXBlb2YgcGFydDtcbiAgICByZXR1cm4gdHlwZSA9PT0gXCJzdHJpbmdcIiB8fCB0eXBlID09PSBcIm51bWJlclwiIHx8IHR5cGUgPT09IFwiYm9vbGVhblwiIHx8IHR5cGUgPT09IFwiYmlnaW50XCI7XG4gIH0pO1xuICAvLyBUcnVuY2F0ZSByYXRoZXIgdGhhbiBjYXAgdGhyb3VnaCB0aGUgdG9rZW5pemVyOiBgdHJpbWAgd291bGQgRFJPUCBhIHNpbmdsZVxuICAvLyB0b2tlbiBsb25nZXIgdGhhbiB0aGUgYnVkZ2V0LCB0dXJuaW5nIG9uZSBsb25nIG5hbWUgaW50byB0aGUgYmFyZSBmYWxsYmFjayBhbmRcbiAgLy8gbWFraW5nIGV2ZXJ5IGxvbmcgbmFtZSBsb29rIGFsaWtlLiBUaGUgaGFzaCBzdGlsbCBzZXBhcmF0ZXMgdGhlbSwgYnV0IHRoZVxuICAvLyBjaGFubmVsIGlzIHVucmVhZGFibGUgaW4gYSBsb2cuXG4gIGNvbnN0IGJvZHkgPSBzdHJpbmdcbiAgICAudG9JZGVudGlmaWVyV2l0aE9wdGlvbnMoeyBkZWxpbWl0ZXI6IFwiX1wiIH0sIC4uLmxhYmVsbGVkKVxuICAgIC5zbGljZSgwLCBNQVhfQ0hBTk5FTF9MRU5HVEggLSBzdWZmaXgubGVuZ3RoIC0gMSlcbiAgICAucmVwbGFjZSgvXyskLywgXCJcIik7XG4gIC8vIEFuIGlkZW50aWZpZXIgY2Fubm90IHN0YXJ0IHdpdGggYSBkaWdpdCBhbmQgdGhlIGhhc2ggYWxwaGFiZXQgaXNcbiAgLy8gZGlnaXQtbGVhZGluZywgc28gYSBudW1lcmljIG9yIGVtcHR5IGJvZHkgbmVlZHMgYSBsZXR0ZXIgaW4gZnJvbnQuXG4gIGNvbnN0IHByZWZpeCA9IC9eW0EtWmEtel9dLy50ZXN0KGJvZHkpID8gYm9keSA6IGAke0NIQU5ORUxfRkFMTEJBQ0t9XyR7Ym9keX1gO1xuICByZXR1cm4gYCR7cHJlZml4fV8ke3N1ZmZpeH1gLnJlcGxhY2UoL18rL2csIFwiX1wiKTtcbn1cblxuLyoqIFF1b3RlIGEgdmFsaWRhdGVkIGNoYW5uZWwgZm9yIGBMSVNURU5gL2BVTkxJU1RFTmAsIHdoaWNoIHRha2Ugbm8gcGFyYW1ldGVycy4gKi9cbmZ1bmN0aW9uIHF1b3RlSWRlbnRpZmllcih2YWx1ZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGBcIiR7dmFsdWUucmVwbGFjZUFsbCgnXCInLCAnXCJcIicpfVwiYDtcbn1cblxuLyoqXG4gKiBQYXJzZSBhIGBOT1RJRllgIHBheWxvYWQgaW50byBhbiBlbnZlbG9wZSwgcmV0dXJuaW5nIGB1bmRlZmluZWRgIGZvciBhbnl0aGluZ1xuICogdGhhdCBpcyBub3Qgb25lLlxuICpcbiAqIFRoZSBjaGFubmVsIGlzIHNoYXJlZCBhbmQgYW55IFBvc3RncmVzIHNlc3Npb24gY2FuIGBwZ19ub3RpZnlgIG9uIGl0LCBzbyBhblxuICogdW5yZWNvZ25pemVkIHBheWxvYWQgaXMgZXhwZWN0ZWQgaW5wdXQsIG5vdCBhbiBleGNlcHRpb24uIFB1Ymxpc2hlcnMgcnVuIHRoaXNcbiAqIG92ZXIgdGhlaXIgb3duIGVuY29kZWQgbWVzc2FnZSB0b28sIHdoaWNoIGlzIGhvdyBhIGJvZHkgdGhhdCBzdHJpbmdpZmllcyBidXRcbiAqIGRvZXMgbm90IHJvdW5kLXRyaXAgaXMgY2F1Z2h0IGJlZm9yZSBpdCBzaGlwcy5cbiAqL1xuZnVuY3Rpb24gZGVjb2RlKHZhbHVlOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBUb3BpY01lc3NhZ2UgfCB1bmRlZmluZWQge1xuICBpZiAoIXZhbHVlKSByZXR1cm4gdW5kZWZpbmVkO1xuICBjb25zdCByZWNvcmQgPSBqc29uLnBhcnNlUmVjb3JkKHZhbHVlKTtcbiAgaWYgKFxuICAgICFyZWNvcmQgfHxcbiAgICB0eXBlb2YgcmVjb3JkLmlkICE9PSBcInN0cmluZ1wiIHx8XG4gICAgdHlwZW9mIHJlY29yZC50b3BpYyAhPT0gXCJzdHJpbmdcIiB8fFxuICAgIHR5cGVvZiByZWNvcmQudHlwZSAhPT0gXCJzdHJpbmdcIiB8fFxuICAgIHR5cGVvZiByZWNvcmQucHVibGlzaGVkQXQgIT09IFwic3RyaW5nXCIgfHxcbiAgICAhcmVjb3JkLm1ldGFkYXRhIHx8XG4gICAgdHlwZW9mIHJlY29yZC5tZXRhZGF0YSAhPT0gXCJvYmplY3RcIiB8fFxuICAgIEFycmF5LmlzQXJyYXkocmVjb3JkLm1ldGFkYXRhKSB8fFxuICAgICEoXCJib2R5XCIgaW4gcmVjb3JkKSB8fFxuICAgICFvYmplY3QuaXNTZXJpYWxpemFibGVWYWx1ZShyZWNvcmQubWV0YWRhdGEpIHx8XG4gICAgIW9iamVjdC5pc1NlcmlhbGl6YWJsZVZhbHVlKHJlY29yZC5ib2R5KVxuICApIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIHJldHVybiB7XG4gICAgaWQ6IHJlY29yZC5pZCxcbiAgICB0b3BpYzogcmVjb3JkLnRvcGljLFxuICAgIHR5cGU6IHJlY29yZC50eXBlLFxuICAgIG1ldGFkYXRhOiByZWNvcmQubWV0YWRhdGEgYXMgVG9waWNNZXRhZGF0YSxcbiAgICBib2R5OiByZWNvcmQuYm9keSBhcyBTZXJpYWxpemFibGVWYWx1ZSxcbiAgICBwdWJsaXNoZWRBdDogcmVjb3JkLnB1Ymxpc2hlZEF0LFxuICB9O1xufVxuXG4vKipcbiAqIEJyb2FkY2FzdHMgc3RydWN0dXJlZCBtZXNzYWdlcyBieSB0b3BpYyBhbmQgZGVsaXZlcnMgdGhlbSB0byBldmVyeSBwcm9jZXNzXG4gKiBsaXN0ZW5pbmcgb24gdGhlIHNhbWUgY2hhbm5lbC5cbiAqXG4gKiBDT05ORUNUSU9OIFNIQVBFLiBQdWJsaXNoaW5nIGJvcnJvd3MgYSBwb29sZWQgY29ubmVjdGlvbiBwZXIgY2FsbCwgbGlrZSBhbnlcbiAqIG90aGVyIHF1ZXJ5LiBMaXN0ZW5pbmcgY2Fubm90OiBgTElTVEVOYCBpcyBzZXNzaW9uIHN0YXRlLCBzbyB0aGUgYnVzIGhvbGRzIE9ORVxuICogZGVkaWNhdGVkIGNsaWVudCBvdXQgb2YgdGhlIHBvb2wgZm9yIGFzIGxvbmcgYXMgaXQgaGFzIHN1YnNjcmliZXJzLCBubyBtYXR0ZXJcbiAqIGhvdyBtYW55IHRvcGljcyBvciBsaXN0ZW5lcnMgYXJlIHJlZ2lzdGVyZWQuIFNpemUgdGhlIHBvb2wgd2l0aCB0aGF0IG9uZVxuICogbG9uZy1saXZlZCBjaGVja291dCBpbiBtaW5kLlxuICpcbiAqIExJRkVDWUNMRS4gQ29uc3RydWN0aW9uIGlzIGluZXJ0IC0gbm90aGluZyBjb25uZWN0cyB1bnRpbCB0aGUgZmlyc3RcbiAqIHtAbGluayBsaXN0ZW59IChvciBhbiBleHBsaWNpdCB7QGxpbmsgc3RhcnR9KS4ge0BsaW5rIGNsb3NlfSBpcyByZXF1aXJlZCB0byBnaXZlXG4gKiB0aGUgY29ubmVjdGlvbiBiYWNrOyBhIGNsb3NlZCBidXMgc3RheXMgY2xvc2VkIGFuZCB0aHJvd3Mgb24gZnVydGhlciB1c2UgcmF0aGVyXG4gKiB0aGFuIHNpbGVudGx5IHJlY29ubmVjdGluZy4gUmVnaXN0ZXIgaXQgd2l0aCB0aGUgaG9zdCdzIHNodXRkb3duIGhvb2suXG4gKlxuICogRkFJTFVSRSBIQU5ETElORy4gQSBsb3N0IG5vdGlmaWNhdGlvbiBjb25uZWN0aW9uIHJlY29ubmVjdHMgb24gaXRzIG93biB3aXRoXG4gKiBib3VuZGVkIGJhY2tvZmYgd2hpbGUgc3Vic2NyaWJlcnMgcmVtYWluLCByZXBvcnRpbmcgZWFjaCBmYWlsZWQgYXR0ZW1wdCB0aHJvdWdoXG4gKiBgb25FcnJvcmAuIE1lc3NhZ2VzIHB1Ymxpc2hlZCBkdXJpbmcgdGhlIGdhcCBhcmUgbG9zdCAtIGBOT1RJRllgIGhhcyBubyByZXBsYXkuXG4gKiBBIHRocm93aW5nIG9yIHJlamVjdGluZyBsaXN0ZW5lciBuZXZlciBhZmZlY3RzIHRoZSBwdWJsaXNoZXIgb3IgdGhlIG90aGVyXG4gKiBsaXN0ZW5lcnM7IGl0cyBmYWlsdXJlIGdvZXMgdG8gYG9uRXJyb3JgLlxuICpcbiAqIE5vdCBzYWZlIHRvIHNoYXJlIG9uZSBpbnN0YW5jZSBhY3Jvc3MgdW5yZWxhdGVkIGNoYW5uZWxzIC0gY29uc3RydWN0IG9uZSBidXNcbiAqIHBlciBjaGFubmVsLiBUaGUgY2hhbm5lbCBpdHNlbGYgaXMgREVSSVZFRCBmcm9tIHRoZSBgY2hhbm5lbGAgb3B0aW9uIHJhdGhlclxuICogdGhhbiB0YWtlbiBsaXRlcmFsbHk7IHNlZSB7QGxpbmsgUG9zdGdyZXNUb3BpY0J1c09wdGlvbnMuY2hhbm5lbH0gYW5kXG4gKiB7QGxpbmsgUG9zdGdyZXNUb3BpY0J1cy5jaGFubmVsTmFtZX0uXG4gKi9cbmV4cG9ydCBjbGFzcyBQb3N0Z3Jlc1RvcGljQnVzIHtcbiAgLyoqXG4gICAqIFRoZSByZXNvbHZlZCBQb3N0Z3JlcyBjaGFubmVsIHRoaXMgYnVzIGxpc3RlbnMgYW5kIHB1Ymxpc2hlcyBvbiwgZGVyaXZlZCBmcm9tXG4gICAqIHRoZSBgY2hhbm5lbGAgb3B0aW9uLiBSZWFkIGl0IHRvIGNvbmZpcm0gdHdvIHByb2Nlc3NlcyBhZ3JlZSwgb3IgdG8gbG9nIHdoYXQgYVxuICAgKiBzZXQgb2YgcGFydHMgYWN0dWFsbHkgcmVzb2x2ZWQgdG8uXG4gICAqL1xuICByZWFkb25seSBjaGFubmVsTmFtZTogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRvbmx5IG1ldGFkYXRhOiBUb3BpY01ldGFkYXRhIHwgVG9waWNNZXRhZGF0YVByb3ZpZGVyIHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIHJlYWRvbmx5IG9uRXJyb3I6IChjYXVzZTogdW5rbm93bikgPT4gdm9pZDtcbiAgcHJpdmF0ZSByZWFkb25seSBsaXN0ZW5lcnMgPSBuZXcgTWFwPHN0cmluZywgU2V0PFRvcGljTGlzdGVuZXI+PigpO1xuICBwcml2YXRlIGNsaWVudDogUG9vbENsaWVudCB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSBzdGFydGluZzogUHJvbWlzZTx2b2lkPiB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSByZWNvbm5lY3Rpbmc6IFByb21pc2U8dm9pZD4gfCB1bmRlZmluZWQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgcmVjb25uZWN0QWJvcnQgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG4gIHByaXZhdGUgY2xvc2VkID0gZmFsc2U7XG4gIHByaXZhdGUgcmVhZG9ubHkgcGVyc2lzdGVuY2U/OiBSZXNvbHZlZFRvcGljQnVzUGVyc2lzdGVuY2VPcHRpb25zO1xuICBwcml2YXRlIHByb3Zpc2lvbmluZz86IFByb21pc2U8dm9pZD47XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSBwb29sOiBQZ1Bvb2xMaWtlICYgUGdRdWVyeWFibGUsXG4gICAgb3B0aW9uczogUG9zdGdyZXNUb3BpY0J1c09wdGlvbnMgPSB7fSxcbiAgKSB7XG4gICAgdGhpcy5jaGFubmVsTmFtZSA9IGNoYW5uZWxOYW1lKFxuICAgICAgb3B0aW9ucy5jaGFubmVsID09PSB1bmRlZmluZWQgPyBERUZBVUxUX0NIQU5ORUwgOiBvcHRpb25zLmNoYW5uZWwsXG4gICAgKTtcbiAgICB0aGlzLm1ldGFkYXRhID0gb3B0aW9ucy5tZXRhZGF0YTtcbiAgICB0aGlzLm9uRXJyb3IgPSBvcHRpb25zLm9uRXJyb3IgPz8gKCgpID0+IHVuZGVmaW5lZCk7XG4gICAgdGhpcy5wZXJzaXN0ZW5jZSA9IG9wdGlvbnMucGVyc2lzdCA/IHJlc29sdmVQZXJzaXN0ZW5jZU9wdGlvbnMob3B0aW9ucy5wZXJzaXN0ID09PSB0cnVlID8gdHJ1ZSA6IG9wdGlvbnMucGVyc2lzdCkgOiB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogT3BlbiB0aGUgZGVkaWNhdGVkIG5vdGlmaWNhdGlvbiBjb25uZWN0aW9uIGFuZCBgTElTVEVOYC5cbiAgICpcbiAgICogSWRlbXBvdGVudCwgYW5kIHNhZmUgdG8gY2FsbCBjb25jdXJyZW50bHkgLSBvdmVybGFwcGluZyBjYWxscyBhd2FpdCB0aGUgc2FtZVxuICAgKiBpbi1mbGlnaHQgY29ubmVjdC4ge0BsaW5rIGxpc3Rlbn0gY2FsbHMgdGhpcywgc28gaXQgaXMgb25seSBuZWVkZWQgdG8gc3VyZmFjZVxuICAgKiBhIGNvbm5lY3Rpb24gcHJvYmxlbSBhdCBzdGFydHVwIHJhdGhlciB0aGFuIG9uIGZpcnN0IHN1YnNjcmliZS4gVGhyb3dzIGlmIHRoZVxuICAgKiBidXMgaXMgY2xvc2VkLCBvciBpZiB0aGUgcG9vbCBjYW5ub3QgaGFuZCBvdXQgYSBjb25uZWN0aW9uLlxuICAgKi9cbiAgYXN5bmMgc3RhcnQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuY2xpZW50KSByZXR1cm47XG4gICAgaWYgKHRoaXMuY2xvc2VkKSB0aHJvdyBuZXcgRXJyb3IoXCJQb3N0Z3JlcyB0b3BpYyBidXMgaXMgY2xvc2VkXCIpO1xuICAgIHRoaXMuc3RhcnRpbmcgPz89IHRoaXMuY29ubmVjdCgpLmZpbmFsbHkoKCkgPT4ge1xuICAgICAgdGhpcy5zdGFydGluZyA9IHVuZGVmaW5lZDtcbiAgICB9KTtcbiAgICBhd2FpdCB0aGlzLnN0YXJ0aW5nO1xuICB9XG5cbiAgLyoqXG4gICAqIFB1Ymxpc2ggYSBtZXNzYWdlIHRvIGB0b3BpY2AsIHJldHVybmluZyB0aGUgZW52ZWxvcGUgdGhhdCB3YXMgc2VudC5cbiAgICpcbiAgICogUmVzb2x2ZXMgb25jZSBQb3N0Z3JlcyBoYXMgYWNjZXB0ZWQgdGhlIGBOT1RJRllgLCB3aGljaCBzYXlzIG5vdGhpbmcgYWJvdXRcbiAgICogYW55b25lIHJlY2VpdmluZyBpdDogc2Vzc2lvbnMgbm90IGxpc3RlbmluZyBhdCB0aGF0IG1vbWVudCBtaXNzIGl0LiBQdWJsaXNoaW5nXG4gICAqIG5lZWRzIG5vIHtAbGluayBzdGFydH0gYW5kIG5vIHN1YnNjcmliZXJzLlxuICAgKlxuICAgKiBWYWxpZGF0aW9uIGlzIGRlbGliZXJhdGVseSBmcm9udC1sb2FkZWQsIHNpbmNlIGEgbWVzc2FnZSB0aGF0IGZhaWxzIG9uIHRoZVxuICAgKiB3aXJlIGlzIGZhciBoYXJkZXIgdG8gZGlhZ25vc2UgdGhhbiBvbmUgcmVqZWN0ZWQgYXQgdGhlIGNhbGw6IGBUeXBlRXJyb3JgIGZvciBhXG4gICAqIGJsYW5rIHRvcGljIG9yIHR5cGUsIG9yIGEgYm9keS9tZXRhZGF0YSB0aGF0IHdvdWxkIG5vdCByb3VuZC10cmlwIHRocm91Z2ggSlNPTlxuICAgKiB1bmNoYW5nZWQgKGBvYmplY3QuaXNTZXJpYWxpemFibGVWYWx1ZWApOyBgUmFuZ2VFcnJvcmAgd2hlbiB0aGUgZW5jb2RlZFxuICAgKiBlbnZlbG9wZSBleGNlZWRzIHRoZSBgTk9USUZZYCBwYXlsb2FkIGxpbWl0LCB3aGljaCB0aGUgYXV0b21hdGljIG1ldGFkYXRhXG4gICAqIGNvdW50cyBhZ2FpbnN0IC0gc2VuZCBhIHJlZmVyZW5jZSBhbmQgbGV0IHRoZSByZWNlaXZlciBmZXRjaCB0aGUgcGF5bG9hZC5cbiAgICogVGhyb3dzIGlmIHRoZSBidXMgaXMgY2xvc2VkLlxuICAgKi9cbiAgYXN5bmMgYnJvYWRjYXN0PFRCb2R5IGV4dGVuZHMgU2VyaWFsaXphYmxlVmFsdWU+KFxuICAgIHRvcGljOiBzdHJpbmcsXG4gICAgaW5wdXQ6IFRvcGljUHVibGlzaElucHV0PFRCb2R5PixcbiAgKTogUHJvbWlzZTxUb3BpY01lc3NhZ2U8VEJvZHk+PiB7XG4gICAgaWYgKCF0b3BpYy50cmltKCkpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJUb3BpYyBtdXN0IG5vdCBiZSBlbXB0eVwiKTtcbiAgICBpZiAoIWlucHV0LnR5cGUudHJpbSgpKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiTWVzc2FnZSB0eXBlIG11c3Qgbm90IGJlIGVtcHR5XCIpO1xuICAgIGlmIChcbiAgICAgICFvYmplY3QuaXNTZXJpYWxpemFibGVWYWx1ZShpbnB1dC5tZXRhZGF0YSA/PyB7fSkgfHxcbiAgICAgICFvYmplY3QuaXNTZXJpYWxpemFibGVWYWx1ZShpbnB1dC5ib2R5KVxuICAgICkge1xuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIk1lc3NhZ2UgbWV0YWRhdGEgYW5kIGJvZHkgbXVzdCBiZSBKU09OIHNlcmlhbGl6YWJsZSB3aXRob3V0IGNvZXJjaW9uXCIpO1xuICAgIH1cbiAgICBpZiAodGhpcy5jbG9zZWQpIHRocm93IG5ldyBFcnJvcihcIlBvc3RncmVzIHRvcGljIGJ1cyBpcyBjbG9zZWRcIik7XG4gICAgY29uc3QgYXV0b21hdGljID0gYXdhaXQgdGhpcy5yZXNvbHZlTWV0YWRhdGEoKTtcbiAgICBjb25zdCBtZXNzYWdlOiBUb3BpY01lc3NhZ2U8VEJvZHk+ID0ge1xuICAgICAgaWQ6IGhhc2guaWQoKSxcbiAgICAgIHRvcGljLFxuICAgICAgdHlwZTogaW5wdXQudHlwZSxcbiAgICAgIG1ldGFkYXRhOiB7IC4uLmF1dG9tYXRpYywgLi4uaW5wdXQubWV0YWRhdGEgfSxcbiAgICAgIGJvZHk6IGlucHV0LmJvZHksXG4gICAgICBwdWJsaXNoZWRBdDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgIH07XG4gICAgbGV0IGVuY29kZWQ6IHN0cmluZztcbiAgICB0cnkge1xuICAgICAgZW5jb2RlZCA9IEpTT04uc3RyaW5naWZ5KG1lc3NhZ2UpO1xuICAgIH0gY2F0Y2ggKGNhdXNlKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKGBNZXNzYWdlIG11c3QgYmUgSlNPTiBzZXJpYWxpemFibGU6ICR7ZXJyb3IuZXJyb3JNZXNzYWdlKGNhdXNlKX1gKTtcbiAgICB9XG4gICAgaWYgKCFkZWNvZGUoZW5jb2RlZCkpIHtcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJNZXNzYWdlIHR5cGUsIG1ldGFkYXRhLCBhbmQgYm9keSBtdXN0IGJlIEpTT04gc2VyaWFsaXphYmxlXCIpO1xuICAgIH1cbiAgICBpZiAoQnVmZmVyLmJ5dGVMZW5ndGgoZW5jb2RlZCwgXCJ1dGY4XCIpID4gTUFYX05PVElGWV9CWVRFUyAmJiB0aGlzLnBlcnNpc3RlbmNlPy5wYXlsb2FkICE9PSBcInBvaW50ZXJcIikge1xuICAgICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoYFBvc3RncmVzIG5vdGlmaWNhdGlvbiBleGNlZWRzICR7TUFYX05PVElGWV9CWVRFU30gYnl0ZXNgKTtcbiAgICB9XG4gICAgaWYgKCF0aGlzLnBlcnNpc3RlbmNlKSBhd2FpdCB0aGlzLnBvb2wucXVlcnkoXCJTRUxFQ1QgcGdfbm90aWZ5KCQxLCAkMilcIiwgW3RoaXMuY2hhbm5lbE5hbWUsIGVuY29kZWRdKTtcbiAgICBlbHNlIHtcbiAgICAgIGlmICh0aGlzLnBlcnNpc3RlbmNlLnByb3Zpc2lvbikge1xuICAgICAgICB0aGlzLnByb3Zpc2lvbmluZyA/Pz0gcHJvdmlzaW9uTWVzc2FnZUJ1c1NjaGVtYSh0aGlzLnBvb2wsIHRoaXMucGVyc2lzdGVuY2UpO1xuICAgICAgICBhd2FpdCB0aGlzLnByb3Zpc2lvbmluZztcbiAgICAgIH1cbiAgICAgIGNvbnN0IGNsaWVudCA9IGF3YWl0IHRoaXMucG9vbC5jb25uZWN0KCk7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBjbGllbnQucXVlcnkoXCJCRUdJTlwiKTtcbiAgICAgICAgYXdhaXQgcGVyc2lzdGVkTm90aWZ5KGNsaWVudCwgdGhpcy5jaGFubmVsTmFtZSwgdG9waWMsIG1lc3NhZ2UsIGVuY29kZWQsIHRoaXMucGVyc2lzdGVuY2UsIGlucHV0LnNjb3BlID8/IHRoaXMucGVyc2lzdGVuY2Uuc2NvcGUsIGlucHV0LnR0bCA/PyB0aGlzLnBlcnNpc3RlbmNlLnR0bCk7XG4gICAgICAgIGF3YWl0IGNsaWVudC5xdWVyeShcIkNPTU1JVFwiKTtcbiAgICAgIH0gY2F0Y2ggKGNhdXNlKSB7XG4gICAgICAgIGF3YWl0IGNsaWVudC5xdWVyeShcIlJPTExCQUNLXCIpLmNhdGNoKCgpID0+IHVuZGVmaW5lZCk7XG4gICAgICAgIHRocm93IGNhdXNlO1xuICAgICAgfSBmaW5hbGx5IHsgY2xpZW50LnJlbGVhc2UoKTsgfVxuICAgIH1cbiAgICByZXR1cm4gbWVzc2FnZTtcbiAgfVxuXG4gIGFzeW5jIGhpc3Rvcnk8VEJvZHkgZXh0ZW5kcyBTZXJpYWxpemFibGVWYWx1ZT4odG9waWM6IHN0cmluZywgb3B0aW9uczogeyBhZnRlcj86IHN0cmluZzsgbGltaXQ/OiBudW1iZXI7IHNjb3BlPzogVG9waWNQZXJzaXN0ZW5jZVNjb3BlIH0gPSB7fSk6IFByb21pc2U8VG9waWNIaXN0b3J5UGFnZTxUQm9keT4+IHtcbiAgICBpZiAoIXRoaXMucGVyc2lzdGVuY2UpIHRocm93IG5ldyBFcnJvcihcIlBvc3RncmVzIHRvcGljIGJ1cyBwZXJzaXN0ZW5jZSBpcyBkaXNhYmxlZFwiKTtcbiAgICBpZiAodGhpcy5wZXJzaXN0ZW5jZS5wcm92aXNpb24pIHtcbiAgICAgIHRoaXMucHJvdmlzaW9uaW5nID8/PSBwcm92aXNpb25NZXNzYWdlQnVzU2NoZW1hKHRoaXMucG9vbCwgdGhpcy5wZXJzaXN0ZW5jZSk7XG4gICAgICBhd2FpdCB0aGlzLnByb3Zpc2lvbmluZztcbiAgICB9XG4gICAgcmV0dXJuIGhpc3Rvcnk8VEJvZHk+KHRoaXMucG9vbCwgdGhpcy5jaGFubmVsTmFtZSwgdG9waWMsIHRoaXMucGVyc2lzdGVuY2UsIG9wdGlvbnMpO1xuICB9XG5cbiAgYXN5bmMgY2xlYW51cEV4cGlyZWQob3B0aW9uczogeyBzY29wZT86IFRvcGljUGVyc2lzdGVuY2VTY29wZTsgbGltaXQ/OiBudW1iZXIgfSA9IHt9KTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBpZiAoIXRoaXMucGVyc2lzdGVuY2UpIHRocm93IG5ldyBFcnJvcihcIlBvc3RncmVzIHRvcGljIGJ1cyBwZXJzaXN0ZW5jZSBpcyBkaXNhYmxlZFwiKTtcbiAgICByZXR1cm4gY2xlYW51cEV4cGlyZWQodGhpcy5wb29sLCB0aGlzLnBlcnNpc3RlbmNlLCBvcHRpb25zLnNjb3BlID8/IHRoaXMucGVyc2lzdGVuY2Uuc2NvcGUsIG9wdGlvbnMubGltaXQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFN1YnNjcmliZSB0byBgdG9waWNgLCByZXR1cm5pbmcgdGhlIGZ1bmN0aW9uIHRoYXQgdW5zdWJzY3JpYmVzLlxuICAgKlxuICAgKiBDb25uZWN0cyBvbiBmaXJzdCB1c2UuIFNldmVyYWwgbGlzdGVuZXJzIG1heSBzaGFyZSBhIHRvcGljOyBlYWNoIGlzIGNhbGxlZFxuICAgKiBvbmNlIHBlciBtZXNzYWdlLiBPbmx5IG1lc3NhZ2VzIHB1Ymxpc2hlZCBBRlRFUiB0aGlzIHJlc29sdmVzIGFycml2ZSwgc29cbiAgICogc3Vic2NyaWJlIGJlZm9yZSB0cmlnZ2VyaW5nIHdoYXRldmVyIHlvdSBleHBlY3QgdG8gb2JzZXJ2ZS5cbiAgICpcbiAgICogVGhlIHJldHVybmVkIGZ1bmN0aW9uIHJlbW92ZXMganVzdCB0aGlzIGxpc3RlbmVyIGFuZCBpcyBzYWZlIHRvIGNhbGwgdHdpY2UuXG4gICAqIFRoZSBjb25uZWN0aW9uIHN0YXlzIG9wZW4gb25jZSB0aGUgbGFzdCBsaXN0ZW5lciBsZWF2ZXMgLSB7QGxpbmsgY2xvc2V9XG4gICAqIHJlbGVhc2VzIGl0IC0gc28gYSBidXMgdGhhdCBzdWJzY3JpYmVzIGFuZCB1bnN1YnNjcmliZXMgcGVyIHJlcXVlc3QgZG9lcyBub3RcbiAgICogY2h1cm4gY29ubmVjdGlvbnMuXG4gICAqL1xuICBhc3luYyBsaXN0ZW48VEJvZHkgZXh0ZW5kcyBTZXJpYWxpemFibGVWYWx1ZT4oXG4gICAgdG9waWM6IHN0cmluZyxcbiAgICBsaXN0ZW5lcjogVG9waWNMaXN0ZW5lcjxUQm9keT4sXG4gICk6IFByb21pc2U8KCkgPT4gUHJvbWlzZTx2b2lkPj4ge1xuICAgIGlmICghdG9waWMudHJpbSgpKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiVG9waWMgbXVzdCBub3QgYmUgZW1wdHlcIik7XG4gICAgYXdhaXQgdGhpcy5zdGFydCgpO1xuICAgIGNvbnN0IGxpc3RlbmVycyA9IHRoaXMubGlzdGVuZXJzLmdldCh0b3BpYykgPz8gbmV3IFNldDxUb3BpY0xpc3RlbmVyPigpO1xuICAgIGxpc3RlbmVycy5hZGQobGlzdGVuZXIgYXMgVG9waWNMaXN0ZW5lcik7XG4gICAgdGhpcy5saXN0ZW5lcnMuc2V0KHRvcGljLCBsaXN0ZW5lcnMpO1xuICAgIHJldHVybiBhc3luYyAoKSA9PiB7XG4gICAgICBsaXN0ZW5lcnMuZGVsZXRlKGxpc3RlbmVyIGFzIFRvcGljTGlzdGVuZXIpO1xuICAgICAgaWYgKGxpc3RlbmVycy5zaXplID09PSAwKSB0aGlzLmxpc3RlbmVycy5kZWxldGUodG9waWMpO1xuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQnVpbGQgdGhlIGF1dG9tYXRpYyBoYWxmIG9mIGEgbWVzc2FnZSdzIG1ldGFkYXRhLlxuICAgKlxuICAgKiBQcmVjZWRlbmNlLCB3ZWFrZXN0IGZpcnN0OiBtYWNoaW5lL3Byb2Nlc3MgY29udGV4dCwgdGhlbiBBcHBLaXQgc2VuZGVyXG4gICAqIGlkZW50aXR5LCB0aGVuIHRoaXMgYnVzJ3MgY29uZmlndXJlZCBtZXRhZGF0YS4gVGhlIGNhbGxlcidzIHBlci1tZXNzYWdlXG4gICAqIG1ldGFkYXRhIGlzIGxheWVyZWQgb3ZlciB0aGUgcmVzdWx0IGluIHtAbGluayBicm9hZGNhc3R9LCBzbyB0aGUgbW9zdCBzcGVjaWZpY1xuICAgKiBzb3VyY2UgYWx3YXlzIHdpbnMgYW5kIG5vdGhpbmcgaGVyZSBjYW4gb3ZlcndyaXRlIGFuIGV4cGxpY2l0IGtleS5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcmVzb2x2ZU1ldGFkYXRhKCk6IFByb21pc2U8VG9waWNNZXRhZGF0YT4ge1xuICAgIGNvbnN0IHNlbmRlciA9IGF3YWl0IHNlbmRlck1ldGFkYXRhKCk7XG4gICAgY29uc3QgY29uZmlndXJlZCA9XG4gICAgICB0eXBlb2YgdGhpcy5tZXRhZGF0YSA9PT0gXCJmdW5jdGlvblwiID8gYXdhaXQgdGhpcy5tZXRhZGF0YSgpIDogKHRoaXMubWV0YWRhdGEgPz8ge30pO1xuICAgIHJldHVybiB7IC4uLm1hY2hpbmVNZXRhZGF0YSgpLCAuLi5zZW5kZXIsIC4uLmNvbmZpZ3VyZWQgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWxlYXNlIHRoZSBub3RpZmljYXRpb24gY29ubmVjdGlvbiBhbmQgc3RvcCBkZWxpdmVyaW5nIG1lc3NhZ2VzLiBJZGVtcG90ZW50LlxuICAgKlxuICAgKiBDYW5jZWxzIGFueSBwZW5kaW5nIHJlY29ubmVjdCwgZHJvcHMgYWxsIGxpc3RlbmVycywgdGhlbiBgVU5MSVNURU5gcyBhbmRcbiAgICogcmV0dXJucyB0aGUgY2xpZW50IHRvIHRoZSBwb29sLiBBIGZhaWxlZCBgVU5MSVNURU5gIGlzIHJlcG9ydGVkIHRvIHRoZSBwb29sIGFzXG4gICAqIGEgcmVsZWFzZSBlcnJvciBzbyB0aGUgY29ubmVjdGlvbiBpcyBESVNDQVJERUQgcmF0aGVyIHRoYW4gaGFuZGVkIHRvIHRoZSBuZXh0XG4gICAqIGNhbGxlciBzdGlsbCBzdWJzY3JpYmVkIHRvIHRoZSBjaGFubmVsLiBEb2VzIG5vdCB0aHJvdzsgdGhlIGJ1cyBzdGF5cyBjbG9zZWQuXG4gICAqL1xuICBhc3luYyBjbG9zZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5jbG9zZWQpIHJldHVybjtcbiAgICB0aGlzLmNsb3NlZCA9IHRydWU7XG4gICAgdGhpcy5yZWNvbm5lY3RBYm9ydC5hYm9ydChuZXcgRXJyb3IoXCJQb3N0Z3JlcyB0b3BpYyBidXMgaXMgY2xvc2VkXCIpKTtcbiAgICBhd2FpdCB0aGlzLnN0YXJ0aW5nPy5jYXRjaCgoKSA9PiB1bmRlZmluZWQpO1xuICAgIGF3YWl0IHRoaXMucmVjb25uZWN0aW5nPy5jYXRjaCgoKSA9PiB1bmRlZmluZWQpO1xuICAgIGNvbnN0IGNsaWVudCA9IHRoaXMuY2xpZW50O1xuICAgIHRoaXMuY2xpZW50ID0gdW5kZWZpbmVkO1xuICAgIHRoaXMubGlzdGVuZXJzLmNsZWFyKCk7XG4gICAgaWYgKCFjbGllbnQpIHJldHVybjtcbiAgICBjbGllbnQucmVtb3ZlTGlzdGVuZXIoXCJub3RpZmljYXRpb25cIiwgdGhpcy5oYW5kbGVOb3RpZmljYXRpb24pO1xuICAgIGNsaWVudC5yZW1vdmVMaXN0ZW5lcihcImVycm9yXCIsIHRoaXMuaGFuZGxlQ2xpZW50RXJyb3IpO1xuICAgIGxldCByZWxlYXNlRXJyb3I6IEVycm9yIHwgdW5kZWZpbmVkO1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBjbGllbnQucXVlcnkoYFVOTElTVEVOICR7cXVvdGVJZGVudGlmaWVyKHRoaXMuY2hhbm5lbE5hbWUpfWApO1xuICAgIH0gY2F0Y2ggKGNhdXNlKSB7XG4gICAgICByZWxlYXNlRXJyb3IgPSBlcnJvci50b0Vycm9yKGNhdXNlKTtcbiAgICB9XG4gICAgY2xpZW50LnJlbGVhc2UocmVsZWFzZUVycm9yKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBvdXQgb25lIGNsaWVudCwgYXR0YWNoIHRoZSBoYW5kbGVycywgYW5kIGBMSVNURU5gLlxuICAgKlxuICAgKiBUaGUgaGFuZGxlcnMgYXJlIGF0dGFjaGVkIEJFRk9SRSB0aGUgYExJU1RFTmAgcm91bmQgdHJpcCBzbyBhIG5vdGlmaWNhdGlvbiBvclxuICAgKiBlcnJvciBhcnJpdmluZyBtaWQtc2V0dXAgaXMgbm90IG1pc3NlZC4gQW55IGZhaWx1cmUgLSBpbmNsdWRpbmcgdGhlIGJ1cyBiZWluZ1xuICAgKiBjbG9zZWQgd2hpbGUgdGhlIGNvbm5lY3Qgd2FzIGluIGZsaWdodCAtIGRldGFjaGVzIHRoZSBoYW5kbGVycyBhbmQgcmVsZWFzZXNcbiAgICogdGhlIGNsaWVudCBhcyBlcnJvcmVkLCBzbyBhIGhhbGYtY29uZmlndXJlZCBjb25uZWN0aW9uIG5ldmVyIHJldHVybnMgdG8gdGhlXG4gICAqIHBvb2wuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGNvbm5lY3QoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgY2xpZW50ID0gYXdhaXQgdGhpcy5wb29sLmNvbm5lY3QoKTtcbiAgICB0cnkge1xuICAgICAgY2xpZW50Lm9uKFwibm90aWZpY2F0aW9uXCIsIHRoaXMuaGFuZGxlTm90aWZpY2F0aW9uKTtcbiAgICAgIGNsaWVudC5vbihcImVycm9yXCIsIHRoaXMuaGFuZGxlQ2xpZW50RXJyb3IpO1xuICAgICAgYXdhaXQgY2xpZW50LnF1ZXJ5KGBMSVNURU4gJHtxdW90ZUlkZW50aWZpZXIodGhpcy5jaGFubmVsTmFtZSl9YCk7XG4gICAgICBpZiAodGhpcy5jbG9zZWQpIHRocm93IG5ldyBFcnJvcihcIlBvc3RncmVzIHRvcGljIGJ1cyBpcyBjbG9zZWRcIik7XG4gICAgICB0aGlzLmNsaWVudCA9IGNsaWVudDtcbiAgICB9IGNhdGNoIChjYXVzZSkge1xuICAgICAgY2xpZW50LnJlbW92ZUxpc3RlbmVyKFwibm90aWZpY2F0aW9uXCIsIHRoaXMuaGFuZGxlTm90aWZpY2F0aW9uKTtcbiAgICAgIGNsaWVudC5yZW1vdmVMaXN0ZW5lcihcImVycm9yXCIsIHRoaXMuaGFuZGxlQ2xpZW50RXJyb3IpO1xuICAgICAgY2xpZW50LnJlbGVhc2UoZXJyb3IudG9FcnJvcihjYXVzZSkpO1xuICAgICAgdGhyb3cgY2F1c2U7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJvdXRlIG9uZSBpbmJvdW5kIG5vdGlmaWNhdGlvbiB0byB0aGUgdG9waWMncyBsaXN0ZW5lcnMuXG4gICAqXG4gICAqIElnbm9yZXMgb3RoZXIgY2hhbm5lbHMgYW5kIHVuZGVjb2RhYmxlIHBheWxvYWRzIC0gdGhlIGNoYW5uZWwgaXMgc2hhcmVkLCBzb1xuICAgKiBib3RoIGFyZSBvcmRpbmFyeSB0cmFmZmljLiBMaXN0ZW5lcnMgYXJlIGludm9rZWQgY29uY3VycmVudGx5IGFuZCB0aGVpclxuICAgKiByZWplY3Rpb25zIGdvIHRvIGBvbkVycm9yYCwga2VlcGluZyBvbmUgc2xvdyBvciBicm9rZW4gc3Vic2NyaWJlciBmcm9tXG4gICAqIHN0YWxsaW5nIHRoZSBub3RpZmljYXRpb24gY29ubmVjdGlvbi5cbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgaGFuZGxlTm90aWZpY2F0aW9uID0gKG5vdGlmaWNhdGlvbjogTm90aWZpY2F0aW9uKTogdm9pZCA9PiB7XG4gICAgaWYgKG5vdGlmaWNhdGlvbi5jaGFubmVsICE9PSB0aGlzLmNoYW5uZWxOYW1lKSByZXR1cm47XG4gICAgY29uc3QgbWVzc2FnZSA9IGRlY29kZShub3RpZmljYXRpb24ucGF5bG9hZCk7XG4gICAgaWYgKCFtZXNzYWdlKSByZXR1cm47XG4gICAgZm9yIChjb25zdCBsaXN0ZW5lciBvZiB0aGlzLmxpc3RlbmVycy5nZXQobWVzc2FnZS50b3BpYykgPz8gW10pIHtcbiAgICAgIFByb21pc2UucmVzb2x2ZShsaXN0ZW5lcihtZXNzYWdlKSkuY2F0Y2godGhpcy5vbkVycm9yKTtcbiAgICB9XG4gIH07XG5cbiAgLyoqXG4gICAqIEhhbmRsZSB0aGUgbm90aWZpY2F0aW9uIGNvbm5lY3Rpb24gZHlpbmcsIHdoaWNoIGBwZ2AgcmVwb3J0cyBhcyBhbiBgZXJyb3JgXG4gICAqIGV2ZW50IHJhdGhlciB0aGFuIGEgcmVqZWN0ZWQgcXVlcnkuXG4gICAqXG4gICAqIFRoZSBjbGllbnQgaXMgdW51c2FibGUgYXQgdGhpcyBwb2ludCwgc28gaXQgaXMgZGV0YWNoZWQgYW5kIHJlbGVhc2VkIGFzXG4gICAqIGVycm9yZWQgKHdoaWNoIGRpc2NhcmRzIGl0KSBiZWZvcmUgYW55dGhpbmcgZWxzZS4gUmVjb25uZWN0aW9uIG9ubHkgc3RhcnRzXG4gICAqIHdoZW4gdGhlcmUgaXMgc3RpbGwgc29tZW9uZSB0byBkZWxpdmVyIHRvLCBzbyBhbiBpZGxlIG9yIGNsb3NpbmcgYnVzIGRvZXMgbm90XG4gICAqIGhvbGQgYSBjb25uZWN0aW9uIG9wZW4gY2hhc2luZyBhIGNoYW5uZWwgbm9ib2R5IHJlYWRzLlxuICAgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBoYW5kbGVDbGllbnRFcnJvciA9IChjYXVzZTogRXJyb3IpOiB2b2lkID0+IHtcbiAgICB0aGlzLm9uRXJyb3IoY2F1c2UpO1xuICAgIGNvbnN0IGNsaWVudCA9IHRoaXMuY2xpZW50O1xuICAgIGlmICghY2xpZW50KSByZXR1cm47XG4gICAgdGhpcy5jbGllbnQgPSB1bmRlZmluZWQ7XG4gICAgY2xpZW50LnJlbW92ZUxpc3RlbmVyKFwibm90aWZpY2F0aW9uXCIsIHRoaXMuaGFuZGxlTm90aWZpY2F0aW9uKTtcbiAgICBjbGllbnQucmVtb3ZlTGlzdGVuZXIoXCJlcnJvclwiLCB0aGlzLmhhbmRsZUNsaWVudEVycm9yKTtcbiAgICBjbGllbnQucmVsZWFzZShjYXVzZSk7XG4gICAgaWYgKHRoaXMuY2xvc2VkIHx8IHRoaXMubGlzdGVuZXJzLnNpemUgPT09IDApIHJldHVybjtcbiAgICB0aGlzLnJlY29ubmVjdGluZyA/Pz0gdGhpcy5yZWNvbm5lY3QoKS5maW5hbGx5KCgpID0+IHtcbiAgICAgIHRoaXMucmVjb25uZWN0aW5nID0gdW5kZWZpbmVkO1xuICAgIH0pO1xuICB9O1xuXG4gIC8qKlxuICAgKiBSZS1lc3RhYmxpc2ggdGhlIG5vdGlmaWNhdGlvbiBjb25uZWN0aW9uIHdpdGggYm91bmRlZCBleHBvbmVudGlhbCBiYWNrb2ZmLlxuICAgKlxuICAgKiBUaGUgZmlyc3QgYXR0ZW1wdCBpcyBpbW1lZGlhdGUsIHNpbmNlIHRoZSBjb21tb24gY2FzZSBpcyBhIHNpbmdsZSBkcm9wcGVkXG4gICAqIGNvbm5lY3Rpb24gdGhhdCByZWNvbm5lY3RzIGF0IG9uY2U7IHN1YnNlcXVlbnQgZGVsYXlzIGRvdWJsZSBmcm9tIDI1MG1zIHVwIHRvXG4gICAqIDVzIGFuZCBzdGF5IHRoZXJlLiBSZXRyaWVzIGluZGVmaW5pdGVseSByYXRoZXIgdGhhbiBnaXZpbmcgdXAsIGJlY2F1c2UgYSBQb3N0Z3JlcyByZXN0YXJ0XG4gICAqIG9yIGEgcm90YXRlZCBMYWtlYmFzZSBjcmVkZW50aWFsIGlzIGEgcmVjb3ZlcmFibGUgb3V0YWdlIGFuZCBhIHNpbGVudGx5IGRlYWRcbiAgICogbGlzdGVuZXIgaXMgd29yc2UgdGhhbiBhIG5vaXN5IG9uZS4gU3RvcHMgd2hlbiB0aGUgYnVzIGNsb3NlcyBvciB0aGUgbGFzdFxuICAgKiBsaXN0ZW5lciBsZWF2ZXMsIGFuZCByZXBvcnRzIGV2ZXJ5IGZhaWxlZCBhdHRlbXB0IHRocm91Z2ggYG9uRXJyb3JgLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyByZWNvbm5lY3QoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgbGV0IGRlbGF5ID0gMDtcbiAgICB3aGlsZSAoIXRoaXMuY2xvc2VkICYmIHRoaXMubGlzdGVuZXJzLnNpemUgPiAwKSB7XG4gICAgICBpZiAoZGVsYXkgPiAwKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYXdhaXQgYXN5bmNVdGlsLnNsZWVwKGRlbGF5LCB0aGlzLnJlY29ubmVjdEFib3J0LnNpZ25hbCk7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgdGhpcy5zdGFydCgpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9IGNhdGNoIChjYXVzZSkge1xuICAgICAgICBpZiAodGhpcy5jbG9zZWQpIHJldHVybjtcbiAgICAgICAgdGhpcy5vbkVycm9yKGNhdXNlKTtcbiAgICAgICAgZGVsYXkgPSBkZWxheSA9PT0gMCA/IE1JTl9SRUNPTk5FQ1RfREVMQVlfTVMgOiBNYXRoLm1pbihkZWxheSAqIDIsIE1BWF9SRUNPTk5FQ1RfREVMQVlfTVMpO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuIl19
@@ -1 +1 @@
1
- {"root":["../src/advisory-lock.ts","../src/topic-bus.ts","../index.ts"],"version":"5.9.3"}
1
+ {"root":["../src/advisory-lock.ts","../src/persistence.ts","../src/topic-bus.ts","../index.ts"],"version":"5.9.3"}
package/package.json CHANGED
@@ -28,7 +28,7 @@
28
28
  "@databricks/appkit": "^0.43.0"
29
29
  },
30
30
  "dependencies": {
31
- "@dbx-tools/shared-core": "0.6.81",
31
+ "@dbx-tools/shared-core": "0.6.85",
32
32
  "pg": "^8.22.0"
33
33
  },
34
34
  "main": "./lib/index.js",
@@ -45,7 +45,7 @@
45
45
  "./package.json": "./package.json"
46
46
  }
47
47
  },
48
- "version": "0.6.81",
48
+ "version": "0.6.85",
49
49
  "types": "./lib/index.d.ts",
50
50
  "type": "module",
51
51
  "exports": {
@@ -0,0 +1,115 @@
1
+ import { object } from "@dbx-tools/shared-core";
2
+ import type { QueryResultRow } from "pg";
3
+ import type { PgPoolLike, PgQueryable } from "./advisory-lock.ts";
4
+ import { withAdvisoryTransactionLock } from "./advisory-lock.ts";
5
+ import type { TopicMessage } from "./topic-bus.ts";
6
+
7
+ export type TopicPersistenceScope = "open" | "restricted";
8
+ export type DurationInput = string | number;
9
+ export interface TopicBusPersistenceOptions {
10
+ schema?: string;
11
+ scope?: TopicPersistenceScope;
12
+ tables?: Partial<Record<TopicPersistenceScope, string>>;
13
+ ttl?: DurationInput | false;
14
+ payload?: "envelope" | "pointer";
15
+ cleanupBatchSize?: number;
16
+ provision?: boolean;
17
+ }
18
+ export interface ResolvedTopicBusPersistenceOptions {
19
+ schema: string;
20
+ scope: TopicPersistenceScope;
21
+ tables: Record<TopicPersistenceScope, string>;
22
+ ttl: DurationInput | false;
23
+ payload: "envelope" | "pointer";
24
+ cleanupBatchSize: number;
25
+ provision: boolean;
26
+ }
27
+ export interface StoredTopicMessage<TBody extends object.SerializableValue = object.SerializableValue> {
28
+ cursor: string;
29
+ expiresAt: string | null;
30
+ scope: TopicPersistenceScope;
31
+ message: TopicMessage<TBody>;
32
+ }
33
+ export interface TopicHistoryPage<TBody extends object.SerializableValue = object.SerializableValue> {
34
+ messages: StoredTopicMessage<TBody>[];
35
+ nextCursor?: string;
36
+ }
37
+
38
+ const DEFAULT_TTL = "24 hours";
39
+ const quote = (value: string): string => `"${value.replaceAll('"', '""')}"`;
40
+ const table = (options: ResolvedTopicBusPersistenceOptions, scope: TopicPersistenceScope): string => `${quote(options.schema)}.${quote(options.tables[scope])}`;
41
+
42
+ export function resolvePersistenceOptions(value: true | TopicBusPersistenceOptions): ResolvedTopicBusPersistenceOptions {
43
+ const configured = value === true ? {} : value;
44
+ const scope = configured.scope ?? "open";
45
+ if (scope !== "open" && scope !== "restricted") throw new TypeError(`Unknown persistence scope: ${String(scope)}`);
46
+ return {
47
+ schema: configured.schema ?? "dbx_message_bus",
48
+ scope,
49
+ tables: { open: configured.tables?.open ?? "open_messages", restricted: configured.tables?.restricted ?? "restricted_messages" },
50
+ ttl: configured.ttl ?? DEFAULT_TTL,
51
+ payload: configured.payload ?? "envelope",
52
+ cleanupBatchSize: configured.cleanupBatchSize ?? 1000,
53
+ provision: configured.provision ?? true,
54
+ };
55
+ }
56
+
57
+ export async function provisionMessageBusSchema(pool: PgPoolLike, options: ResolvedTopicBusPersistenceOptions): Promise<void> {
58
+ await withAdvisoryTransactionLock(pool, ["dbx_message_bus", "schema"], async (client) => {
59
+ await client.query(`CREATE SCHEMA IF NOT EXISTS ${quote(options.schema)}`);
60
+ await client.query(`CREATE TABLE IF NOT EXISTS ${quote(options.schema)}.${quote("schema_version")} (version INTEGER PRIMARY KEY)`);
61
+ for (const scope of ["open", "restricted"] as const) {
62
+ const name = table(options, scope);
63
+ await client.query(`CREATE TABLE IF NOT EXISTS ${name} (sequence BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, channel TEXT NOT NULL, topic TEXT NOT NULL, message_id TEXT NOT NULL, published_at TIMESTAMPTZ NOT NULL, expires_at TIMESTAMPTZ, xact_id XID8 NOT NULL DEFAULT pg_current_xact_id(), envelope JSONB NOT NULL, UNIQUE (channel, message_id), CHECK (jsonb_typeof(envelope) = 'object'))`);
64
+ await client.query(`CREATE INDEX IF NOT EXISTS ${quote(`${options.tables[scope]}_replay_idx`)} ON ${name} (channel, topic, sequence)`);
65
+ await client.query(`CREATE INDEX IF NOT EXISTS ${quote(`${options.tables[scope]}_expiry_idx`)} ON ${name} (expires_at) WHERE expires_at IS NOT NULL`);
66
+ }
67
+ await client.query(`INSERT INTO ${quote(options.schema)}.${quote("schema_version")} (version) VALUES (1) ON CONFLICT (version) DO NOTHING`);
68
+ });
69
+ }
70
+
71
+ export function messageBusGrantStatements(roles: string | readonly string[], scope: TopicPersistenceScope, options: ResolvedTopicBusPersistenceOptions): string[] {
72
+ const selected = table(options, scope);
73
+ return (typeof roles === "string" ? [roles] : roles).flatMap((role) => [
74
+ `GRANT USAGE ON SCHEMA ${quote(options.schema)} TO ${quote(role)};`,
75
+ `GRANT SELECT, INSERT, DELETE ON TABLE ${selected} TO ${quote(role)};`,
76
+ `GRANT SELECT ON TABLE ${quote(options.schema)}.${quote("schema_version")} TO ${quote(role)};`,
77
+ ]);
78
+ }
79
+
80
+ function cursor(scope: TopicPersistenceScope, sequence: string | number): string {
81
+ return Buffer.from(JSON.stringify([scope, String(sequence)])).toString("base64url");
82
+ }
83
+ function after(value: string | undefined, scope: TopicPersistenceScope): string {
84
+ if (!value) return "0";
85
+ const decoded = JSON.parse(Buffer.from(value, "base64url").toString()) as [string, string];
86
+ if (decoded[0] !== scope) throw new TypeError("History cursor belongs to another persistence scope");
87
+ return decoded[1];
88
+ }
89
+ export function ttlMilliseconds(value: DurationInput | false): number | null {
90
+ if (value === false) return null;
91
+ const milliseconds = object.toDuration(value);
92
+ if (milliseconds === undefined || milliseconds <= 0) throw new TypeError(`Invalid persistence TTL: ${String(value)}`);
93
+ return milliseconds;
94
+ }
95
+
96
+ export async function cleanupExpired(queryable: PgQueryable, options: ResolvedTopicBusPersistenceOptions, scope: TopicPersistenceScope, limit = options.cleanupBatchSize): Promise<number> {
97
+ const result = await queryable.query(`WITH expired AS (SELECT ctid FROM ${table(options, scope)} WHERE expires_at IS NOT NULL AND expires_at <= clock_timestamp() ORDER BY expires_at LIMIT $1) DELETE FROM ${table(options, scope)} AS messages USING expired WHERE messages.ctid = expired.ctid`, [limit]);
98
+ return result.rowCount ?? 0;
99
+ }
100
+
101
+ type HistoryRow = QueryResultRow & { sequence: string; expires_at: Date | string | null; envelope: TopicMessage };
102
+ export async function history<TBody extends object.SerializableValue>(queryable: PgQueryable, channel: string, topic: string, options: ResolvedTopicBusPersistenceOptions, input: { after?: string; limit?: number; scope?: TopicPersistenceScope } = {}): Promise<TopicHistoryPage<TBody>> {
103
+ const scope = input.scope ?? options.scope;
104
+ const limit = input.limit ?? 100;
105
+ const result = await queryable.query<HistoryRow>(`SELECT sequence, expires_at, envelope FROM ${table(options, scope)} WHERE channel = $1 AND topic = $2 AND sequence > $3::bigint AND (expires_at IS NULL OR expires_at > clock_timestamp()) ORDER BY sequence LIMIT $4`, [channel, topic, after(input.after, scope), limit]);
106
+ const messages = result.rows.map((row) => ({ cursor: cursor(scope, row.sequence), expiresAt: row.expires_at === null ? null : new Date(row.expires_at).toISOString(), scope, message: row.envelope as TopicMessage<TBody> }));
107
+ return { messages, ...(messages.length === limit ? { nextCursor: messages.at(-1)!.cursor } : {}) };
108
+ }
109
+
110
+ export async function persistedNotify(client: PgQueryable, channel: string, topic: string, message: TopicMessage, encoded: string, options: ResolvedTopicBusPersistenceOptions, scope: TopicPersistenceScope, ttl: DurationInput | false): Promise<void> {
111
+ await cleanupExpired(client, options, scope);
112
+ const milliseconds = ttlMilliseconds(ttl);
113
+ await client.query(`INSERT INTO ${table(options, scope)} (channel, topic, message_id, published_at, expires_at, envelope) VALUES ($1, $2, $3, $4, CASE WHEN $5::bigint IS NULL THEN NULL ELSE clock_timestamp() + ($5::bigint * interval '1 millisecond') END, $6::jsonb)`, [channel, topic, message.id, message.publishedAt, milliseconds, encoded]);
114
+ await client.query("SELECT pg_notify($1, $2)", [channel, encoded]);
115
+ }
package/src/topic-bus.ts CHANGED
@@ -29,6 +29,7 @@ import { async as asyncUtil, error, hash, json, object, string } from "@dbx-tool
29
29
  import type { Notification, PoolClient } from "pg";
30
30
 
31
31
  import type { PgPoolLike, PgQueryable } from "./advisory-lock.ts";
32
+ import { cleanupExpired, history, persistedNotify, provisionMessageBusSchema, resolvePersistenceOptions, type DurationInput, type ResolvedTopicBusPersistenceOptions, type TopicBusPersistenceOptions, type TopicHistoryPage, type TopicPersistenceScope } from "./persistence.ts";
32
33
 
33
34
  /**
34
35
  * `@dbx-tools/shared-core` owns the JSON-round-trip rule; this alias just keeps the
@@ -130,6 +131,8 @@ export interface TopicPublishInput<TBody extends SerializableValue = Serializabl
130
131
  metadata?: TopicMetadata;
131
132
  /** The payload. Must satisfy `object.isSerializableValue`. */
132
133
  body: TBody;
134
+ scope?: TopicPersistenceScope;
135
+ ttl?: DurationInput | false;
133
136
  }
134
137
 
135
138
  /**
@@ -185,6 +188,7 @@ export interface PostgresTopicBusOptions {
185
188
  * swallowing them, so wire this to a logger in anything long-running.
186
189
  */
187
190
  onError?: (cause: unknown) => void;
191
+ persist?: boolean | TopicBusPersistenceOptions;
188
192
  }
189
193
 
190
194
  /**
@@ -397,6 +401,8 @@ export class PostgresTopicBus {
397
401
  private reconnecting: Promise<void> | undefined;
398
402
  private readonly reconnectAbort = new AbortController();
399
403
  private closed = false;
404
+ private readonly persistence?: ResolvedTopicBusPersistenceOptions;
405
+ private provisioning?: Promise<void>;
400
406
 
401
407
  constructor(
402
408
  private readonly pool: PgPoolLike & PgQueryable,
@@ -407,6 +413,7 @@ export class PostgresTopicBus {
407
413
  );
408
414
  this.metadata = options.metadata;
409
415
  this.onError = options.onError ?? (() => undefined);
416
+ this.persistence = options.persist ? resolvePersistenceOptions(options.persist === true ? true : options.persist) : undefined;
410
417
  }
411
418
 
412
419
  /**
@@ -472,13 +479,42 @@ export class PostgresTopicBus {
472
479
  if (!decode(encoded)) {
473
480
  throw new TypeError("Message type, metadata, and body must be JSON serializable");
474
481
  }
475
- if (Buffer.byteLength(encoded, "utf8") > MAX_NOTIFY_BYTES) {
482
+ if (Buffer.byteLength(encoded, "utf8") > MAX_NOTIFY_BYTES && this.persistence?.payload !== "pointer") {
476
483
  throw new RangeError(`Postgres notification exceeds ${MAX_NOTIFY_BYTES} bytes`);
477
484
  }
478
- await this.pool.query("SELECT pg_notify($1, $2)", [this.channelName, encoded]);
485
+ if (!this.persistence) await this.pool.query("SELECT pg_notify($1, $2)", [this.channelName, encoded]);
486
+ else {
487
+ if (this.persistence.provision) {
488
+ this.provisioning ??= provisionMessageBusSchema(this.pool, this.persistence);
489
+ await this.provisioning;
490
+ }
491
+ const client = await this.pool.connect();
492
+ try {
493
+ await client.query("BEGIN");
494
+ await persistedNotify(client, this.channelName, topic, message, encoded, this.persistence, input.scope ?? this.persistence.scope, input.ttl ?? this.persistence.ttl);
495
+ await client.query("COMMIT");
496
+ } catch (cause) {
497
+ await client.query("ROLLBACK").catch(() => undefined);
498
+ throw cause;
499
+ } finally { client.release(); }
500
+ }
479
501
  return message;
480
502
  }
481
503
 
504
+ async history<TBody extends SerializableValue>(topic: string, options: { after?: string; limit?: number; scope?: TopicPersistenceScope } = {}): Promise<TopicHistoryPage<TBody>> {
505
+ if (!this.persistence) throw new Error("Postgres topic bus persistence is disabled");
506
+ if (this.persistence.provision) {
507
+ this.provisioning ??= provisionMessageBusSchema(this.pool, this.persistence);
508
+ await this.provisioning;
509
+ }
510
+ return history<TBody>(this.pool, this.channelName, topic, this.persistence, options);
511
+ }
512
+
513
+ async cleanupExpired(options: { scope?: TopicPersistenceScope; limit?: number } = {}): Promise<number> {
514
+ if (!this.persistence) throw new Error("Postgres topic bus persistence is disabled");
515
+ return cleanupExpired(this.pool, this.persistence, options.scope ?? this.persistence.scope, options.limit);
516
+ }
517
+
482
518
  /**
483
519
  * Subscribe to `topic`, returning the function that unsubscribes.
484
520
  *