@dbx-tools/postgres 0.6.86 → 0.6.88
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/README.md +81 -6
- package/index.ts +1 -0
- package/lib/exports.d.ts +2 -2
- package/lib/exports.js +2 -2
- package/lib/index.d.ts +1 -0
- package/lib/index.js +2 -1
- package/lib/src/persistence.d.ts +29 -0
- package/lib/src/persistence.js +78 -9
- package/lib/src/topic-bus.d.ts +2 -0
- package/lib/src/topic-bus.js +34 -7
- package/package.json +2 -2
- package/src/persistence.ts +174 -25
- package/src/topic-bus.ts +74 -12
package/README.md
CHANGED
|
@@ -24,6 +24,12 @@ them without a second database client or connection pool.
|
|
|
24
24
|
- Rejects a payload that would not survive a JSON round trip unchanged, at the
|
|
25
25
|
call site rather than on the wire.
|
|
26
26
|
- Reconnects a dropped listener with bounded backoff while subscribers remain.
|
|
27
|
+
- Optionally PERSISTS every published message to a package-owned table, so a
|
|
28
|
+
subscriber that was not listening can replay history by cursor, with a default
|
|
29
|
+
TTL and cleanup on insert.
|
|
30
|
+
- Two payload styles: the whole envelope in the notification, or a pointer the
|
|
31
|
+
listener reads back — which lifts the 8000-byte `NOTIFY` limit and keeps the
|
|
32
|
+
contents behind a table grant.
|
|
27
33
|
|
|
28
34
|
## Advisory Locks
|
|
29
35
|
|
|
@@ -89,7 +95,8 @@ await bus.close();
|
|
|
89
95
|
Every process listening on the channel receives every message; there are no
|
|
90
96
|
competing consumers. That makes the bus right for live fan-out — an SSE stream per
|
|
91
97
|
browser tab, a cache invalidation, a presence ping — and wrong for work
|
|
92
|
-
distribution.
|
|
98
|
+
distribution. Delivery is live-only by default; turn on `persist` (below) when a
|
|
99
|
+
subscriber needs replay, and use a real queue when it needs acks.
|
|
93
100
|
|
|
94
101
|
### The Envelope
|
|
95
102
|
|
|
@@ -173,6 +180,74 @@ One channel carries many topics, so adding a topic costs nothing; give a genuine
|
|
|
173
180
|
high-volume unrelated stream its own channel instead, since every listening
|
|
174
181
|
session decodes every message on the channel.
|
|
175
182
|
|
|
183
|
+
### Replay With `persist`
|
|
184
|
+
|
|
185
|
+
`NOTIFY` has no replay: a process that was not listening never learns what it
|
|
186
|
+
missed. Set `persist` and each published message is INSERTed in the same
|
|
187
|
+
transaction as its notification, so history becomes readable by cursor.
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
const bus = new PostgresTopicBus(pool, { persist: true });
|
|
191
|
+
|
|
192
|
+
await bus.broadcast("orders", { type: "order.updated", body: { id: 7 } });
|
|
193
|
+
|
|
194
|
+
let cursor: string | undefined;
|
|
195
|
+
do {
|
|
196
|
+
const page = await bus.history("orders", { after: cursor, limit: 100 });
|
|
197
|
+
for (const { message, expiresAt } of page.messages) handle(message, expiresAt);
|
|
198
|
+
cursor = page.nextCursor;
|
|
199
|
+
} while (cursor);
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
The row and the notification COMMIT together, which is the property the whole
|
|
203
|
+
design rests on: `NOTIFY` is delivered at commit rather than at statement time, so
|
|
204
|
+
a listener can never be told about a row it cannot yet read.
|
|
205
|
+
|
|
206
|
+
| Option | Default | Behavior |
|
|
207
|
+
| ------------------ | ----------------- | -------------------------------------------------------------- |
|
|
208
|
+
| `schema` | `dbx_message_bus` | Schema the package owns. |
|
|
209
|
+
| `scope` | `open` | Which tier's table publishes and history read by default. |
|
|
210
|
+
| `tables` | `*_messages` | Override a tier's table name for a managed installation. |
|
|
211
|
+
| `ttl` | `24 hours` | Per-message expiry. `false` keeps messages until deleted. |
|
|
212
|
+
| `payload` | `envelope` | `pointer` notifies with routing only. See below. |
|
|
213
|
+
| `cleanupBatchSize` | `1000` | Expired rows deleted per persisted publish. |
|
|
214
|
+
| `provision` | `true` | Create the schema, tables, and indexes on first persisted use. |
|
|
215
|
+
|
|
216
|
+
Messages EXPIRE by default. A 24-hour TTL is the default precisely because an
|
|
217
|
+
unbounded message table is the failure this feature would otherwise introduce;
|
|
218
|
+
expired rows are deleted in bounded batches on each persisted publish, and
|
|
219
|
+
`cleanupExpired()` runs the same sweep on demand. `ttl: false` opts one bus (or
|
|
220
|
+
`{ ttl: false }` on a single `broadcast`) out of expiry — it is available, but it
|
|
221
|
+
is not the default.
|
|
222
|
+
|
|
223
|
+
Two tiers, `open` and `restricted`, exist so one channel can carry messages with
|
|
224
|
+
different read audiences: they are separate tables, so a role granted the open
|
|
225
|
+
table cannot read restricted history. `messageBusGrantStatements(roles, scope,
|
|
226
|
+
options)` emits exactly the grants a tier needs, and a `history` cursor is bound
|
|
227
|
+
to the tier it came from — resuming an open page against the restricted table
|
|
228
|
+
throws rather than silently returning someone else's rows. Publish to a tier
|
|
229
|
+
per-message with `broadcast(topic, { scope: "restricted", ... })`.
|
|
230
|
+
|
|
231
|
+
Set `provision: false` when a migration owns the schema; the statements are
|
|
232
|
+
otherwise applied once, under an advisory transaction lock, so concurrent
|
|
233
|
+
instances installing at boot do not race.
|
|
234
|
+
|
|
235
|
+
### Envelope Or Pointer
|
|
236
|
+
|
|
237
|
+
`payload: "envelope"` (the default) puts the whole message in the notification.
|
|
238
|
+
One round trip, no read amplification, bounded by PostgreSQL's payload limit.
|
|
239
|
+
|
|
240
|
+
`payload: "pointer"` notifies with routing and identity only — `{ v, scope, topic,
|
|
241
|
+
id, sequence }` — and the listener reads the envelope back. That lifts the size
|
|
242
|
+
limit entirely (a body larger than 7900 bytes is only publishable this way) and
|
|
243
|
+
means a subscriber without the tier's table grant learns that something happened
|
|
244
|
+
without learning what. The cost is one read per notification. Listeners receive
|
|
245
|
+
the same `TopicMessage` either way; the difference is invisible above `listen`.
|
|
246
|
+
|
|
247
|
+
A pointer whose row is already gone (TTL cleanup won the race) or unreadable
|
|
248
|
+
delivers nothing rather than raising — expected on the restricted tier. Use
|
|
249
|
+
`decodePointer` if a non-bus consumer needs to read the raw notification.
|
|
250
|
+
|
|
176
251
|
### Naming A Channel
|
|
177
252
|
|
|
178
253
|
`channel` takes whatever identifies the channel, not a pre-sanitized identifier —
|
|
@@ -218,11 +293,11 @@ native surface to prefer here.
|
|
|
218
293
|
|
|
219
294
|
## Module Map
|
|
220
295
|
|
|
221
|
-
| Module | Purpose
|
|
222
|
-
| -------------- |
|
|
223
|
-
| `advisoryLock` | Stable lock IDs plus session- and transaction-scoped lock helpers.
|
|
224
|
-
| `topicBus` | Topic bus, message contracts, and deterministic `channelName`.
|
|
225
|
-
| `
|
|
296
|
+
| Module | Purpose |
|
|
297
|
+
| -------------- | ---------------------------------------------------------------------- |
|
|
298
|
+
| `advisoryLock` | Stable lock IDs plus session- and transaction-scoped lock helpers. |
|
|
299
|
+
| `topicBus` | Topic bus, message contracts, and deterministic `channelName`. |
|
|
300
|
+
| `persistence` | Stored-message schema, grants, TTL cleanup, history, and pointer wire. |
|
|
226
301
|
|
|
227
302
|
Both modules are also flattened onto the package root, so
|
|
228
303
|
`import { withAdvisoryLock, PostgresTopicBus } from "@dbx-tools/postgres"` works
|
package/index.ts
CHANGED
|
@@ -6,6 +6,7 @@ export * as advisoryLock from "./src/advisory-lock.ts";
|
|
|
6
6
|
export * as persistence from "./src/persistence.ts";
|
|
7
7
|
export * as topicBus from "./src/topic-bus.ts";
|
|
8
8
|
export type { AdvisoryLockKey, PgPoolLike, PgQueryable } from "./src/advisory-lock.ts";
|
|
9
|
+
export { POINTER_VERSION } from "./src/persistence.ts";
|
|
9
10
|
export type { DurationInput, ResolvedTopicBusPersistenceOptions } from "./src/persistence.ts";
|
|
10
11
|
export { PostgresTopicBus } from "./src/topic-bus.ts";
|
|
11
12
|
export type { TopicMetadata, TopicMessage, TopicPublishInput, TopicListener, TopicMetadataProvider, PostgresTopicBusOptions } from "./src/topic-bus.ts";
|
package/lib/exports.d.ts
CHANGED
|
@@ -1,3 +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";
|
|
2
|
+
export { decodePointer, messageBusGrantStatements, provisionMessageBusSchema, resolvePersistenceOptions, } from "./src/persistence.ts";
|
|
3
|
+
export type { TopicPersistenceScope, TopicBusPersistenceOptions, StoredTopicMessage, TopicHistoryPage, TopicPointer, } from "./src/persistence.ts";
|
package/lib/exports.js
CHANGED
|
@@ -3,5 +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
|
-
export { messageBusGrantStatements, provisionMessageBusSchema, resolvePersistenceOptions } from "./src/persistence.js";
|
|
7
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
6
|
+
export { decodePointer, messageBusGrantStatements, provisionMessageBusSchema, resolvePersistenceOptions, } from "./src/persistence.js";
|
|
7
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhwb3J0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL2V4cG9ydHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsZ0ZBQWdGO0FBQ2hGLDRFQUE0RTtBQUM1RSw0RUFBNEU7QUFDNUUsa0RBQWtEO0FBQ2xELE9BQU8sRUFDTCxjQUFjLEVBQ2QsZ0JBQWdCLEVBQ2hCLDJCQUEyQixHQUM1QixNQUFNLHdCQUF3QixDQUFDO0FBQ2hDLE9BQU8sRUFDTCxhQUFhLEVBQ2IseUJBQXlCLEVBQ3pCLHlCQUF5QixFQUN6Qix5QkFBeUIsR0FDMUIsTUFBTSxzQkFBc0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIEZsYXQgcmUtZXhwb3J0cyBsYXllcmVkIG9udG8gdGhlIGdlbmVyYXRlZCBgaW5kZXgudHNgIGJhcnJlbCwgd2hpY2ggcHVibGlzaGVzXG4vLyBlYWNoIG1vZHVsZSBhcyBhIG5hbWVzcGFjZSAoYGFkdmlzb3J5TG9ja2AsIGB0b3BpY0J1c2ApIGFuZCBkb2VzIG5vdCBsaWZ0XG4vLyBmdW5jdGlvbnMgdG8gdGhlIHBhY2thZ2Ugcm9vdC4gVGhlc2UgYXJlIHRoZSBjYWxsLXNpdGUgbmFtZXMsIHNvIHRoZXkgYXJlXG4vLyBpbXBvcnRhYmxlIGRpcmVjdGx5IGZyb20gYEBkYngtdG9vbHMvcG9zdGdyZXNgLlxuZXhwb3J0IHtcbiAgYWR2aXNvcnlMb2NrSWQsXG4gIHdpdGhBZHZpc29yeUxvY2ssXG4gIHdpdGhBZHZpc29yeVRyYW5zYWN0aW9uTG9jayxcbn0gZnJvbSBcIi4vc3JjL2Fkdmlzb3J5LWxvY2sudHNcIjtcbmV4cG9ydCB7XG4gIGRlY29kZVBvaW50ZXIsXG4gIG1lc3NhZ2VCdXNHcmFudFN0YXRlbWVudHMsXG4gIHByb3Zpc2lvbk1lc3NhZ2VCdXNTY2hlbWEsXG4gIHJlc29sdmVQZXJzaXN0ZW5jZU9wdGlvbnMsXG59IGZyb20gXCIuL3NyYy9wZXJzaXN0ZW5jZS50c1wiO1xuZXhwb3J0IHR5cGUge1xuICBUb3BpY1BlcnNpc3RlbmNlU2NvcGUsXG4gIFRvcGljQnVzUGVyc2lzdGVuY2VPcHRpb25zLFxuICBTdG9yZWRUb3BpY01lc3NhZ2UsXG4gIFRvcGljSGlzdG9yeVBhZ2UsXG4gIFRvcGljUG9pbnRlcixcbn0gZnJvbSBcIi4vc3JjL3BlcnNpc3RlbmNlLnRzXCI7XG4iXX0=
|
package/lib/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * as advisoryLock from "./src/advisory-lock.ts";
|
|
|
2
2
|
export * as persistence from "./src/persistence.ts";
|
|
3
3
|
export * as topicBus from "./src/topic-bus.ts";
|
|
4
4
|
export type { AdvisoryLockKey, PgPoolLike, PgQueryable } from "./src/advisory-lock.ts";
|
|
5
|
+
export { POINTER_VERSION } from "./src/persistence.ts";
|
|
5
6
|
export type { DurationInput, ResolvedTopicBusPersistenceOptions } from "./src/persistence.ts";
|
|
6
7
|
export { PostgresTopicBus } from "./src/topic-bus.ts";
|
|
7
8
|
export type { TopicMetadata, TopicMessage, TopicPublishInput, TopicListener, TopicMetadataProvider, PostgresTopicBusOptions } from "./src/topic-bus.ts";
|
package/lib/index.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
export * as advisoryLock from "./src/advisory-lock.js";
|
|
5
5
|
export * as persistence from "./src/persistence.js";
|
|
6
6
|
export * as topicBus from "./src/topic-bus.js";
|
|
7
|
+
export { POINTER_VERSION } from "./src/persistence.js";
|
|
7
8
|
export { PostgresTopicBus } from "./src/topic-bus.js";
|
|
8
9
|
export * from "./exports.js";
|
|
9
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
10
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwyQ0FBMkM7QUFDM0MsbURBQW1EO0FBQ25ELHdFQUF3RTtBQUV4RSxPQUFPLEtBQUssWUFBWSxNQUFNLHdCQUF3QixDQUFDO0FBQ3ZELE9BQU8sS0FBSyxXQUFXLE1BQU0sc0JBQXNCLENBQUM7QUFDcEQsT0FBTyxLQUFLLFFBQVEsTUFBTSxvQkFBb0IsQ0FBQztBQUUvQyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFdkQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFFdEQsY0FBYyxjQUFjLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBHRU5FUkFURUQgYnkgcHJvamVuIHdhdGNoIC0gRE8gTk9UIEVESVQuXG4vLyBSZWdlbmVyYXRlZCBmcm9tIHRoZSBleHBvcnRpbmcgbW9kdWxlcyBpbiAuL3NyYy5cbi8vIEhhbmQgZWRpdHMgYXJlIG92ZXJ3cml0dGVuIG9uIHRoZSBuZXh0IHdhdGNoOyB0aGlzIGZpbGUgaXMgcmVhZC1vbmx5LlxuXG5leHBvcnQgKiBhcyBhZHZpc29yeUxvY2sgZnJvbSBcIi4vc3JjL2Fkdmlzb3J5LWxvY2sudHNcIjtcbmV4cG9ydCAqIGFzIHBlcnNpc3RlbmNlIGZyb20gXCIuL3NyYy9wZXJzaXN0ZW5jZS50c1wiO1xuZXhwb3J0ICogYXMgdG9waWNCdXMgZnJvbSBcIi4vc3JjL3RvcGljLWJ1cy50c1wiO1xuZXhwb3J0IHR5cGUgeyBBZHZpc29yeUxvY2tLZXksIFBnUG9vbExpa2UsIFBnUXVlcnlhYmxlIH0gZnJvbSBcIi4vc3JjL2Fkdmlzb3J5LWxvY2sudHNcIjtcbmV4cG9ydCB7IFBPSU5URVJfVkVSU0lPTiB9IGZyb20gXCIuL3NyYy9wZXJzaXN0ZW5jZS50c1wiO1xuZXhwb3J0IHR5cGUgeyBEdXJhdGlvbklucHV0LCBSZXNvbHZlZFRvcGljQnVzUGVyc2lzdGVuY2VPcHRpb25zIH0gZnJvbSBcIi4vc3JjL3BlcnNpc3RlbmNlLnRzXCI7XG5leHBvcnQgeyBQb3N0Z3Jlc1RvcGljQnVzIH0gZnJvbSBcIi4vc3JjL3RvcGljLWJ1cy50c1wiO1xuZXhwb3J0IHR5cGUgeyBUb3BpY01ldGFkYXRhLCBUb3BpY01lc3NhZ2UsIFRvcGljUHVibGlzaElucHV0LCBUb3BpY0xpc3RlbmVyLCBUb3BpY01ldGFkYXRhUHJvdmlkZXIsIFBvc3RncmVzVG9waWNCdXNPcHRpb25zIH0gZnJvbSBcIi4vc3JjL3RvcGljLWJ1cy50c1wiO1xuZXhwb3J0ICogZnJvbSBcIi4vZXhwb3J0cy50c1wiO1xuIl19
|
package/lib/src/persistence.d.ts
CHANGED
|
@@ -31,6 +31,11 @@ export interface TopicHistoryPage<TBody extends object.SerializableValue = objec
|
|
|
31
31
|
messages: StoredTopicMessage<TBody>[];
|
|
32
32
|
nextCursor?: string;
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Pointer-payload version. A listener that does not recognize the version treats
|
|
36
|
+
* the notification as foreign traffic rather than guessing at its shape.
|
|
37
|
+
*/
|
|
38
|
+
export declare const POINTER_VERSION = 1;
|
|
34
39
|
export declare function resolvePersistenceOptions(value: true | TopicBusPersistenceOptions): ResolvedTopicBusPersistenceOptions;
|
|
35
40
|
export declare function provisionMessageBusSchema(pool: PgPoolLike, options: ResolvedTopicBusPersistenceOptions): Promise<void>;
|
|
36
41
|
export declare function messageBusGrantStatements(roles: string | readonly string[], scope: TopicPersistenceScope, options: ResolvedTopicBusPersistenceOptions): string[];
|
|
@@ -42,3 +47,27 @@ export declare function history<TBody extends object.SerializableValue>(queryabl
|
|
|
42
47
|
scope?: TopicPersistenceScope;
|
|
43
48
|
}): Promise<TopicHistoryPage<TBody>>;
|
|
44
49
|
export declare function persistedNotify(client: PgQueryable, channel: string, topic: string, message: TopicMessage, encoded: string, options: ResolvedTopicBusPersistenceOptions, scope: TopicPersistenceScope, ttl: DurationInput | false): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* The `payload: "pointer"` notification body: routing and identity only, so the
|
|
52
|
+
* size limit does not apply and a listener without the table grant learns that
|
|
53
|
+
* something happened without learning what.
|
|
54
|
+
*/
|
|
55
|
+
export declare function pointerPayload(scope: TopicPersistenceScope, topic: string, id: string, sequence: string | number): string;
|
|
56
|
+
/** A decoded pointer notification. */
|
|
57
|
+
export interface TopicPointer {
|
|
58
|
+
scope: TopicPersistenceScope;
|
|
59
|
+
topic: string;
|
|
60
|
+
id: string;
|
|
61
|
+
sequence: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Read a notification as a pointer, or `undefined` when it is not one. The channel
|
|
65
|
+
* is shared, so an unrecognized payload is ordinary traffic rather than an error.
|
|
66
|
+
*/
|
|
67
|
+
export declare function decodePointer(value: string | undefined): TopicPointer | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* Fetch the one stored envelope a pointer names. Returns `undefined` when the row
|
|
70
|
+
* is gone (TTL cleanup won the race) or the reader lacks the table's grant, both
|
|
71
|
+
* of which are expected on the `restricted` tier rather than errors.
|
|
72
|
+
*/
|
|
73
|
+
export declare function readPointer<TBody extends object.SerializableValue>(queryable: PgQueryable, channel: string, pointer: TopicPointer, options: ResolvedTopicBusPersistenceOptions): Promise<TopicMessage<TBody> | undefined>;
|
package/lib/src/persistence.js
CHANGED
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
import { object } from "@dbx-tools/shared-core";
|
|
2
2
|
import { withAdvisoryTransactionLock } from "./advisory-lock.js";
|
|
3
3
|
const DEFAULT_TTL = "24 hours";
|
|
4
|
+
/**
|
|
5
|
+
* Pointer-payload version. A listener that does not recognize the version treats
|
|
6
|
+
* the notification as foreign traffic rather than guessing at its shape.
|
|
7
|
+
*/
|
|
8
|
+
export const POINTER_VERSION = 1;
|
|
4
9
|
const quote = (value) => `"${value.replaceAll('"', '""')}"`;
|
|
5
10
|
const table = (options, scope) => `${quote(options.schema)}.${quote(options.tables[scope])}`;
|
|
6
11
|
export function resolvePersistenceOptions(value) {
|
|
7
12
|
const configured = value === true ? {} : value;
|
|
8
13
|
const scope = configured.scope ?? "open";
|
|
9
|
-
if (scope !== "open" && scope !== "restricted")
|
|
14
|
+
if (scope !== "open" && scope !== "restricted") {
|
|
10
15
|
throw new TypeError(`Unknown persistence scope: ${String(scope)}`);
|
|
16
|
+
}
|
|
11
17
|
return {
|
|
12
18
|
schema: configured.schema ?? "dbx_message_bus",
|
|
13
19
|
scope,
|
|
14
|
-
tables: {
|
|
20
|
+
tables: {
|
|
21
|
+
open: configured.tables?.open ?? "open_messages",
|
|
22
|
+
restricted: configured.tables?.restricted ?? "restricted_messages",
|
|
23
|
+
},
|
|
15
24
|
ttl: configured.ttl ?? DEFAULT_TTL,
|
|
16
25
|
payload: configured.payload ?? "envelope",
|
|
17
26
|
cleanupBatchSize: configured.cleanupBatchSize ?? 1000,
|
|
@@ -46,16 +55,18 @@ function after(value, scope) {
|
|
|
46
55
|
if (!value)
|
|
47
56
|
return "0";
|
|
48
57
|
const decoded = JSON.parse(Buffer.from(value, "base64url").toString());
|
|
49
|
-
if (decoded[0] !== scope)
|
|
58
|
+
if (decoded[0] !== scope) {
|
|
50
59
|
throw new TypeError("History cursor belongs to another persistence scope");
|
|
60
|
+
}
|
|
51
61
|
return decoded[1];
|
|
52
62
|
}
|
|
53
63
|
export function ttlMilliseconds(value) {
|
|
54
64
|
if (value === false)
|
|
55
65
|
return null;
|
|
56
66
|
const milliseconds = object.toDuration(value);
|
|
57
|
-
if (milliseconds === undefined || milliseconds <= 0)
|
|
67
|
+
if (milliseconds === undefined || milliseconds <= 0) {
|
|
58
68
|
throw new TypeError(`Invalid persistence TTL: ${String(value)}`);
|
|
69
|
+
}
|
|
59
70
|
return milliseconds;
|
|
60
71
|
}
|
|
61
72
|
export async function cleanupExpired(queryable, options, scope, limit = options.cleanupBatchSize) {
|
|
@@ -66,13 +77,71 @@ export async function history(queryable, channel, topic, options, input = {}) {
|
|
|
66
77
|
const scope = input.scope ?? options.scope;
|
|
67
78
|
const limit = input.limit ?? 100;
|
|
68
79
|
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) => ({
|
|
70
|
-
|
|
80
|
+
const messages = result.rows.map((row) => ({
|
|
81
|
+
cursor: cursor(scope, row.sequence),
|
|
82
|
+
expiresAt: row.expires_at === null ? null : new Date(row.expires_at).toISOString(),
|
|
83
|
+
scope,
|
|
84
|
+
message: row.envelope,
|
|
85
|
+
}));
|
|
86
|
+
return {
|
|
87
|
+
messages,
|
|
88
|
+
...(messages.length === limit ? { nextCursor: messages.at(-1).cursor } : {}),
|
|
89
|
+
};
|
|
71
90
|
}
|
|
72
91
|
export async function persistedNotify(client, channel, topic, message, encoded, options, scope, ttl) {
|
|
73
92
|
await cleanupExpired(client, options, scope);
|
|
74
93
|
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
|
-
|
|
94
|
+
const inserted = 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) RETURNING sequence`, [channel, topic, message.id, message.publishedAt, milliseconds, encoded]);
|
|
95
|
+
// The row and the notification commit together, so a pointer is never delivered
|
|
96
|
+
// before the row it names is readable - `NOTIFY` is delivered at COMMIT, not at
|
|
97
|
+
// statement time.
|
|
98
|
+
const payload = options.payload === "pointer"
|
|
99
|
+
? pointerPayload(scope, topic, message.id, inserted.rows[0]?.sequence ?? "0")
|
|
100
|
+
: encoded;
|
|
101
|
+
await client.query("SELECT pg_notify($1, $2)", [channel, payload]);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The `payload: "pointer"` notification body: routing and identity only, so the
|
|
105
|
+
* size limit does not apply and a listener without the table grant learns that
|
|
106
|
+
* something happened without learning what.
|
|
107
|
+
*/
|
|
108
|
+
export function pointerPayload(scope, topic, id, sequence) {
|
|
109
|
+
return JSON.stringify({ v: POINTER_VERSION, scope, topic, id, sequence: String(sequence) });
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Read a notification as a pointer, or `undefined` when it is not one. The channel
|
|
113
|
+
* is shared, so an unrecognized payload is ordinary traffic rather than an error.
|
|
114
|
+
*/
|
|
115
|
+
export function decodePointer(value) {
|
|
116
|
+
if (!value)
|
|
117
|
+
return undefined;
|
|
118
|
+
let record;
|
|
119
|
+
try {
|
|
120
|
+
record = JSON.parse(value);
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
if (!record || typeof record !== "object" || Array.isArray(record))
|
|
126
|
+
return undefined;
|
|
127
|
+
const candidate = record;
|
|
128
|
+
if (candidate.v !== POINTER_VERSION)
|
|
129
|
+
return undefined;
|
|
130
|
+
const { scope, topic, id, sequence } = candidate;
|
|
131
|
+
if (scope !== "open" && scope !== "restricted")
|
|
132
|
+
return undefined;
|
|
133
|
+
if (typeof topic !== "string" || typeof id !== "string" || typeof sequence !== "string") {
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
return { scope, topic, id, sequence };
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Fetch the one stored envelope a pointer names. Returns `undefined` when the row
|
|
140
|
+
* is gone (TTL cleanup won the race) or the reader lacks the table's grant, both
|
|
141
|
+
* of which are expected on the `restricted` tier rather than errors.
|
|
142
|
+
*/
|
|
143
|
+
export async function readPointer(queryable, channel, pointer, options) {
|
|
144
|
+
const result = await queryable.query(`SELECT envelope FROM ${table(options, pointer.scope)} WHERE channel = $1 AND message_id = $2 AND (expires_at IS NULL OR expires_at > clock_timestamp())`, [channel, pointer.id]);
|
|
145
|
+
return result.rows[0]?.envelope;
|
|
77
146
|
}
|
|
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=
|
|
147
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVyc2lzdGVuY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcGVyc2lzdGVuY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBR2hELE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBc0NqRSxNQUFNLFdBQVcsR0FBRyxVQUFVLENBQUM7QUFDL0I7OztHQUdHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sZUFBZSxHQUFHLENBQUMsQ0FBQztBQUNqQyxNQUFNLEtBQUssR0FBRyxDQUFDLEtBQWEsRUFBVSxFQUFFLENBQUMsSUFBSSxLQUFLLENBQUMsVUFBVSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDO0FBQzVFLE1BQU0sS0FBSyxHQUFHLENBQUMsT0FBMkMsRUFBRSxLQUE0QixFQUFVLEVBQUUsQ0FDbEcsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQztBQUU3RCxNQUFNLFVBQVUseUJBQXlCLENBQ3ZDLEtBQXdDO0lBRXhDLE1BQU0sVUFBVSxHQUFHLEtBQUssS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO0lBQy9DLE1BQU0sS0FBSyxHQUFHLFVBQVUsQ0FBQyxLQUFLLElBQUksTUFBTSxDQUFDO0lBQ3pDLElBQUksS0FBSyxLQUFLLE1BQU0sSUFBSSxLQUFLLEtBQUssWUFBWSxFQUFFLENBQUM7UUFDL0MsTUFBTSxJQUFJLFNBQVMsQ0FBQyw4QkFBOEIsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNyRSxDQUFDO0lBQ0QsT0FBTztRQUNMLE1BQU0sRUFBRSxVQUFVLENBQUMsTUFBTSxJQUFJLGlCQUFpQjtRQUM5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RSxLQUFLLEVBQUUsRUFBRSxFQUFFLFFBQVEsRUFBRSxDQUFDO0FBQ3hDLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxXQUFXLENBQy9CLFNBQXNCLEVBQ3RCLE9BQWUsRUFDZixPQUFxQixFQUNyQixPQUEyQztJQUUzQyxNQUFNLE1BQU0sR0FBRyxNQUFNLFNBQVMsQ0FBQyxLQUFLLENBQ2xDLHdCQUF3QixLQUFLLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxLQUFLLENBQUMsb0dBQW9HLEVBQ3pKLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FDdEIsQ0FBQztJQUNGLE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxRQUEyQyxDQUFDO0FBQ3JFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBvYmplY3QgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHR5cGUgeyBRdWVyeVJlc3VsdFJvdyB9IGZyb20gXCJwZ1wiO1xuaW1wb3J0IHR5cGUgeyBQZ1Bvb2xMaWtlLCBQZ1F1ZXJ5YWJsZSB9IGZyb20gXCIuL2Fkdmlzb3J5LWxvY2sudHNcIjtcbmltcG9ydCB7IHdpdGhBZHZpc29yeVRyYW5zYWN0aW9uTG9jayB9IGZyb20gXCIuL2Fkdmlzb3J5LWxvY2sudHNcIjtcbmltcG9ydCB0eXBlIHsgVG9waWNNZXNzYWdlIH0gZnJvbSBcIi4vdG9waWMtYnVzLnRzXCI7XG5cbmV4cG9ydCB0eXBlIFRvcGljUGVyc2lzdGVuY2VTY29wZSA9IFwib3BlblwiIHwgXCJyZXN0cmljdGVkXCI7XG5leHBvcnQgdHlwZSBEdXJhdGlvbklucHV0ID0gc3RyaW5nIHwgbnVtYmVyO1xuZXhwb3J0IGludGVyZmFjZSBUb3BpY0J1c1BlcnNpc3RlbmNlT3B0aW9ucyB7XG4gIHNjaGVtYT86IHN0cmluZztcbiAgc2NvcGU/OiBUb3BpY1BlcnNpc3RlbmNlU2NvcGU7XG4gIHRhYmxlcz86IFBhcnRpYWw8UmVjb3JkPFRvcGljUGVyc2lzdGVuY2VTY29wZSwgc3RyaW5nPj47XG4gIHR0bD86IER1cmF0aW9uSW5wdXQgfCBmYWxzZTtcbiAgcGF5bG9hZD86IFwiZW52ZWxvcGVcIiB8IFwicG9pbnRlclwiO1xuICBjbGVhbnVwQmF0Y2hTaXplPzogbnVtYmVyO1xuICBwcm92aXNpb24/OiBib29sZWFuO1xufVxuZXhwb3J0IGludGVyZmFjZSBSZXNvbHZlZFRvcGljQnVzUGVyc2lzdGVuY2VPcHRpb25zIHtcbiAgc2NoZW1hOiBzdHJpbmc7XG4gIHNjb3BlOiBUb3BpY1BlcnNpc3RlbmNlU2NvcGU7XG4gIHRhYmxlczogUmVjb3JkPFRvcGljUGVyc2lzdGVuY2VTY29wZSwgc3RyaW5nPjtcbiAgdHRsOiBEdXJhdGlvbklucHV0IHwgZmFsc2U7XG4gIHBheWxvYWQ6IFwiZW52ZWxvcGVcIiB8IFwicG9pbnRlclwiO1xuICBjbGVhbnVwQmF0Y2hTaXplOiBudW1iZXI7XG4gIHByb3Zpc2lvbjogYm9vbGVhbjtcbn1cbmV4cG9ydCBpbnRlcmZhY2UgU3RvcmVkVG9waWNNZXNzYWdlPFxuICBUQm9keSBleHRlbmRzIG9iamVjdC5TZXJpYWxpemFibGVWYWx1ZSA9IG9iamVjdC5TZXJpYWxpemFibGVWYWx1ZSxcbj4ge1xuICBjdXJzb3I6IHN0cmluZztcbiAgZXhwaXJlc0F0OiBzdHJpbmcgfCBudWxsO1xuICBzY29wZTogVG9waWNQZXJzaXN0ZW5jZVNjb3BlO1xuICBtZXNzYWdlOiBUb3BpY01lc3NhZ2U8VEJvZHk+O1xufVxuZXhwb3J0IGludGVyZmFjZSBUb3BpY0hpc3RvcnlQYWdlPFxuICBUQm9keSBleHRlbmRzIG9iamVjdC5TZXJpYWxpemFibGVWYWx1ZSA9IG9iamVjdC5TZXJpYWxpemFibGVWYWx1ZSxcbj4ge1xuICBtZXNzYWdlczogU3RvcmVkVG9waWNNZXNzYWdlPFRCb2R5PltdO1xuICBuZXh0Q3Vyc29yPzogc3RyaW5nO1xufVxuXG5jb25zdCBERUZBVUxUX1RUTCA9IFwiMjQgaG91cnNcIjtcbi8qKlxuICogUG9pbnRlci1wYXlsb2FkIHZlcnNpb24uIEEgbGlzdGVuZXIgdGhhdCBkb2VzIG5vdCByZWNvZ25pemUgdGhlIHZlcnNpb24gdHJlYXRzXG4gKiB0aGUgbm90aWZpY2F0aW9uIGFzIGZvcmVpZ24gdHJhZmZpYyByYXRoZXIgdGhhbiBndWVzc2luZyBhdCBpdHMgc2hhcGUuXG4gKi9cbmV4cG9ydCBjb25zdCBQT0lOVEVSX1ZFUlNJT04gPSAxO1xuY29uc3QgcXVvdGUgPSAodmFsdWU6IHN0cmluZyk6IHN0cmluZyA9PiBgXCIke3ZhbHVlLnJlcGxhY2VBbGwoJ1wiJywgJ1wiXCInKX1cImA7XG5jb25zdCB0YWJsZSA9IChvcHRpb25zOiBSZXNvbHZlZFRvcGljQnVzUGVyc2lzdGVuY2VPcHRpb25zLCBzY29wZTogVG9waWNQZXJzaXN0ZW5jZVNjb3BlKTogc3RyaW5nID0+XG4gIGAke3F1b3RlKG9wdGlvbnMuc2NoZW1hKX0uJHtxdW90ZShvcHRpb25zLnRhYmxlc1tzY29wZV0pfWA7XG5cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlUGVyc2lzdGVuY2VPcHRpb25zKFxuICB2YWx1ZTogdHJ1ZSB8IFRvcGljQnVzUGVyc2lzdGVuY2VPcHRpb25zLFxuKTogUmVzb2x2ZWRUb3BpY0J1c1BlcnNpc3RlbmNlT3B0aW9ucyB7XG4gIGNvbnN0IGNvbmZpZ3VyZWQgPSB2YWx1ZSA9PT0gdHJ1ZSA/IHt9IDogdmFsdWU7XG4gIGNvbnN0IHNjb3BlID0gY29uZmlndXJlZC5zY29wZSA/PyBcIm9wZW5cIjtcbiAgaWYgKHNjb3BlICE9PSBcIm9wZW5cIiAmJiBzY29wZSAhPT0gXCJyZXN0cmljdGVkXCIpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKGBVbmtub3duIHBlcnNpc3RlbmNlIHNjb3BlOiAke1N0cmluZyhzY29wZSl9YCk7XG4gIH1cbiAgcmV0dXJuIHtcbiAgICBzY2hlbWE6IGNvbmZpZ3VyZWQuc2NoZW1hID8/IFwiZGJ4X21lc3NhZ2VfYnVzXCIsXG4gICAgc2NvcGUsXG4gICAgdGFibGVzOiB7XG4gICAgICBvcGVuOiBjb25maWd1cmVkLnRhYmxlcz8ub3BlbiA/PyBcIm9wZW5fbWVzc2FnZXNcIixcbiAgICAgIHJlc3RyaWN0ZWQ6IGNvbmZpZ3VyZWQudGFibGVzPy5yZXN0cmljdGVkID8/IFwicmVzdHJpY3RlZF9tZXNzYWdlc1wiLFxuICAgIH0sXG4gICAgdHRsOiBjb25maWd1cmVkLnR0bCA/PyBERUZBVUxUX1RUTCxcbiAgICBwYXlsb2FkOiBjb25maWd1cmVkLnBheWxvYWQgPz8gXCJlbnZlbG9wZVwiLFxuICAgIGNsZWFudXBCYXRjaFNpemU6IGNvbmZpZ3VyZWQuY2xlYW51cEJhdGNoU2l6ZSA/PyAxMDAwLFxuICAgIHByb3Zpc2lvbjogY29uZmlndXJlZC5wcm92aXNpb24gPz8gdHJ1ZSxcbiAgfTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHByb3Zpc2lvbk1lc3NhZ2VCdXNTY2hlbWEoXG4gIHBvb2w6IFBnUG9vbExpa2UsXG4gIG9wdGlvbnM6IFJlc29sdmVkVG9waWNCdXNQZXJzaXN0ZW5jZU9wdGlvbnMsXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgYXdhaXQgd2l0aEFkdmlzb3J5VHJhbnNhY3Rpb25Mb2NrKHBvb2wsIFtcImRieF9tZXNzYWdlX2J1c1wiLCBcInNjaGVtYVwiXSwgYXN5bmMgKGNsaWVudCkgPT4ge1xuICAgIGF3YWl0IGNsaWVudC5xdWVyeShgQ1JFQVRFIFNDSEVNQSBJRiBOT1QgRVhJU1RTICR7cXVvdGUob3B0aW9ucy5zY2hlbWEpfWApO1xuICAgIGF3YWl0IGNsaWVudC5xdWVyeShcbiAgICAgIGBDUkVBVEUgVEFCTEUgSUYgTk9UIEVYSVNUUyAke3F1b3RlKG9wdGlvbnMuc2NoZW1hKX0uJHtxdW90ZShcInNjaGVtYV92ZXJzaW9uXCIpfSAodmVyc2lvbiBJTlRFR0VSIFBSSU1BUlkgS0VZKWAsXG4gICAgKTtcbiAgICBmb3IgKGNvbnN0IHNjb3BlIG9mIFtcIm9wZW5cIiwgXCJyZXN0cmljdGVkXCJdIGFzIGNvbnN0KSB7XG4gICAgICBjb25zdCBuYW1lID0gdGFibGUob3B0aW9ucywgc2NvcGUpO1xuICAgICAgYXdhaXQgY2xpZW50LnF1ZXJ5KFxuICAgICAgICBgQ1JFQVRFIFRBQkxFIElGIE5PVCBFWElTVFMgJHtuYW1lfSAoc2VxdWVuY2UgQklHSU5UIEdFTkVSQVRFRCBBTFdBWVMgQVMgSURFTlRJVFkgUFJJTUFSWSBLRVksIGNoYW5uZWwgVEVYVCBOT1QgTlVMTCwgdG9waWMgVEVYVCBOT1QgTlVMTCwgbWVzc2FnZV9pZCBURVhUIE5PVCBOVUxMLCBwdWJsaXNoZWRfYXQgVElNRVNUQU1QVFogTk9UIE5VTEwsIGV4cGlyZXNfYXQgVElNRVNUQU1QVFosIHhhY3RfaWQgWElEOCBOT1QgTlVMTCBERUZBVUxUIHBnX2N1cnJlbnRfeGFjdF9pZCgpLCBlbnZlbG9wZSBKU09OQiBOT1QgTlVMTCwgVU5JUVVFIChjaGFubmVsLCBtZXNzYWdlX2lkKSwgQ0hFQ0sgKGpzb25iX3R5cGVvZihlbnZlbG9wZSkgPSAnb2JqZWN0JykpYCxcbiAgICAgICk7XG4gICAgICBhd2FpdCBjbGllbnQucXVlcnkoXG4gICAgICAgIGBDUkVBVEUgSU5ERVggSUYgTk9UIEVYSVNUUyAke3F1b3RlKGAke29wdGlvbnMudGFibGVzW3Njb3BlXX1fcmVwbGF5X2lkeGApfSBPTiAke25hbWV9IChjaGFubmVsLCB0b3BpYywgc2VxdWVuY2UpYCxcbiAgICAgICk7XG4gICAgICBhd2FpdCBjbGllbnQucXVlcnkoXG4gICAgICAgIGBDUkVBVEUgSU5ERVggSUYgTk9UIEVYSVNUUyAke3F1b3RlKGAke29wdGlvbnMudGFibGVzW3Njb3BlXX1fZXhwaXJ5X2lkeGApfSBPTiAke25hbWV9IChleHBpcmVzX2F0KSBXSEVSRSBleHBpcmVzX2F0IElTIE5PVCBOVUxMYCxcbiAgICAgICk7XG4gICAgfVxuICAgIGF3YWl0IGNsaWVudC5xdWVyeShcbiAgICAgIGBJTlNFUlQgSU5UTyAke3F1b3RlKG9wdGlvbnMuc2NoZW1hKX0uJHtxdW90ZShcInNjaGVtYV92ZXJzaW9uXCIpfSAodmVyc2lvbikgVkFMVUVTICgxKSBPTiBDT05GTElDVCAodmVyc2lvbikgRE8gTk9USElOR2AsXG4gICAgKTtcbiAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBtZXNzYWdlQnVzR3JhbnRTdGF0ZW1lbnRzKFxuICByb2xlczogc3RyaW5nIHwgcmVhZG9ubHkgc3RyaW5nW10sXG4gIHNjb3BlOiBUb3BpY1BlcnNpc3RlbmNlU2NvcGUsXG4gIG9wdGlvbnM6IFJlc29sdmVkVG9waWNCdXNQZXJzaXN0ZW5jZU9wdGlvbnMsXG4pOiBzdHJpbmdbXSB7XG4gIGNvbnN0IHNlbGVjdGVkID0gdGFibGUob3B0aW9ucywgc2NvcGUpO1xuICByZXR1cm4gKHR5cGVvZiByb2xlcyA9PT0gXCJzdHJpbmdcIiA/IFtyb2xlc10gOiByb2xlcykuZmxhdE1hcCgocm9sZSkgPT4gW1xuICAgIGBHUkFOVCBVU0FHRSBPTiBTQ0hFTUEgJHtxdW90ZShvcHRpb25zLnNjaGVtYSl9IFRPICR7cXVvdGUocm9sZSl9O2AsXG4gICAgYEdSQU5UIFNFTEVDVCwgSU5TRVJULCBERUxFVEUgT04gVEFCTEUgJHtzZWxlY3RlZH0gVE8gJHtxdW90ZShyb2xlKX07YCxcbiAgICBgR1JBTlQgU0VMRUNUIE9OIFRBQkxFICR7cXVvdGUob3B0aW9ucy5zY2hlbWEpfS4ke3F1b3RlKFwic2NoZW1hX3ZlcnNpb25cIil9IFRPICR7cXVvdGUocm9sZSl9O2AsXG4gIF0pO1xufVxuXG5mdW5jdGlvbiBjdXJzb3Ioc2NvcGU6IFRvcGljUGVyc2lzdGVuY2VTY29wZSwgc2VxdWVuY2U6IHN0cmluZyB8IG51bWJlcik6IHN0cmluZyB7XG4gIHJldHVybiBCdWZmZXIuZnJvbShKU09OLnN0cmluZ2lmeShbc2NvcGUsIFN0cmluZyhzZXF1ZW5jZSldKSkudG9TdHJpbmcoXCJiYXNlNjR1cmxcIik7XG59XG5mdW5jdGlvbiBhZnRlcih2YWx1ZTogc3RyaW5nIHwgdW5kZWZpbmVkLCBzY29wZTogVG9waWNQZXJzaXN0ZW5jZVNjb3BlKTogc3RyaW5nIHtcbiAgaWYgKCF2YWx1ZSkgcmV0dXJuIFwiMFwiO1xuICBjb25zdCBkZWNvZGVkID0gSlNPTi5wYXJzZShCdWZmZXIuZnJvbSh2YWx1ZSwgXCJiYXNlNjR1cmxcIikudG9TdHJpbmcoKSkgYXMgW3N0cmluZywgc3RyaW5nXTtcbiAgaWYgKGRlY29kZWRbMF0gIT09IHNjb3BlKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkhpc3RvcnkgY3Vyc29yIGJlbG9uZ3MgdG8gYW5vdGhlciBwZXJzaXN0ZW5jZSBzY29wZVwiKTtcbiAgfVxuICByZXR1cm4gZGVjb2RlZFsxXTtcbn1cbmV4cG9ydCBmdW5jdGlvbiB0dGxNaWxsaXNlY29uZHModmFsdWU6IER1cmF0aW9uSW5wdXQgfCBmYWxzZSk6IG51bWJlciB8IG51bGwge1xuICBpZiAodmFsdWUgPT09IGZhbHNlKSByZXR1cm4gbnVsbDtcbiAgY29uc3QgbWlsbGlzZWNvbmRzID0gb2JqZWN0LnRvRHVyYXRpb24odmFsdWUpO1xuICBpZiAobWlsbGlzZWNvbmRzID09PSB1bmRlZmluZWQgfHwgbWlsbGlzZWNvbmRzIDw9IDApIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKGBJbnZhbGlkIHBlcnNpc3RlbmNlIFRUTDogJHtTdHJpbmcodmFsdWUpfWApO1xuICB9XG4gIHJldHVybiBtaWxsaXNlY29uZHM7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhbnVwRXhwaXJlZChcbiAgcXVlcnlhYmxlOiBQZ1F1ZXJ5YWJsZSxcbiAgb3B0aW9uczogUmVzb2x2ZWRUb3BpY0J1c1BlcnNpc3RlbmNlT3B0aW9ucyxcbiAgc2NvcGU6IFRvcGljUGVyc2lzdGVuY2VTY29wZSxcbiAgbGltaXQgPSBvcHRpb25zLmNsZWFudXBCYXRjaFNpemUsXG4pOiBQcm9taXNlPG51bWJlcj4ge1xuICBjb25zdCByZXN1bHQgPSBhd2FpdCBxdWVyeWFibGUucXVlcnkoXG4gICAgYFdJVEggZXhwaXJlZCBBUyAoU0VMRUNUIGN0aWQgRlJPTSAke3RhYmxlKG9wdGlvbnMsIHNjb3BlKX0gV0hFUkUgZXhwaXJlc19hdCBJUyBOT1QgTlVMTCBBTkQgZXhwaXJlc19hdCA8PSBjbG9ja190aW1lc3RhbXAoKSBPUkRFUiBCWSBleHBpcmVzX2F0IExJTUlUICQxKSBERUxFVEUgRlJPTSAke3RhYmxlKG9wdGlvbnMsIHNjb3BlKX0gQVMgbWVzc2FnZXMgVVNJTkcgZXhwaXJlZCBXSEVSRSBtZXNzYWdlcy5jdGlkID0gZXhwaXJlZC5jdGlkYCxcbiAgICBbbGltaXRdLFxuICApO1xuICByZXR1cm4gcmVzdWx0LnJvd0NvdW50ID8/IDA7XG59XG5cbnR5cGUgSGlzdG9yeVJvdyA9IFF1ZXJ5UmVzdWx0Um93ICYge1xuICBzZXF1ZW5jZTogc3RyaW5nO1xuICBleHBpcmVzX2F0OiBEYXRlIHwgc3RyaW5nIHwgbnVsbDtcbiAgZW52ZWxvcGU6IFRvcGljTWVzc2FnZTtcbn07XG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaGlzdG9yeTxUQm9keSBleHRlbmRzIG9iamVjdC5TZXJpYWxpemFibGVWYWx1ZT4oXG4gIHF1ZXJ5YWJsZTogUGdRdWVyeWFibGUsXG4gIGNoYW5uZWw6IHN0cmluZyxcbiAgdG9waWM6IHN0cmluZyxcbiAgb3B0aW9uczogUmVzb2x2ZWRUb3BpY0J1c1BlcnNpc3RlbmNlT3B0aW9ucyxcbiAgaW5wdXQ6IHsgYWZ0ZXI/OiBzdHJpbmc7IGxpbWl0PzogbnVtYmVyOyBzY29wZT86IFRvcGljUGVyc2lzdGVuY2VTY29wZSB9ID0ge30sXG4pOiBQcm9taXNlPFRvcGljSGlzdG9yeVBhZ2U8VEJvZHk+PiB7XG4gIGNvbnN0IHNjb3BlID0gaW5wdXQuc2NvcGUgPz8gb3B0aW9ucy5zY29wZTtcbiAgY29uc3QgbGltaXQgPSBpbnB1dC5saW1pdCA/PyAxMDA7XG4gIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHF1ZXJ5YWJsZS5xdWVyeTxIaXN0b3J5Um93PihcbiAgICBgU0VMRUNUIHNlcXVlbmNlLCBleHBpcmVzX2F0LCBlbnZlbG9wZSBGUk9NICR7dGFibGUob3B0aW9ucywgc2NvcGUpfSBXSEVSRSBjaGFubmVsID0gJDEgQU5EIHRvcGljID0gJDIgQU5EIHNlcXVlbmNlID4gJDM6OmJpZ2ludCBBTkQgKGV4cGlyZXNfYXQgSVMgTlVMTCBPUiBleHBpcmVzX2F0ID4gY2xvY2tfdGltZXN0YW1wKCkpIE9SREVSIEJZIHNlcXVlbmNlIExJTUlUICQ0YCxcbiAgICBbY2hhbm5lbCwgdG9waWMsIGFmdGVyKGlucHV0LmFmdGVyLCBzY29wZSksIGxpbWl0XSxcbiAgKTtcbiAgY29uc3QgbWVzc2FnZXMgPSByZXN1bHQucm93cy5tYXAoKHJvdykgPT4gKHtcbiAgICBjdXJzb3I6IGN1cnNvcihzY29wZSwgcm93LnNlcXVlbmNlKSxcbiAgICBleHBpcmVzQXQ6IHJvdy5leHBpcmVzX2F0ID09PSBudWxsID8gbnVsbCA6IG5ldyBEYXRlKHJvdy5leHBpcmVzX2F0KS50b0lTT1N0cmluZygpLFxuICAgIHNjb3BlLFxuICAgIG1lc3NhZ2U6IHJvdy5lbnZlbG9wZSBhcyBUb3BpY01lc3NhZ2U8VEJvZHk+LFxuICB9KSk7XG4gIHJldHVybiB7XG4gICAgbWVzc2FnZXMsXG4gICAgLi4uKG1lc3NhZ2VzLmxlbmd0aCA9PT0gbGltaXQgPyB7IG5leHRDdXJzb3I6IG1lc3NhZ2VzLmF0KC0xKSEuY3Vyc29yIH0gOiB7fSksXG4gIH07XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBwZXJzaXN0ZWROb3RpZnkoXG4gIGNsaWVudDogUGdRdWVyeWFibGUsXG4gIGNoYW5uZWw6IHN0cmluZyxcbiAgdG9waWM6IHN0cmluZyxcbiAgbWVzc2FnZTogVG9waWNNZXNzYWdlLFxuICBlbmNvZGVkOiBzdHJpbmcsXG4gIG9wdGlvbnM6IFJlc29sdmVkVG9waWNCdXNQZXJzaXN0ZW5jZU9wdGlvbnMsXG4gIHNjb3BlOiBUb3BpY1BlcnNpc3RlbmNlU2NvcGUsXG4gIHR0bDogRHVyYXRpb25JbnB1dCB8IGZhbHNlLFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGF3YWl0IGNsZWFudXBFeHBpcmVkKGNsaWVudCwgb3B0aW9ucywgc2NvcGUpO1xuICBjb25zdCBtaWxsaXNlY29uZHMgPSB0dGxNaWxsaXNlY29uZHModHRsKTtcbiAgY29uc3QgaW5zZXJ0ZWQgPSBhd2FpdCBjbGllbnQucXVlcnk8UXVlcnlSZXN1bHRSb3cgJiB7IHNlcXVlbmNlOiBzdHJpbmcgfT4oXG4gICAgYElOU0VSVCBJTlRPICR7dGFibGUob3B0aW9ucywgc2NvcGUpfSAoY2hhbm5lbCwgdG9waWMsIG1lc3NhZ2VfaWQsIHB1Ymxpc2hlZF9hdCwgZXhwaXJlc19hdCwgZW52ZWxvcGUpIFZBTFVFUyAoJDEsICQyLCAkMywgJDQsIENBU0UgV0hFTiAkNTo6YmlnaW50IElTIE5VTEwgVEhFTiBOVUxMIEVMU0UgY2xvY2tfdGltZXN0YW1wKCkgKyAoJDU6OmJpZ2ludCAqIGludGVydmFsICcxIG1pbGxpc2Vjb25kJykgRU5ELCAkNjo6anNvbmIpIFJFVFVSTklORyBzZXF1ZW5jZWAsXG4gICAgW2NoYW5uZWwsIHRvcGljLCBtZXNzYWdlLmlkLCBtZXNzYWdlLnB1Ymxpc2hlZEF0LCBtaWxsaXNlY29uZHMsIGVuY29kZWRdLFxuICApO1xuICAvLyBUaGUgcm93IGFuZCB0aGUgbm90aWZpY2F0aW9uIGNvbW1pdCB0b2dldGhlciwgc28gYSBwb2ludGVyIGlzIG5ldmVyIGRlbGl2ZXJlZFxuICAvLyBiZWZvcmUgdGhlIHJvdyBpdCBuYW1lcyBpcyByZWFkYWJsZSAtIGBOT1RJRllgIGlzIGRlbGl2ZXJlZCBhdCBDT01NSVQsIG5vdCBhdFxuICAvLyBzdGF0ZW1lbnQgdGltZS5cbiAgY29uc3QgcGF5bG9hZCA9XG4gICAgb3B0aW9ucy5wYXlsb2FkID09PSBcInBvaW50ZXJcIlxuICAgICAgPyBwb2ludGVyUGF5bG9hZChzY29wZSwgdG9waWMsIG1lc3NhZ2UuaWQsIGluc2VydGVkLnJvd3NbMF0/LnNlcXVlbmNlID8/IFwiMFwiKVxuICAgICAgOiBlbmNvZGVkO1xuICBhd2FpdCBjbGllbnQucXVlcnkoXCJTRUxFQ1QgcGdfbm90aWZ5KCQxLCAkMilcIiwgW2NoYW5uZWwsIHBheWxvYWRdKTtcbn1cblxuLyoqXG4gKiBUaGUgYHBheWxvYWQ6IFwicG9pbnRlclwiYCBub3RpZmljYXRpb24gYm9keTogcm91dGluZyBhbmQgaWRlbnRpdHkgb25seSwgc28gdGhlXG4gKiBzaXplIGxpbWl0IGRvZXMgbm90IGFwcGx5IGFuZCBhIGxpc3RlbmVyIHdpdGhvdXQgdGhlIHRhYmxlIGdyYW50IGxlYXJucyB0aGF0XG4gKiBzb21ldGhpbmcgaGFwcGVuZWQgd2l0aG91dCBsZWFybmluZyB3aGF0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gcG9pbnRlclBheWxvYWQoXG4gIHNjb3BlOiBUb3BpY1BlcnNpc3RlbmNlU2NvcGUsXG4gIHRvcGljOiBzdHJpbmcsXG4gIGlkOiBzdHJpbmcsXG4gIHNlcXVlbmNlOiBzdHJpbmcgfCBudW1iZXIsXG4pOiBzdHJpbmcge1xuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoeyB2OiBQT0lOVEVSX1ZFUlNJT04sIHNjb3BlLCB0b3BpYywgaWQsIHNlcXVlbmNlOiBTdHJpbmcoc2VxdWVuY2UpIH0pO1xufVxuXG4vKiogQSBkZWNvZGVkIHBvaW50ZXIgbm90aWZpY2F0aW9uLiAqL1xuZXhwb3J0IGludGVyZmFjZSBUb3BpY1BvaW50ZXIge1xuICBzY29wZTogVG9waWNQZXJzaXN0ZW5jZVNjb3BlO1xuICB0b3BpYzogc3RyaW5nO1xuICBpZDogc3RyaW5nO1xuICBzZXF1ZW5jZTogc3RyaW5nO1xufVxuXG4vKipcbiAqIFJlYWQgYSBub3RpZmljYXRpb24gYXMgYSBwb2ludGVyLCBvciBgdW5kZWZpbmVkYCB3aGVuIGl0IGlzIG5vdCBvbmUuIFRoZSBjaGFubmVsXG4gKiBpcyBzaGFyZWQsIHNvIGFuIHVucmVjb2duaXplZCBwYXlsb2FkIGlzIG9yZGluYXJ5IHRyYWZmaWMgcmF0aGVyIHRoYW4gYW4gZXJyb3IuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkZWNvZGVQb2ludGVyKHZhbHVlOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBUb3BpY1BvaW50ZXIgfCB1bmRlZmluZWQge1xuICBpZiAoIXZhbHVlKSByZXR1cm4gdW5kZWZpbmVkO1xuICBsZXQgcmVjb3JkOiB1bmtub3duO1xuICB0cnkge1xuICAgIHJlY29yZCA9IEpTT04ucGFyc2UodmFsdWUpO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIGlmICghcmVjb3JkIHx8IHR5cGVvZiByZWNvcmQgIT09IFwib2JqZWN0XCIgfHwgQXJyYXkuaXNBcnJheShyZWNvcmQpKSByZXR1cm4gdW5kZWZpbmVkO1xuICBjb25zdCBjYW5kaWRhdGUgPSByZWNvcmQgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIGlmIChjYW5kaWRhdGUudiAhPT0gUE9JTlRFUl9WRVJTSU9OKSByZXR1cm4gdW5kZWZpbmVkO1xuICBjb25zdCB7IHNjb3BlLCB0b3BpYywgaWQsIHNlcXVlbmNlIH0gPSBjYW5kaWRhdGU7XG4gIGlmIChzY29wZSAhPT0gXCJvcGVuXCIgJiYgc2NvcGUgIT09IFwicmVzdHJpY3RlZFwiKSByZXR1cm4gdW5kZWZpbmVkO1xuICBpZiAodHlwZW9mIHRvcGljICE9PSBcInN0cmluZ1wiIHx8IHR5cGVvZiBpZCAhPT0gXCJzdHJpbmdcIiB8fCB0eXBlb2Ygc2VxdWVuY2UgIT09IFwic3RyaW5nXCIpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIHJldHVybiB7IHNjb3BlLCB0b3BpYywgaWQsIHNlcXVlbmNlIH07XG59XG5cbi8qKlxuICogRmV0Y2ggdGhlIG9uZSBzdG9yZWQgZW52ZWxvcGUgYSBwb2ludGVyIG5hbWVzLiBSZXR1cm5zIGB1bmRlZmluZWRgIHdoZW4gdGhlIHJvd1xuICogaXMgZ29uZSAoVFRMIGNsZWFudXAgd29uIHRoZSByYWNlKSBvciB0aGUgcmVhZGVyIGxhY2tzIHRoZSB0YWJsZSdzIGdyYW50LCBib3RoXG4gKiBvZiB3aGljaCBhcmUgZXhwZWN0ZWQgb24gdGhlIGByZXN0cmljdGVkYCB0aWVyIHJhdGhlciB0aGFuIGVycm9ycy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRQb2ludGVyPFRCb2R5IGV4dGVuZHMgb2JqZWN0LlNlcmlhbGl6YWJsZVZhbHVlPihcbiAgcXVlcnlhYmxlOiBQZ1F1ZXJ5YWJsZSxcbiAgY2hhbm5lbDogc3RyaW5nLFxuICBwb2ludGVyOiBUb3BpY1BvaW50ZXIsXG4gIG9wdGlvbnM6IFJlc29sdmVkVG9waWNCdXNQZXJzaXN0ZW5jZU9wdGlvbnMsXG4pOiBQcm9taXNlPFRvcGljTWVzc2FnZTxUQm9keT4gfCB1bmRlZmluZWQ+IHtcbiAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcXVlcnlhYmxlLnF1ZXJ5PFF1ZXJ5UmVzdWx0Um93ICYgeyBlbnZlbG9wZTogVG9waWNNZXNzYWdlIH0+KFxuICAgIGBTRUxFQ1QgZW52ZWxvcGUgRlJPTSAke3RhYmxlKG9wdGlvbnMsIHBvaW50ZXIuc2NvcGUpfSBXSEVSRSBjaGFubmVsID0gJDEgQU5EIG1lc3NhZ2VfaWQgPSAkMiBBTkQgKGV4cGlyZXNfYXQgSVMgTlVMTCBPUiBleHBpcmVzX2F0ID4gY2xvY2tfdGltZXN0YW1wKCkpYCxcbiAgICBbY2hhbm5lbCwgcG9pbnRlci5pZF0sXG4gICk7XG4gIHJldHVybiByZXN1bHQucm93c1swXT8uZW52ZWxvcGUgYXMgVG9waWNNZXNzYWdlPFRCb2R5PiB8IHVuZGVmaW5lZDtcbn1cbiJdfQ==
|
package/lib/src/topic-bus.d.ts
CHANGED
|
@@ -285,6 +285,8 @@ export declare class PostgresTopicBus {
|
|
|
285
285
|
* stalling the notification connection.
|
|
286
286
|
*/
|
|
287
287
|
private readonly handleNotification;
|
|
288
|
+
/** Hand one decoded message to the topic's listeners. */
|
|
289
|
+
private deliver;
|
|
288
290
|
/**
|
|
289
291
|
* Handle the notification connection dying, which `pg` reports as an `error`
|
|
290
292
|
* event rather than a rejected query.
|
package/lib/src/topic-bus.js
CHANGED
|
@@ -25,7 +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
|
+
import { cleanupExpired, decodePointer, history, persistedNotify, provisionMessageBusSchema, readPointer, resolvePersistenceOptions, } from "./persistence.js";
|
|
29
29
|
/** Channel parts used when a caller names no channel of its own. */
|
|
30
30
|
const DEFAULT_CHANNEL = "dbx_tools_topic_bus";
|
|
31
31
|
/**
|
|
@@ -259,7 +259,9 @@ export class PostgresTopicBus {
|
|
|
259
259
|
this.channelName = channelName(options.channel === undefined ? DEFAULT_CHANNEL : options.channel);
|
|
260
260
|
this.metadata = options.metadata;
|
|
261
261
|
this.onError = options.onError ?? (() => undefined);
|
|
262
|
-
this.persistence = options.persist
|
|
262
|
+
this.persistence = options.persist
|
|
263
|
+
? resolvePersistenceOptions(options.persist === true ? true : options.persist)
|
|
264
|
+
: undefined;
|
|
263
265
|
}
|
|
264
266
|
/**
|
|
265
267
|
* Open the dedicated notification connection and `LISTEN`.
|
|
@@ -324,11 +326,16 @@ export class PostgresTopicBus {
|
|
|
324
326
|
if (!decode(encoded)) {
|
|
325
327
|
throw new TypeError("Message type, metadata, and body must be JSON serializable");
|
|
326
328
|
}
|
|
327
|
-
|
|
329
|
+
// Only the envelope payload is bounded by the `NOTIFY` limit. A pointer
|
|
330
|
+
// notification is a fixed handful of bytes, so persistence with
|
|
331
|
+
// `payload: "pointer"` lifts the cap entirely.
|
|
332
|
+
if (Buffer.byteLength(encoded, "utf8") > MAX_NOTIFY_BYTES &&
|
|
333
|
+
this.persistence?.payload !== "pointer") {
|
|
328
334
|
throw new RangeError(`Postgres notification exceeds ${MAX_NOTIFY_BYTES} bytes`);
|
|
329
335
|
}
|
|
330
|
-
if (!this.persistence)
|
|
336
|
+
if (!this.persistence) {
|
|
331
337
|
await this.pool.query("SELECT pg_notify($1, $2)", [this.channelName, encoded]);
|
|
338
|
+
}
|
|
332
339
|
else {
|
|
333
340
|
if (this.persistence.provision) {
|
|
334
341
|
this.provisioning ??= provisionMessageBusSchema(this.pool, this.persistence);
|
|
@@ -471,12 +478,32 @@ export class PostgresTopicBus {
|
|
|
471
478
|
if (notification.channel !== this.channelName)
|
|
472
479
|
return;
|
|
473
480
|
const message = decode(notification.payload);
|
|
474
|
-
if (
|
|
481
|
+
if (message) {
|
|
482
|
+
this.deliver(message);
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
// `payload: "pointer"` carries only routing and identity, so the envelope has
|
|
486
|
+
// to be read back before anything can be delivered. Only attempted when this
|
|
487
|
+
// bus is configured for persistence; otherwise the payload is foreign traffic
|
|
488
|
+
// on a shared channel and ignored as before.
|
|
489
|
+
const pointer = this.persistence ? decodePointer(notification.payload) : undefined;
|
|
490
|
+
if (!pointer)
|
|
475
491
|
return;
|
|
492
|
+
if (!this.listeners.has(pointer.topic))
|
|
493
|
+
return;
|
|
494
|
+
readPointer(this.pool, this.channelName, pointer, this.persistence)
|
|
495
|
+
.then((stored) => {
|
|
496
|
+
if (stored)
|
|
497
|
+
this.deliver(stored);
|
|
498
|
+
})
|
|
499
|
+
.catch(this.onError);
|
|
500
|
+
};
|
|
501
|
+
/** Hand one decoded message to the topic's listeners. */
|
|
502
|
+
deliver(message) {
|
|
476
503
|
for (const listener of this.listeners.get(message.topic) ?? []) {
|
|
477
504
|
Promise.resolve(listener(message)).catch(this.onError);
|
|
478
505
|
}
|
|
479
|
-
}
|
|
506
|
+
}
|
|
480
507
|
/**
|
|
481
508
|
* Handle the notification connection dying, which `pg` reports as an `error`
|
|
482
509
|
* event rather than a rejected query.
|
|
@@ -535,4 +562,4 @@ export class PostgresTopicBus {
|
|
|
535
562
|
}
|
|
536
563
|
}
|
|
537
564
|
}
|
|
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
|
|
565
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9waWMtYnVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3RvcGljLWJ1cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBd0JHO0FBRUgsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUNuQyxPQUFPLEVBQUUsS0FBSyxJQUFJLFNBQVMsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFJL0YsT0FBTyxFQUNMLGNBQWMsRUFDZCxhQUFhLEVBQ2IsT0FBTyxFQUNQLGVBQWUsRUFDZix5QkFBeUIsRUFDekIsV0FBVyxFQUNYLHlCQUF5QixHQU0xQixNQUFNLGtCQUFrQixDQUFDO0FBUTFCLG9FQUFvRTtBQUNwRSxNQUFNLGVBQWUsR0FBRyxxQkFBcUIsQ0FBQztBQUM5Qzs7OztHQUlHO0FBQ0gsTUFBTSxrQkFBa0IsR0FBRyxFQUFFLENBQUM7QUFDOUIscUZBQXFGO0FBQ3JGLE1BQU0sbUJBQW1CLEdBQUcsQ0FBQyxDQUFDO0FBQzlCLDBFQUEwRTtBQUMxRSxNQUFNLGdCQUFnQixHQUFHLEtBQUssQ0FBQztBQUMvQjs7OztHQUlHO0FBQ0gsTUFBTSxnQkFBZ0IsR0FBRyxLQUFLLENBQUM7QUFDL0IsTUFBTSxzQkFBc0IsR0FBRyxHQUFHLENBQUM7QUFDbkMsTUFBTSxzQkFBc0IsR0FBRyxLQUFLLENBQUM7QUFrQnJDOzs7O0dBSUc7QUFDSCxJQUFJLFlBQTJELENBQUM7QUFnSGhFOzs7O0dBSUc7QUFDSCxTQUFTLGVBQWUsQ0FBQyxNQUFxRDtJQUM1RSxPQUFPLE1BQU0sQ0FBQyxXQUFXLENBQ3ZCLE1BQU0sQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsS0FBSyxFQUF3QyxFQUFFO1FBQzVFLE9BQU8sS0FBSyxDQUFDLENBQUMsQ0FBQyxL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QUFDO1lBQ0gsQ0FBQztZQUNELElBQUksQ0FBQztnQkFDSCxNQUFNLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDbkIsT0FBTztZQUNULENBQUM7WUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO2dCQUNmLElBQUksSUFBSSxDQUFDLE1BQU07b0JBQUUsT0FBTztnQkFDeEIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDcEIsS0FBSyxHQUFHLEtBQUssS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLHNCQUFzQixDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssR0FBRyxDQUFDLEVBQUUsc0JBQXNCLENBQUMsQ0FBQztZQUM3RixDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVG9waWMgZmFuLW91dCBvdmVyIFBvc3RncmVTUUwgYExJU1RFTmAvYE5PVElGWWAsIGZvciB0ZWxsaW5nIGV2ZXJ5IHJ1bm5pbmdcbiAqIGluc3RhbmNlIG9mIGFuIGFwcCB0aGF0IHNvbWV0aGluZyBoYXBwZW5lZC5cbiAqXG4gKiBUaGUgc2libGluZyBgYWR2aXNvcnktbG9ja2AgbW9kdWxlIGlzIGFib3V0IG1ha2luZyBzdXJlIG9ubHkgT05FIGNvbm5lY3Rpb25cbiAqIGRvZXMgYSB0aGluZzsgdGhpcyBvbmUgaXMgdGhlIG9wcG9zaXRlIC0gRVZFUlkgbGlzdGVuaW5nIHNlc3Npb24gZ2V0cyBldmVyeVxuICogbm90aWZpY2F0aW9uLiBUaGF0IG1ha2VzIGl0IHRoZSByaWdodCBwcmltaXRpdmUgZm9yIGxpdmUgVUkgdXBkYXRlc1xuICogKGFuIFNTRSBzdHJlYW0gcGVyIGJyb3dzZXIgdGFiLCBhIGNhY2hlIGludmFsaWRhdGlvbiwgYSBwcmVzZW5jZSBwaW5nKSBhbmQgdGhlXG4gKiB3cm9uZyBvbmUgZm9yIHdvcmsgZGlzdHJpYnV0aW9uOiB0aGVyZSBhcmUgbm8gY29tcGV0aW5nIGNvbnN1bWVycywgbm8gYWNrcywgYW5kXG4gKiBubyByZXBsYXkuXG4gKlxuICogRGVsaXZlcnkgaXMgYmVzdC1lZmZvcnQgYW5kIGxpdmUuIGBOT1RJRllgIHJlYWNoZXMgc2Vzc2lvbnMgdGhhdCBhcmUgbGlzdGVuaW5nXG4gKiBhdCB0aGUgbW9tZW50IGl0IGNvbW1pdHMsIHNvIGEgbGlzdGVuZXIgdGhhdCBjb25uZWN0cyBhIHNlY29uZCBsYXRlciBuZXZlciBzZWVzXG4gKiBpdCwgYW5kIGEgbGlzdGVuZXIgd2hvc2UgY29ubmVjdGlvbiBkcm9wcyBtaXNzZXMgZXZlcnl0aGluZyB1bnRpbCB0aGUgYnVzXG4gKiByZWNvbm5lY3RzLiBVc2UgYSB0YWJsZSBvciBhIHF1ZXVlIHdoZW4gYSBzdWJzY3JpYmVyIG5lZWRzIGR1cmFiaWxpdHkuXG4gKlxuICogT05FIENIQU5ORUwsIE1BTlkgVE9QSUNTLiBFdmVyeSBidXMgaW5zdGFuY2UgbGlzdGVucyBvbiBhIHNpbmdsZSBQb3N0Z3Jlc1xuICogY2hhbm5lbCAoYGNoYW5uZWxgLCBkZWZhdWx0IGBkYnhfdG9vbHNfdG9waWNfYnVzYCkgYW5kIGZpbHRlcnMgYnkgdGhlXG4gKiBlbnZlbG9wZSdzIGB0b3BpY2AgaW4tcHJvY2Vzcywgc28gYWRkaW5nIGEgdG9waWMgY29zdHMgbm8gY29ubmVjdGlvbiBhbmQgbm9cbiAqIGBMSVNURU5gLiBUaGUgdHJhZGVvZmYgaXMgdGhhdCBldmVyeSBsaXN0ZW5pbmcgc2Vzc2lvbiBkZWNvZGVzIGV2ZXJ5IG1lc3NhZ2Ugb25cbiAqIHRoZSBjaGFubmVsOyBnaXZlIGEgZ2VudWluZWx5IGhpZ2gtdm9sdW1lLCB1bnJlbGF0ZWQgc3RyZWFtIGl0cyBvd24gYGNoYW5uZWxgXG4gKiByYXRoZXIgdGhhbiBhIHRvcGljLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBob3N0bmFtZSB9IGZyb20gXCJub2RlOm9zXCI7XG5pbXBvcnQgeyBhc3luYyBhcyBhc3luY1V0aWwsIGVycm9yLCBoYXNoLCBqc29uLCBvYmplY3QsIHN0cmluZyB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5pbXBvcnQgdHlwZSB7IE5vdGlmaWNhdGlvbiwgUG9vbENsaWVudCB9IGZyb20gXCJwZ1wiO1xuXG5pbXBvcnQgdHlwZSB7IFBnUG9vbExpa2UsIFBnUXVlcnlhYmxlIH0gZnJvbSBcIi4vYWR2aXNvcnktbG9jay50c1wiO1xuaW1wb3J0IHtcbiAgY2xlYW51cEV4cGlyZWQsXG4gIGRlY29kZVBvaW50ZXIsXG4gIGhpc3RvcnksXG4gIHBlcnNpc3RlZE5vdGlmeSxcbiAgcHJvdmlzaW9uTWVzc2FnZUJ1c1NjaGVtYSxcbiAgcmVhZFBvaW50ZXIsXG4gIHJlc29sdmVQZXJzaXN0ZW5jZU9wdGlvbnMsXG4gIHR5cGUgRHVyYXRpb25JbnB1dCxcbiAgdHlwZSBSZXNvbHZlZFRvcGljQnVzUGVyc2lzdGVuY2VPcHRpb25zLFxuICB0eXBlIFRvcGljQnVzUGVyc2lzdGVuY2VPcHRpb25zLFxuICB0eXBlIFRvcGljSGlzdG9yeVBhZ2UsXG4gIHR5cGUgVG9waWNQZXJzaXN0ZW5jZVNjb3BlLFxufSBmcm9tIFwiLi9wZXJzaXN0ZW5jZS50c1wiO1xuXG4vKipcbiAqIGBAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlYCBvd25zIHRoZSBKU09OLXJvdW5kLXRyaXAgcnVsZTsgdGhpcyBhbGlhcyBqdXN0IGtlZXBzIHRoZVxuICogZ2VuZXJpYyBzaWduYXR1cmVzIGJlbG93IHJlYWRhYmxlLiBDb25zdW1lcnMgaW1wb3J0IHRoZSB0eXBlIGZyb20gc2hhcmVkLWNvcmUuXG4gKi9cbnR5cGUgU2VyaWFsaXphYmxlVmFsdWUgPSBvYmplY3QuU2VyaWFsaXphYmxlVmFsdWU7XG5cbi8qKiBDaGFubmVsIHBhcnRzIHVzZWQgd2hlbiBhIGNhbGxlciBuYW1lcyBubyBjaGFubmVsIG9mIGl0cyBvd24uICovXG5jb25zdCBERUZBVUxUX0NIQU5ORUwgPSBcImRieF90b29sc190b3BpY19idXNcIjtcbi8qKlxuICogYE5BTUVEQVRBTEVOIC0gMWAuIFBvc3RncmVzIFRSVU5DQVRFUyBhIGxvbmdlciBjaGFubmVsIG5hbWUgcmF0aGVyIHRoYW5cbiAqIHJlamVjdGluZyBpdCwgd2hpY2ggd291bGQgc3BsaXQgcHVibGlzaGVycyBhbmQgbGlzdGVuZXJzIG9udG8gZGlmZmVyZW50XG4gKiBjaGFubmVscyB3aGlsZSBldmVyeSBjYWxsIGxvb2tlZCBsaWtlIGl0IHN1Y2NlZWRlZC5cbiAqL1xuY29uc3QgTUFYX0NIQU5ORUxfTEVOR1RIID0gNjM7XG4vKiogQmFzZS0zMiBjaGFycyBvZiB0aGUgY2hhbm5lbCdzIGlkZW50aXR5IHN1ZmZpeC4gTWF4IDcgLSB0aGUgZGlnZXN0IGlzIDMyIGJpdHMuICovXG5jb25zdCBDSEFOTkVMX0hBU0hfTEVOR1RIID0gNjtcbi8qKiBCb2R5IHVzZWQgd2hlbiB0aGUgcGFydHMgdG9rZW5pemUgdG8gbm90aGluZywgb3IgbGVhZCB3aXRoIGEgZGlnaXQuICovXG5jb25zdCBDSEFOTkVMX0ZBTExCQUNLID0gXCJidXNcIjtcbi8qKlxuICogRW5jb2RlZC1lbnZlbG9wZSBjZWlsaW5nLiBQb3N0Z3JlU1FMIGNhcHMgYSBgTk9USUZZYCBwYXlsb2FkIGF0IDgwMDAgYnl0ZXMgYW5kXG4gKiBmYWlscyB0aGUgc3RhdGVtZW50IHBhc3QgdGhhdCwgc28gdGhlIGJ1cyByZWplY3RzIHRoZSBtZXNzYWdlIGZpcnN0IHdpdGggYSBzaXplXG4gKiBpdCBjYW4gbmFtZS4gVGhlIG1hcmdpbiBiZWxvdyA4MDAwIGNvdmVycyB0aGUgc2VydmVyJ3Mgb3duIGFjY291bnRpbmcuXG4gKi9cbmNvbnN0IE1BWF9OT1RJRllfQllURVMgPSA3XzkwMDtcbmNvbnN0IE1JTl9SRUNPTk5FQ1RfREVMQVlfTVMgPSAyNTA7XG5jb25zdCBNQVhfUkVDT05ORUNUX0RFTEFZX01TID0gNV8wMDA7XG5cbi8qKlxuICogVGhlIHN1YnNldCBvZiBBcHBLaXQncyBwZXItcmVxdWVzdCBleGVjdXRpb24gY29udGV4dCB0aGUgYnVzIHJlYWRzIGZvciBzZW5kZXJcbiAqIGlkZW50aXR5LiBGaWVsZHMgYXJlIGB1bmtub3duYCBiZWNhdXNlIHRoaXMgaXMgYSBzdHJ1Y3R1cmFsIHZpZXcgb2YgYW4gT1BUSU9OQUxcbiAqIHBlZXI6IHRoZSB2YWx1ZXMgYXJlIHRyaW1tZWQgYW5kIHZhbGlkYXRlZCByYXRoZXIgdGhhbiB0cnVzdGVkLlxuICovXG50eXBlIEFwcEtpdEV4ZWN1dGlvbkNvbnRleHQgPSB7XG4gIHVzZXJFbWFpbD86IHVua25vd247XG4gIHVzZXJJZD86IHVua25vd247XG4gIHVzZXJOYW1lPzogdW5rbm93bjtcbn07XG5cbi8qKiBTdHJ1Y3R1cmFsIHZpZXcgb2YgYEBkYXRhYnJpY2tzL2FwcGtpdGAsIGltcG9ydGVkIGxhemlseSBhbmQgbmV2ZXIgcmVxdWlyZWQuICovXG50eXBlIEFwcEtpdE1vZHVsZSA9IHtcbiAgZ2V0RXhlY3V0aW9uQ29udGV4dCgpOiBBcHBLaXRFeGVjdXRpb25Db250ZXh0O1xufTtcblxuLyoqXG4gKiBDYWNoZWQgcmVzdWx0IG9mIHRoZSBvbmUgb3B0aW9uYWwtcGVlciBpbXBvcnQsIHJlc29sdmVkIHRvIGB1bmRlZmluZWRgIHdoZW5cbiAqIEFwcEtpdCBpcyBub3QgaW5zdGFsbGVkLiBNZW1vaXplZCBzbyBhIGJ1cyBpbiBhIHBsYWluIFBvc3RncmVzIHByb2Nlc3MgcGF5cyBmb3JcbiAqIHRoZSBmYWlsZWQgcmVzb2x1dGlvbiBvbmNlIGluc3RlYWQgb2YgcGVyIGJyb2FkY2FzdC5cbiAqL1xubGV0IGFwcEtpdE1vZHVsZTogUHJvbWlzZTxBcHBLaXRNb2R1bGUgfCB1bmRlZmluZWQ+IHwgdW5kZWZpbmVkO1xuXG4vKipcbiAqIEZsYXQta2V5ZWQgY29udGV4dCB0cmF2ZWxsaW5nIGFsb25nc2lkZSBhIG1lc3NhZ2UgYm9keTogd2hvIHNlbnQgaXQsIGZyb21cbiAqIHdoZXJlLCBpbiB3aGljaCBkZXBsb3ltZW50LiBWYWx1ZXMgbWF5IG5lc3QsIGJ1dCB0aGUga2V5cyBhcmUgdGhlIGFkZHJlc3NhYmxlXG4gKiBwYXJ0IC0gYSBsaXN0ZW5lciBmaWx0ZXJpbmcgb3IgbGFiZWxsaW5nIG1lc3NhZ2VzIHJlYWRzIGBtZXRhZGF0YS51c2VyYCwgbm90IGFcbiAqIHBhdGggaW50byB0aGUgYm9keS5cbiAqL1xuZXhwb3J0IHR5cGUgVG9waWNNZXRhZGF0YSA9IFJlY29yZDxzdHJpbmcsIFNlcmlhbGl6YWJsZVZhbHVlPjtcblxuLyoqXG4gKiBUaGUgd2lyZSBlbnZlbG9wZSBldmVyeSBzdWJzY3JpYmVyIHJlY2VpdmVzLCBhbmQgd2hhdCB7QGxpbmtcbiAqIFBvc3RncmVzVG9waWNCdXMuYnJvYWRjYXN0fSByZXR1cm5zIHRvIHRoZSBwdWJsaXNoZXIuXG4gKlxuICogYGlkYCwgYHRvcGljYCwgYW5kIGBwdWJsaXNoZWRBdGAgYXJlIGFzc2lnbmVkIGJ5IHRoZSBidXM7IGB0eXBlYCwgYG1ldGFkYXRhYCxcbiAqIGFuZCBgYm9keWAgY29tZSBmcm9tIHRoZSBjYWxsZXIgKHdpdGggYXV0b21hdGljIGNvbnRleHQgbWVyZ2VkIHVuZGVyXG4gKiBgbWV0YWRhdGFgKS4gVGhlIHNoYXBlIGlzIHN0YWJsZSBlbm91Z2ggdG8gaGFuZCBzdHJhaWdodCB0byBhbiBTU0UgYGRhdGE6YFxuICogZnJhbWUuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVG9waWNNZXNzYWdlPFRCb2R5IGV4dGVuZHMgU2VyaWFsaXphYmxlVmFsdWUgPSBTZXJpYWxpemFibGVWYWx1ZT4ge1xuICAvKipcbiAgICogUGVyLW1lc3NhZ2UgaWRlbnRpdHkgZ2VuZXJhdGVkIGJ5IHRoZSBwdWJsaXNoZXIsIHVuaXF1ZSBhY3Jvc3MgaW5zdGFuY2VzLlxuICAgKiBTdWl0YWJsZSBmb3IgZGVkdXBlIHdoZW4gYSBjbGllbnQgcmVjb25uZWN0cyBhbmQgZm9yIGFuIFNTRSBgaWQ6YCBmaWVsZC4gTm90XG4gICAqIG9yZGVyZWQsIGFuZCBub3QgYSBkYXRhYmFzZSBrZXkuXG4gICAqL1xuICBpZDogc3RyaW5nO1xuICAvKiogVGhlIHRvcGljIHRoaXMgd2FzIGJyb2FkY2FzdCBvbjsgbGlzdGVuZXJzIG9uIG90aGVyIHRvcGljcyBuZXZlciBzZWUgaXQuICovXG4gIHRvcGljOiBzdHJpbmc7XG4gIC8qKiBDYWxsZXItY2hvc2VuIGV2ZW50IG5hbWUsIGUuZy4gYG9yZGVyLnVwZGF0ZWRgLiBOZXZlciBlbXB0eS4gKi9cbiAgdHlwZTogc3RyaW5nO1xuICAvKiogQXV0b21hdGljIGNvbnRleHQgbWVyZ2VkIHdpdGggY2FsbGVyIG1ldGFkYXRhLiBTZWUge0BsaW5rIFRvcGljTWV0YWRhdGF9LiAqL1xuICBtZXRhZGF0YTogVG9waWNNZXRhZGF0YTtcbiAgLyoqIFRoZSBjYWxsZXIncyBwYXlsb2FkLCB1bmNoYW5nZWQuICovXG4gIGJvZHk6IFRCb2R5O1xuICAvKipcbiAgICogSVNPLTg2MDEgcHVibGlzaCB0aW1lIGZyb20gdGhlIFBVQkxJU0hJTkcgcHJvY2VzcydzIGNsb2NrLCBub3QgdGhlIGRhdGFiYXNlJ3MuXG4gICAqIEZpbmUgZm9yIGRpc3BsYXk7IGRvIG5vdCBvcmRlciBtZXNzYWdlcyBmcm9tIGRpZmZlcmVudCBpbnN0YW5jZXMgYnkgaXQuXG4gICAqL1xuICBwdWJsaXNoZWRBdDogc3RyaW5nO1xufVxuXG4vKiogV2hhdCBhIGNhbGxlciBzdXBwbGllcyB0byB7QGxpbmsgUG9zdGdyZXNUb3BpY0J1cy5icm9hZGNhc3R9LiAqL1xuZXhwb3J0IGludGVyZmFjZSBUb3BpY1B1Ymxpc2hJbnB1dDxUQm9keSBleHRlbmRzIFNlcmlhbGl6YWJsZVZhbHVlID0gU2VyaWFsaXphYmxlVmFsdWU+IHtcbiAgLyoqIEV2ZW50IG5hbWUsIGUuZy4gYGNoYXQubWVzc2FnZWAuIE11c3QgYmUgbm9uLWJsYW5rLiAqL1xuICB0eXBlOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBDb250ZXh0IHRvIGF0dGFjaC4gV2lucyBvdmVyIGFueSBhdXRvbWF0aWMga2V5IG9mIHRoZSBzYW1lIG5hbWUsIHNvIGEgY2FsbGVyXG4gICAqIGNhbiBvdmVycmlkZSBhIG1hY2hpbmUgZGVmYXVsdCAoYHByb2plY3RgKSBvciBhZGQgaXRzIG93biAoYHRyYWNlSWRgKS5cbiAgICovXG4gIG1ldGFkYXRhPzogVG9waWNNZXRhZGF0YTtcbiAgLyoqIFRoZSBwYXlsb2FkLiBNdXN0IHNhdGlzZnkgYG9iamVjdC5pc1NlcmlhbGl6YWJsZVZhbHVlYC4gKi9cbiAgYm9keTogVEJvZHk7XG4gIHNjb3BlPzogVG9waWNQZXJzaXN0ZW5jZVNjb3BlO1xuICB0dGw/OiBEdXJhdGlvbklucHV0IHwgZmFsc2U7XG59XG5cbi8qKlxuICogU3Vic2NyaWJlciBjYWxsYmFjay4gSW52b2tlZCBvbmNlIHBlciBtYXRjaGluZyBtZXNzYWdlIG9uIHRoZSBub3RpZmljYXRpb25cbiAqIGNvbm5lY3Rpb24ncyBjYWxsYmFjaywgc28gaXQgc2hvdWxkIG5vdCBibG9jazogYSByZXR1cm5lZCBwcm9taXNlIGlzIGF3YWl0ZWRcbiAqIG9ubHkgdG8gcm91dGUgYSByZWplY3Rpb24gdG8gYG9uRXJyb3JgLCBhbmQgbGlzdGVuZXJzIGZvciBvbmUgbWVzc2FnZSBydW5cbiAqIGNvbmN1cnJlbnRseSByYXRoZXIgdGhhbiBpbiByZWdpc3RyYXRpb24gb3JkZXIuXG4gKlxuICogYFRCb2R5YCBpcyB1bmNoZWNrZWQgYXQgcnVudGltZS4gVGhlIGJ1cyBndWFyYW50ZWVzIHRoZSBib2R5IGlzIHNlcmlhbGl6YWJsZSxcbiAqIG5vdCB0aGF0IGl0IG1hdGNoZXMgdGhlIHR5cGUgcGFyYW1ldGVyLCBzbyB2YWxpZGF0ZSBhbnl0aGluZyBhIGxpc3RlbmVyXG4gKiBicmFuY2hlcyBvbi5cbiAqL1xuZXhwb3J0IHR5cGUgVG9waWNMaXN0ZW5lcjxUQm9keSBleHRlbmRzIFNlcmlhbGl6YWJsZVZhbHVlID0gU2VyaWFsaXphYmxlVmFsdWU+ID0gKFxuICBtZXNzYWdlOiBUb3BpY01lc3NhZ2U8VEJvZHk+LFxuKSA9PiB2b2lkIHwgUHJvbWlzZUxpa2U8dm9pZD47XG5cbi8qKlxuICogUmVzb2x2ZXMgbWV0YWRhdGEgYXQgcHVibGlzaCB0aW1lIGluc3RlYWQgb2YgY29uc3RydWN0aW9uIHRpbWUsIGZvciBjb250ZXh0IGFcbiAqIHByb2Nlc3MgbGVhcm5zIGxhdGUgb3IgYXN5bmNocm9ub3VzbHkgLSBhbiBpbnN0YW5jZSBpZCBmcm9tIGEgY29udHJvbCBwbGFuZSwgYVxuICogZGlzY292ZXJlZCBhZGRyZXNzIGEgY2FsbGVyIGNob29zZXMgdG8gYXR0YWNoLiBDYWxsZWQgb24gZXZlcnkgYnJvYWRjYXN0LCBzb1xuICogbWVtb2l6ZSBhbnl0aGluZyBleHBlbnNpdmU7IGEgcmVqZWN0aW9uIGZhaWxzIHRoZSBicm9hZGNhc3QuXG4gKi9cbmV4cG9ydCB0eXBlIFRvcGljTWV0YWRhdGFQcm92aWRlciA9ICgpID0+IFRvcGljTWV0YWRhdGEgfCBQcm9taXNlTGlrZTxUb3BpY01ldGFkYXRhPjtcblxuLyoqIENvbnN0cnVjdGlvbiBvcHRpb25zIGZvciB7QGxpbmsgUG9zdGdyZXNUb3BpY0J1c30uICovXG5leHBvcnQgaW50ZXJmYWNlIFBvc3RncmVzVG9waWNCdXNPcHRpb25zIHtcbiAgLyoqXG4gICAqIFdoYXQgaWRlbnRpZmllcyB0aGlzIGNoYW5uZWwgLSBhbnl0aGluZywgbm90IGp1c3QgYW4gaWRlbnRpZmllcjogYSBuYW1lLCBhblxuICAgKiBpZCwgYSBgW2VudiwgZmVhdHVyZV1gIHBhaXIsIGEgY29uZmlnIG9iamVjdC4gVGhlIHBhcnRzIGFyZSB0b2tlbml6ZWQgaW50byBhXG4gICAqIGxlZ2FsIFBvc3RncmVzIGNoYW5uZWwgbmFtZSB3aXRoIGEgc2hvcnQgaGFzaCBvZiB0aGUgb3JpZ2luYWxzIGFwcGVuZGVkLCBzb1xuICAgKiB0aGUgZGVyaXZhdGlvbiBpcyBkZXRlcm1pbmlzdGljIGFuZCBubyBjYWxsIHNpdGUgaGFzIHRvIHNhbml0aXplLiBTZWVcbiAgICoge0BsaW5rIFBvc3RncmVzVG9waWNCdXMuY2hhbm5lbE5hbWV9IGZvciB0aGUgcmVzb2x2ZWQgbmFtZS5cbiAgICpcbiAgICogT25lIHZhbHVlIG9yIG1hbnk6IGFuIGFycmF5IGlzIHJlYWQgYXMgbXVsdGlwbGUgcGFydHNcbiAgICogKHtAbGluayBvYmplY3QuT25lT3JNYW55fSksIGFueXRoaW5nIGVsc2UgYXMgYSBzaW5nbGUgcGFydC4gU29cbiAgICogYFtcImJpbGxpbmdcIiwgXCJwcm9kXCJdYCBhbmQgYFwiYmlsbGluZ19wcm9kXCJgIGFyZSBkaWZmZXJlbnQgY2hhbm5lbHMsIHNpbmNlIHRoZVxuICAgKiBoYXNoIHNlZXMgZGlmZmVyZW50IHN0cnVjdHVyZS5cbiAgICpcbiAgICogRXZlcnkgcGFydGljaXBhdGluZyBwcm9jZXNzIG11c3QgcGFzcyBFUVVJVkFMRU5UIHBhcnRzLCBzaW5jZSBhIGRpZmZlcmVudFxuICAgKiBzcGVsbGluZyBoYXNoZXMgdG8gYSBkaWZmZXJlbnQgY2hhbm5lbC4gRGVmYXVsdHMgdG8gYSBzaGFyZWRcbiAgICogYGRieF90b29sc190b3BpY19idXNgIGNoYW5uZWwuXG4gICAqL1xuICBjaGFubmVsPzogdW5rbm93bjtcbiAgLyoqXG4gICAqIEV4dHJhIGNvbnRleHQgYWRkZWQgdG8gZXZlcnkgbWVzc2FnZSB0aGlzIGJ1cyBwdWJsaXNoZXMsIGVpdGhlciBhIGZpeGVkXG4gICAqIHJlY29yZCBvciBhIHtAbGluayBUb3BpY01ldGFkYXRhUHJvdmlkZXJ9IGNhbGxlZCBwZXIgYnJvYWRjYXN0LiBPdmVycmlkZXNcbiAgICogYXV0b21hdGljIG1hY2hpbmUga2V5czsgcGVyLWNhbGwgYG1ldGFkYXRhYCBvdmVycmlkZXMgdGhpcy5cbiAgICovXG4gIG1ldGFkYXRhPzogVG9waWNNZXRhZGF0YSB8IFRvcGljTWV0YWRhdGFQcm92aWRlcjtcbiAgLyoqXG4gICAqIFNpbmsgZm9yIGZhaWx1cmVzIHRoYXQgaGF2ZSBubyBjYWxsZXIgdG8gdGhyb3cgdG86IGEgbGlzdGVuZXIgdGhhdCByZWplY3RlZCxcbiAgICogYSBkcm9wcGVkIG5vdGlmaWNhdGlvbiBjb25uZWN0aW9uLCBhIGZhaWxlZCByZWNvbm5lY3QgYXR0ZW1wdC4gRGVmYXVsdHMgdG9cbiAgICogc3dhbGxvd2luZyB0aGVtLCBzbyB3aXJlIHRoaXMgdG8gYSBsb2dnZXIgaW4gYW55dGhpbmcgbG9uZy1ydW5uaW5nLlxuICAgKi9cbiAgb25FcnJvcj86IChjYXVzZTogdW5rbm93bikgPT4gdm9pZDtcbiAgcGVyc2lzdD86IGJvb2xlYW4gfCBUb3BpY0J1c1BlcnNpc3RlbmNlT3B0aW9ucztcbn1cblxuLyoqXG4gKiBEcm9wIGtleXMgd2hvc2UgdmFsdWUgaXMgYHVuZGVmaW5lZGAsIHNvIGFuIHVuc2V0IGVudmlyb25tZW50IHZhcmlhYmxlIGxlYXZlc1xuICogdGhlIGtleSBBQlNFTlQgcmF0aGVyIHRoYW4gcHJlc2VudC1hbmQtbnVsbC4gQWJzZW5jZSBpcyB3aGF0IGxldHMgY2FsbGVyXG4gKiBtZXRhZGF0YSBhbmQgbGF0ZXIgbWVyZ2UgbGF5ZXJzIHN1cHBseSB0aGUga2V5IGluc3RlYWQuXG4gKi9cbmZ1bmN0aW9uIGRlZmluZWRNZXRhZGF0YSh2YWx1ZXM6IFJlY29yZDxzdHJpbmcsIFNlcmlhbGl6YWJsZVZhbHVlIHwgdW5kZWZpbmVkPik6IFRvcGljTWV0YWRhdGEge1xuICByZXR1cm4gT2JqZWN0LmZyb21FbnRyaWVzKFxuICAgIE9iamVjdC5lbnRyaWVzKHZhbHVlcykuZmlsdGVyKChlbnRyeSk6IGVudHJ5IGlzIFtzdHJpbmcsIFNlcmlhbGl6YWJsZVZhbHVlXSA9PiB7XG4gICAgICByZXR1cm4gZW50cnlbMV0gIT09IHVuZGVmaW5lZDtcbiAgICB9KSxcbiAgKTtcbn1cblxuLyoqXG4gKiBDb250ZXh0IGV2ZXJ5IG1lc3NhZ2UgZ2V0cyBmb3IgZnJlZTogd2hpY2ggcHJvamVjdCwgaG9zdCwgYW5kIGRlcGxveW1lbnRcbiAqIHB1Ymxpc2hlZCBpdC5cbiAqXG4gKiBSZWFkIGZyZXNoIHBlciBicm9hZGNhc3QgcmF0aGVyIHRoYW4gY2FjaGVkLCBiZWNhdXNlIGEgbG9uZy1saXZlZCBwcm9jZXNzIGNhblxuICogYmUgcmUtcGFyZW50ZWQgKGEgZGVwbG95bWVudCBpZCBhcHBlYXJpbmcgYWZ0ZXIgYm9vdCkuIEtleXMgdGhhdCByZXNvbHZlIHRvXG4gKiBub3RoaW5nIGFyZSBvbWl0dGVkLlxuICpcbiAqIERlbGliZXJhdGVseSBOT1QgaW5jbHVkZWQ6IHB1YmxpYy9jbGllbnQgSVAsIHByb2Nlc3MgaWQsIENQVSBhcmNoaXRlY3R1cmUsXG4gKiBydW50aW1lIG5hbWUsIGFuZCBydW50aW1lIHZlcnNpb24uIElQcyBhbmQgcGlkcyBhcmUgbm9pc3ksIG9mdGVuIHNlbnNpdGl2ZSxcbiAqIGFuZCBidXJuIGBOT1RJRllgIHBheWxvYWQgYnVkZ2V0OyBhcmNoaXRlY3R1cmUvcnVudGltZSBhcmUgY29uc3RhbnQgcGVyXG4gKiBkZXBsb3ltZW50IGFuZCBwYXkgdGhlIHNhbWUgY29zdC4gQSBwcm9jZXNzIHRoYXQgd2FudHMgYW55IG9mIHRoZW0gcGFzc2VzIGFcbiAqIHtAbGluayBUb3BpY01ldGFkYXRhUHJvdmlkZXJ9IG9yIHBlci1tZXNzYWdlIGBtZXRhZGF0YWAuXG4gKi9cbmZ1bmN0aW9uIG1hY2hpbmVNZXRhZGF0YSgpOiBUb3BpY01ldGFkYXRhIHtcbiAgcmV0dXJuIGRlZmluZWRNZXRhZGF0YSh7XG4gICAgcHJvamVjdDpcbiAgICAgIHN0cmluZy5maXJzdE5vbkVtcHR5KFtcbiAgICAgICAgcHJvY2Vzcy5lbnYuREFUQUJSSUNLU19BUFBfTkFNRSxcbiAgICAgICAgcHJvY2Vzcy5lbnYuREFUQUJSSUNLU19CVU5ETEVfTkFNRSxcbiAgICAgICAgcHJvY2Vzcy5lbnYuUFJPSkVDVF9OQU1FLFxuICAgICAgICBwcm9jZXNzLmVudi5ucG1fcGFja2FnZV9uYW1lLFxuICAgICAgXSkgPz8gdW5kZWZpbmVkLFxuICAgIGhvc3RuYW1lOiBob3N0bmFtZSgpLFxuICAgIHBsYXRmb3JtOiBwcm9jZXNzLnBsYXRmb3JtLFxuICAgIGVudmlyb25tZW50OiBzdHJpbmcudHJpbVRvTnVsbChwcm9jZXNzLmVudi5OT0RFX0VOVikgPz8gdW5kZWZpbmVkLFxuICAgIGFwcE5hbWU6IHN0cmluZy50cmltVG9OdWxsKHByb2Nlc3MuZW52LkRBVEFCUklDS1NfQVBQX05BTUUpID8/IHVuZGVmaW5lZCxcbiAgICBkZXBsb3ltZW50SWQ6IHN0cmluZy50cmltVG9OdWxsKHByb2Nlc3MuZW52LkRBVEFCUklDS1NfQVBQX0RFUExPWU1FTlRfSUQpID8/IHVuZGVmaW5lZCxcbiAgICBkYXRhYnJpY2tzSG9zdDogc3RyaW5nLnRyaW1Ub051bGwocHJvY2Vzcy5lbnYuREFUQUJSSUNLU19IT1NUKSA/PyB1bmRlZmluZWQsXG4gIH0pO1xufVxuXG4vKipcbiAqIElkZW50aXR5IG9mIHRoZSBzaWduZWQtaW4gdXNlciBvbiB3aG9zZSBiZWhhbGYgdGhpcyBicm9hZGNhc3QgaGFwcGVucywgd2hlbiB0aGVcbiAqIHByb2Nlc3MgY2FuIHRlbGwuXG4gKlxuICogYEBkYXRhYnJpY2tzL2FwcGtpdGAgaXMgYW4gT1BUSU9OQUwgcGVlciwgc28gdGhlIGltcG9ydCBpcyBsYXp5IGFuZCBhIG1pc3NpbmdcbiAqIG1vZHVsZSBpcyBub3QgYW4gZXJyb3IgLSB0aGlzIGlzIGEgcGxhaW4gUG9zdGdyZXMgcGFja2FnZSB0aGF0IGFkZHMgc2VuZGVyXG4gKiBpZGVudGl0eSB3aGVuIGl0IGhhcHBlbnMgdG8gcnVuIGluc2lkZSBhbiBBcHBLaXQgYXBwLiBPdXRzaWRlIGFuIGFjdGl2ZVxuICogcGVyLXJlcXVlc3QgZXhlY3V0aW9uIGNvbnRleHQgQXBwS2l0IHRocm93cywgd2hpY2ggbWVhbnMgXCJubyB1c2VyIGhlcmVcIiwgc28gdGhlXG4gKiByZXN1bHQgaXMgZW1wdHkgbWV0YWRhdGEgcmF0aGVyIHRoYW4gYSBmYWlsZWQgYnJvYWRjYXN0LlxuICovXG5hc3luYyBmdW5jdGlvbiBzZW5kZXJNZXRhZGF0YSgpOiBQcm9taXNlPFRvcGljTWV0YWRhdGE+IHtcbiAgYXBwS2l0TW9kdWxlID8/PSBpbXBvcnQoXCJAZGF0YWJyaWNrcy9hcHBraXRcIilcbiAgICAudGhlbigobW9kdWxlKSA9PiBtb2R1bGUgYXMgQXBwS2l0TW9kdWxlKVxuICAgIC5jYXRjaCgoKSA9PiB1bmRlZmluZWQpO1xuICBjb25zdCBhcHBraXQgPSBhd2FpdCBhcHBLaXRNb2R1bGU7XG4gIGlmICghYXBwa2l0KSByZXR1cm4ge307XG4gIHRyeSB7XG4gICAgY29uc3QgY29udGV4dCA9IGFwcGtpdC5nZXRFeGVjdXRpb25Db250ZXh0KCk7XG4gICAgcmV0dXJuIGRlZmluZWRNZXRhZGF0YSh7XG4gICAgICBzZW5kZXJJZDogc3RyaW5nLnRyaW1Ub051bGwoY29udGV4dC51c2VySWQpID8/IHVuZGVmaW5lZCxcbiAgICAgIHNlbmRlck5hbWU6IHN0cmluZy50cmltVG9OdWxsKGNvbnRleHQudXNlck5hbWUpID8/IHVuZGVmaW5lZCxcbiAgICAgIHNlbmRlckVtYWlsOiBzdHJpbmcudHJpbVRvTnVsbChjb250ZXh0LnVzZXJFbWFpbCkgPz8gdW5kZWZpbmVkLFxuICAgIH0pO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4ge307XG4gIH1cbn1cblxuLyoqXG4gKiBEZXJpdmUgYSBsZWdhbCBQb3N0Z3JlcyBjaGFubmVsIG5hbWUgZnJvbSB3aGF0ZXZlciBhIGNhbGxlciB1c2VkIHRvIGlkZW50aWZ5XG4gKiB0aGUgY2hhbm5lbC5cbiAqXG4gKiBDYWxsZXJzIHRoaW5rIGluIHRlcm1zIG9mIHdoYXQgdGhlIGNoYW5uZWwgSVMgLSBhbiBhcHAgbmFtZSwgYSB0ZW5hbnQgaWQsIGFcbiAqIGBbZW52LCBmZWF0dXJlXWAgcGFpciwgYSBjb25maWcgb2JqZWN0IC0gYW5kIG5vbmUgb2YgdGhvc2UgYXJlIGlkZW50aWZpZXJzLlxuICogUmVqZWN0aW5nIHRoZW0gcHVzaGVkIHRoZSBzYW5pdGl6aW5nIG9udG8gZXZlcnkgY2FsbCBzaXRlLCB3aGljaCBpcyBob3cgdHdvXG4gKiBzZXJ2aWNlcyBlbmQgdXAgZGlzYWdyZWVpbmcgYWJvdXQgd2hldGhlciB0aGUgY2hhbm5lbCBpcyBgbXktYXBwYCwgYG15X2FwcGAsXG4gKiBvciBgbXlBcHBgIGFuZCBzaWxlbnRseSBuZXZlciBoZWFyIGVhY2ggb3RoZXIuXG4gKlxuICogVGhlIHBhcnRzIGFyZSB0b2tlbml6ZWQgYW5kIGpvaW5lZCBpbnRvIGFuIGlkZW50aWZpZXIsIHRoZW4gYSBzaG9ydCBoYXNoIG9mIHRoZVxuICogT1JJR0lOQUwgcGFydHMgaXMgYXBwZW5kZWQuIFRoZSBoYXNoIGlzIHdoYXQgbWFrZXMgdGhlIG1hcHBpbmcgdHJ1c3R3b3J0aHk6XG4gKiB0b2tlbml6aW5nIGFsb25lIGlzIGxvc3N5LCBzbyBgbXktYXBwYCBhbmQgYG15X2FwcGAgYW5kIGBteUFwcGAgd291bGQgY29sbGFwc2VcbiAqIG9udG8gb25lIGNoYW5uZWwsIGFuZCBhIG5hbWUgbG9uZyBlbm91Z2ggdG8gaGl0IGBOQU1FREFUQUxFTmAgd291bGQgY29sbGlkZVxuICogd2l0aCBhbnl0aGluZyBzaGFyaW5nIGl0cyBsZWFkaW5nIHRva2Vucy4gV2l0aCB0aGUgc3VmZml4LCB0aGUgcmVhZGFibGUgcGFydFxuICogc3RheXMgcmVhZGFibGUgYW5kIGRpc3RpbmN0IGlucHV0cyBzdGF5IGRpc3RpbmN0LlxuICpcbiAqIERldGVybWluaXN0aWMgYWNyb3NzIHByb2Nlc3NlcyBhbmQgcnVucywgd2hpY2ggaXMgdGhlIHdob2xlIHBvaW50IC0gdHdvXG4gKiBzZXJ2aWNlcyBnaXZlbiB0aGUgc2FtZSBwYXJ0cyBtdXN0IGxhbmQgb24gdGhlIHNhbWUgY2hhbm5lbCB3aXRob3V0XG4gKiBjb29yZGluYXRpbmcuIEhhc2ggaW5wdXRzIGFyZSBzdHJ1Y3R1cmUtYXdhcmUsIHNvIGBbXCJhXCIsIFwiYlwiXWAgYW5kIGBbXCJhX2JcIl1gXG4gKiBkaWZmZXIsIGFuZCBvYmplY3Qga2V5IG9yZGVyIGRvZXMgbm90LlxuICovXG5leHBvcnQgZnVuY3Rpb24gY2hhbm5lbE5hbWUodmFsdWU6IHVua25vd24pOiBzdHJpbmcge1xuICBjb25zdCBwYXJ0cyA9IG9iamVjdC50b09uZU9yTWFueSh2YWx1ZSk7XG4gIC8vIEhhc2ggdGhlIENBTk9OSUNBTCBmb3JtLCB0aGUgc2FtZSBydWxlIGBhZHZpc29yeUxvY2tJZGAgdXNlcywgc28gc3RydWN0dXJlIGFuZFxuICAvLyB0eXBlcyBkZWNpZGUgaWRlbnRpdHk6IGBbXCJhXCIsXCJiXCJdYCBkaWZmZXJzIGZyb20gYFtcImFiXCJdYCwgYDFgIGZyb20gYFwiMVwiYCwgYW5kXG4gIC8vIG9iamVjdCBrZXkgb3JkZXIgZG9lcyBub3QgbWF0dGVyLiBIYXNoaW5nIHRoZSByYXcgcGFydHMgd291bGQgaW5zdGVhZCBsZWFuIG9uXG4gIC8vIHRoZSBoYXNoIG1vZHVsZSdzIGNhbm9uaWNhbGl6ZXIsIHdoaWNoIGZvbGRzIGV2ZXJ5IGBEYXRlYCBvbnRvIG9uZSB0b2tlbi5cbiAgY29uc3Qgc3VmZml4ID0gaGFzaC5mbnZIYXNoV2l0aE9wdGlvbnMoXG4gICAgeyBsZW5ndGg6IENIQU5ORUxfSEFTSF9MRU5HVEggfSxcbiAgICBwYXJ0cy5tYXAoKHBhcnQpID0+IG9iamVjdC50b1N0YWJsZUtleShwYXJ0KSkuam9pbihcIlxcdTAwMDBcIiksXG4gICk7XG4gIC8vIE9ubHkgcGFydHMgdGhhdCBzdHJpbmdpZnkgdG8gc29tZXRoaW5nIGEgcmVhZGVyIHJlY29nbml6ZXMgY29udHJpYnV0ZSB0byB0aGVcbiAgLy8gcmVhZGFibGUgaGFsZi4gQW4gb2JqZWN0IHdvdWxkIHRva2VuaXplIGZyb20gYFN0cmluZyh2YWx1ZSlgIGFzXG4gIC8vIGBvYmplY3Rfb2JqZWN0YCwgd2hpY2ggaXMgbm9pc2UgLSBpdCBzdGlsbCBzaGFwZXMgdGhlIGhhc2gsIHNvIGlkZW50aXR5IGlzXG4gIC8vIHVuYWZmZWN0ZWQuXG4gIGNvbnN0IGxhYmVsbGVkID0gcGFydHMuZmlsdGVyKChwYXJ0KSA9PiB7XG4gICAgY29uc3QgdHlwZSA9IHR5cGVvZiBwYXJ0O1xuICAgIHJldHVybiB0eXBlID09PSBcInN0cmluZ1wiIHx8IHR5cGUgPT09IFwibnVtYmVyXCIgfHwgdHlwZSA9PT0gXCJib29sZWFuXCIgfHwgdHlwZSA9PT0gXCJiaWdpbnRcIjtcbiAgfSk7XG4gIC8vIFRydW5jYXRlIHJhdGhlciB0aGFuIGNhcCB0aHJvdWdoIHRoZSB0b2tlbml6ZXI6IGB0cmltYCB3b3VsZCBEUk9QIGEgc2luZ2xlXG4gIC8vIHRva2VuIGxvbmdlciB0aGFuIHRoZSBidWRnZXQsIHR1cm5pbmcgb25lIGxvbmcgbmFtZSBpbnRvIHRoZSBiYXJlIGZhbGxiYWNrIGFuZFxuICAvLyBtYWtpbmcgZXZlcnkgbG9uZyBuYW1lIGxvb2sgYWxpa2UuIFRoZSBoYXNoIHN0aWxsIHNlcGFyYXRlcyB0aGVtLCBidXQgdGhlXG4gIC8vIGNoYW5uZWwgaXMgdW5yZWFkYWJsZSBpbiBhIGxvZy5cbiAgY29uc3QgYm9keSA9IHN0cmluZ1xuICAgIC50b0lkZW50aWZpZXJXaXRoT3B0aW9ucyh7IGRlbGltaXRlcjogXCJfXCIgfSwgLi4ubGFiZWxsZWQpXG4gICAgLnNsaWNlKDAsIE1BWF9DSEFOTkVMX0xFTkdUSCAtIHN1ZmZpeC5sZW5ndGggLSAxKVxuICAgIC5yZXBsYWNlKC9fKyQvLCBcIlwiKTtcbiAgLy8gQW4gaWRlbnRpZmllciBjYW5ub3Qgc3RhcnQgd2l0aCBhIGRpZ2l0IGFuZCB0aGUgaGFzaCBhbHBoYWJldCBpc1xuICAvLyBkaWdpdC1sZWFkaW5nLCBzbyBhIG51bWVyaWMgb3IgZW1wdHkgYm9keSBuZWVkcyBhIGxldHRlciBpbiBmcm9udC5cbiAgY29uc3QgcHJlZml4ID0gL15bQS1aYS16X10vLnRlc3QoYm9keSkgPyBib2R5IDogYCR7Q0hBTk5FTF9GQUxMQkFDS31fJHtib2R5fWA7XG4gIHJldHVybiBgJHtwcmVmaXh9XyR7c3VmZml4fWAucmVwbGFjZSgvXysvZywgXCJfXCIpO1xufVxuXG4vKiogUXVvdGUgYSB2YWxpZGF0ZWQgY2hhbm5lbCBmb3IgYExJU1RFTmAvYFVOTElTVEVOYCwgd2hpY2ggdGFrZSBubyBwYXJhbWV0ZXJzLiAqL1xuZnVuY3Rpb24gcXVvdGVJZGVudGlmaWVyKHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gYFwiJHt2YWx1ZS5yZXBsYWNlQWxsKCdcIicsICdcIlwiJyl9XCJgO1xufVxuXG4vKipcbiAqIFBhcnNlIGEgYE5PVElGWWAgcGF5bG9hZCBpbnRvIGFuIGVudmVsb3BlLCByZXR1cm5pbmcgYHVuZGVmaW5lZGAgZm9yIGFueXRoaW5nXG4gKiB0aGF0IGlzIG5vdCBvbmUuXG4gKlxuICogVGhlIGNoYW5uZWwgaXMgc2hhcmVkIGFuZCBhbnkgUG9zdGdyZXMgc2Vzc2lvbiBjYW4gYHBnX25vdGlmeWAgb24gaXQsIHNvIGFuXG4gKiB1bnJlY29nbml6ZWQgcGF5bG9hZCBpcyBleHBlY3RlZCBpbnB1dCwgbm90IGFuIGV4Y2VwdGlvbi4gUHVibGlzaGVycyBydW4gdGhpc1xuICogb3ZlciB0aGVpciBvd24gZW5jb2RlZCBtZXNzYWdlIHRvbywgd2hpY2ggaXMgaG93IGEgYm9keSB0aGF0IHN0cmluZ2lmaWVzIGJ1dFxuICogZG9lcyBub3Qgcm91bmQtdHJpcCBpcyBjYXVnaHQgYmVmb3JlIGl0IHNoaXBzLlxuICovXG5mdW5jdGlvbiBkZWNvZGUodmFsdWU6IHN0cmluZyB8IHVuZGVmaW5lZCk6IFRvcGljTWVzc2FnZSB8IHVuZGVmaW5lZCB7XG4gIGlmICghdmFsdWUpIHJldHVybiB1bmRlZmluZWQ7XG4gIGNvbnN0IHJlY29yZCA9IGpzb24ucGFyc2VSZWNvcmQodmFsdWUpO1xuICBpZiAoXG4gICAgIXJlY29yZCB8fFxuICAgIHR5cGVvZiByZWNvcmQuaWQgIT09IFwic3RyaW5nXCIgfHxcbiAgICB0eXBlb2YgcmVjb3JkLnRvcGljICE9PSBcInN0cmluZ1wiIHx8XG4gICAgdHlwZW9mIHJlY29yZC50eXBlICE9PSBcInN0cmluZ1wiIHx8XG4gICAgdHlwZW9mIHJlY29yZC5wdWJsaXNoZWRBdCAhPT0gXCJzdHJpbmdcIiB8fFxuICAgICFyZWNvcmQubWV0YWRhdGEgfHxcbiAgICB0eXBlb2YgcmVjb3JkLm1ldGFkYXRhICE9PSBcIm9iamVjdFwiIHx8XG4gICAgQXJyYXkuaXNBcnJheShyZWNvcmQubWV0YWRhdGEpIHx8XG4gICAgIShcImJvZHlcIiBpbiByZWNvcmQpIHx8XG4gICAgIW9iamVjdC5pc1NlcmlhbGl6YWJsZVZhbHVlKHJlY29yZC5tZXRhZGF0YSkgfHxcbiAgICAhb2JqZWN0LmlzU2VyaWFsaXphYmxlVmFsdWUocmVjb3JkLmJvZHkpXG4gICkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgcmV0dXJuIHtcbiAgICBpZDogcmVjb3JkLmlkLFxuICAgIHRvcGljOiByZWNvcmQudG9waWMsXG4gICAgdHlwZTogcmVjb3JkLnR5cGUsXG4gICAgbWV0YWRhdGE6IHJlY29yZC5tZXRhZGF0YSBhcyBUb3BpY01ldGFkYXRhLFxuICAgIGJvZHk6IHJlY29yZC5ib2R5IGFzIFNlcmlhbGl6YWJsZVZhbHVlLFxuICAgIHB1Ymxpc2hlZEF0OiByZWNvcmQucHVibGlzaGVkQXQsXG4gIH07XG59XG5cbi8qKlxuICogQnJvYWRjYXN0cyBzdHJ1Y3R1cmVkIG1lc3NhZ2VzIGJ5IHRvcGljIGFuZCBkZWxpdmVycyB0aGVtIHRvIGV2ZXJ5IHByb2Nlc3NcbiAqIGxpc3RlbmluZyBvbiB0aGUgc2FtZSBjaGFubmVsLlxuICpcbiAqIENPTk5FQ1RJT04gU0hBUEUuIFB1Ymxpc2hpbmcgYm9ycm93cyBhIHBvb2xlZCBjb25uZWN0aW9uIHBlciBjYWxsLCBsaWtlIGFueVxuICogb3RoZXIgcXVlcnkuIExpc3RlbmluZyBjYW5ub3Q6IGBMSVNURU5gIGlzIHNlc3Npb24gc3RhdGUsIHNvIHRoZSBidXMgaG9sZHMgT05FXG4gKiBkZWRpY2F0ZWQgY2xpZW50IG91dCBvZiB0aGUgcG9vbCBmb3IgYXMgbG9uZyBhcyBpdCBoYXMgc3Vic2NyaWJlcnMsIG5vIG1hdHRlclxuICogaG93IG1hbnkgdG9waWNzIG9yIGxpc3RlbmVycyBhcmUgcmVnaXN0ZXJlZC4gU2l6ZSB0aGUgcG9vbCB3aXRoIHRoYXQgb25lXG4gKiBsb25nLWxpdmVkIGNoZWNrb3V0IGluIG1pbmQuXG4gKlxuICogTElGRUNZQ0xFLiBDb25zdHJ1Y3Rpb24gaXMgaW5lcnQgLSBub3RoaW5nIGNvbm5lY3RzIHVudGlsIHRoZSBmaXJzdFxuICoge0BsaW5rIGxpc3Rlbn0gKG9yIGFuIGV4cGxpY2l0IHtAbGluayBzdGFydH0pLiB7QGxpbmsgY2xvc2V9IGlzIHJlcXVpcmVkIHRvIGdpdmVcbiAqIHRoZSBjb25uZWN0aW9uIGJhY2s7IGEgY2xvc2VkIGJ1cyBzdGF5cyBjbG9zZWQgYW5kIHRocm93cyBvbiBmdXJ0aGVyIHVzZSByYXRoZXJcbiAqIHRoYW4gc2lsZW50bHkgcmVjb25uZWN0aW5nLiBSZWdpc3RlciBpdCB3aXRoIHRoZSBob3N0J3Mgc2h1dGRvd24gaG9vay5cbiAqXG4gKiBGQUlMVVJFIEhBTkRMSU5HLiBBIGxvc3Qgbm90aWZpY2F0aW9uIGNvbm5lY3Rpb24gcmVjb25uZWN0cyBvbiBpdHMgb3duIHdpdGhcbiAqIGJvdW5kZWQgYmFja29mZiB3aGlsZSBzdWJzY3JpYmVycyByZW1haW4sIHJlcG9ydGluZyBlYWNoIGZhaWxlZCBhdHRlbXB0IHRocm91Z2hcbiAqIGBvbkVycm9yYC4gTWVzc2FnZXMgcHVibGlzaGVkIGR1cmluZyB0aGUgZ2FwIGFyZSBsb3N0IC0gYE5PVElGWWAgaGFzIG5vIHJlcGxheS5cbiAqIEEgdGhyb3dpbmcgb3IgcmVqZWN0aW5nIGxpc3RlbmVyIG5ldmVyIGFmZmVjdHMgdGhlIHB1Ymxpc2hlciBvciB0aGUgb3RoZXJcbiAqIGxpc3RlbmVyczsgaXRzIGZhaWx1cmUgZ29lcyB0byBgb25FcnJvcmAuXG4gKlxuICogTm90IHNhZmUgdG8gc2hhcmUgb25lIGluc3RhbmNlIGFjcm9zcyB1bnJlbGF0ZWQgY2hhbm5lbHMgLSBjb25zdHJ1Y3Qgb25lIGJ1c1xuICogcGVyIGNoYW5uZWwuIFRoZSBjaGFubmVsIGl0c2VsZiBpcyBERVJJVkVEIGZyb20gdGhlIGBjaGFubmVsYCBvcHRpb24gcmF0aGVyXG4gKiB0aGFuIHRha2VuIGxpdGVyYWxseTsgc2VlIHtAbGluayBQb3N0Z3Jlc1RvcGljQnVzT3B0aW9ucy5jaGFubmVsfSBhbmRcbiAqIHtAbGluayBQb3N0Z3Jlc1RvcGljQnVzLmNoYW5uZWxOYW1lfS5cbiAqL1xuZXhwb3J0IGNsYXNzIFBvc3RncmVzVG9waWNCdXMge1xuICAvKipcbiAgICogVGhlIHJlc29sdmVkIFBvc3RncmVzIGNoYW5uZWwgdGhpcyBidXMgbGlzdGVucyBhbmQgcHVibGlzaGVzIG9uLCBkZXJpdmVkIGZyb21cbiAgICogdGhlIGBjaGFubmVsYCBvcHRpb24uIFJlYWQgaXQgdG8gY29uZmlybSB0d28gcHJvY2Vzc2VzIGFncmVlLCBvciB0byBsb2cgd2hhdCBhXG4gICAqIHNldCBvZiBwYXJ0cyBhY3R1YWxseSByZXNvbHZlZCB0by5cbiAgICovXG4gIHJlYWRvbmx5IGNoYW5uZWxOYW1lOiBzdHJpbmc7XG4gIHByaXZhdGUgcmVhZG9ubHkgbWV0YWRhdGE6IFRvcGljTWV0YWRhdGEgfCBUb3BpY01ldGFkYXRhUHJvdmlkZXIgfCB1bmRlZmluZWQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgb25FcnJvcjogKGNhdXNlOiB1bmtub3duKSA9PiB2b2lkO1xuICBwcml2YXRlIHJlYWRvbmx5IGxpc3RlbmVycyA9IG5ldyBNYXA8c3RyaW5nLCBTZXQ8VG9waWNMaXN0ZW5lcj4+KCk7XG4gIHByaXZhdGUgY2xpZW50OiBQb29sQ2xpZW50IHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIHN0YXJ0aW5nOiBQcm9taXNlPHZvaWQ+IHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIHJlY29ubmVjdGluZzogUHJvbWlzZTx2b2lkPiB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSByZWFkb25seSByZWNvbm5lY3RBYm9ydCA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKTtcbiAgcHJpdmF0ZSBjbG9zZWQgPSBmYWxzZTtcbiAgcHJpdmF0ZSByZWFkb25seSBwZXJzaXN0ZW5jZT86IFJlc29sdmVkVG9waWNCdXNQZXJzaXN0ZW5jZU9wdGlvbnM7XG4gIHByaXZhdGUgcHJvdmlzaW9uaW5nPzogUHJvbWlzZTx2b2lkPjtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IHBvb2w6IFBnUG9vbExpa2UgJiBQZ1F1ZXJ5YWJsZSxcbiAgICBvcHRpb25zOiBQb3N0Z3Jlc1RvcGljQnVzT3B0aW9ucyA9IHt9LFxuICApIHtcbiAgICB0aGlzLmNoYW5uZWxOYW1lID0gY2hhbm5lbE5hbWUoXG4gICAgICBvcHRpb25zLmNoYW5uZWwgPT09IHVuZGVmaW5lZCA/IERFRkFVTFRfQ0hBTk5FTCA6IG9wdGlvbnMuY2hhbm5lbCxcbiAgICApO1xuICAgIHRoaXMubWV0YWRhdGEgPSBvcHRpb25zLm1ldGFkYXRhO1xuICAgIHRoaXMub25FcnJvciA9IG9wdGlvbnMub25FcnJvciA/PyAoKCkgPT4gdW5kZWZpbmVkKTtcbiAgICB0aGlzLnBlcnNpc3RlbmNlID0gb3B0aW9ucy5wZXJzaXN0XG4gICAgICA/IHJlc29sdmVQZXJzaXN0ZW5jZU9wdGlvbnMob3B0aW9ucy5wZXJzaXN0ID09PSB0cnVlID8gdHJ1ZSA6IG9wdGlvbnMucGVyc2lzdClcbiAgICAgIDogdW5kZWZpbmVkO1xuICB9XG5cbiAgLyoqXG4gICAqIE9wZW4gdGhlIGRlZGljYXRlZCBub3RpZmljYXRpb24gY29ubmVjdGlvbiBhbmQgYExJU1RFTmAuXG4gICAqXG4gICAqIElkZW1wb3RlbnQsIGFuZCBzYWZlIHRvIGNhbGwgY29uY3VycmVudGx5IC0gb3ZlcmxhcHBpbmcgY2FsbHMgYXdhaXQgdGhlIHNhbWVcbiAgICogaW4tZmxpZ2h0IGNvbm5lY3QuIHtAbGluayBsaXN0ZW59IGNhbGxzIHRoaXMsIHNvIGl0IGlzIG9ubHkgbmVlZGVkIHRvIHN1cmZhY2VcbiAgICogYSBjb25uZWN0aW9uIHByb2JsZW0gYXQgc3RhcnR1cCByYXRoZXIgdGhhbiBvbiBmaXJzdCBzdWJzY3JpYmUuIFRocm93cyBpZiB0aGVcbiAgICogYnVzIGlzIGNsb3NlZCwgb3IgaWYgdGhlIHBvb2wgY2Fubm90IGhhbmQgb3V0IGEgY29ubmVjdGlvbi5cbiAgICovXG4gIGFzeW5jIHN0YXJ0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmNsaWVudCkgcmV0dXJuO1xuICAgIGlmICh0aGlzLmNsb3NlZCkgdGhyb3cgbmV3IEVycm9yKFwiUG9zdGdyZXMgdG9waWMgYnVzIGlzIGNsb3NlZFwiKTtcbiAgICB0aGlzLnN0YXJ0aW5nID8/PSB0aGlzLmNvbm5lY3QoKS5maW5hbGx5KCgpID0+IHtcbiAgICAgIHRoaXMuc3RhcnRpbmcgPSB1bmRlZmluZWQ7XG4gICAgfSk7XG4gICAgYXdhaXQgdGhpcy5zdGFydGluZztcbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaXNoIGEgbWVzc2FnZSB0byBgdG9waWNgLCByZXR1cm5pbmcgdGhlIGVudmVsb3BlIHRoYXQgd2FzIHNlbnQuXG4gICAqXG4gICAqIFJlc29sdmVzIG9uY2UgUG9zdGdyZXMgaGFzIGFjY2VwdGVkIHRoZSBgTk9USUZZYCwgd2hpY2ggc2F5cyBub3RoaW5nIGFib3V0XG4gICAqIGFueW9uZSByZWNlaXZpbmcgaXQ6IHNlc3Npb25zIG5vdCBsaXN0ZW5pbmcgYXQgdGhhdCBtb21lbnQgbWlzcyBpdC4gUHVibGlzaGluZ1xuICAgKiBuZWVkcyBubyB7QGxpbmsgc3RhcnR9IGFuZCBubyBzdWJzY3JpYmVycy5cbiAgICpcbiAgICogVmFsaWRhdGlvbiBpcyBkZWxpYmVyYXRlbHkgZnJvbnQtbG9hZGVkLCBzaW5jZSBhIG1lc3NhZ2UgdGhhdCBmYWlscyBvbiB0aGVcbiAgICogd2lyZSBpcyBmYXIgaGFyZGVyIHRvIGRpYWdub3NlIHRoYW4gb25lIHJlamVjdGVkIGF0IHRoZSBjYWxsOiBgVHlwZUVycm9yYCBmb3IgYVxuICAgKiBibGFuayB0b3BpYyBvciB0eXBlLCBvciBhIGJvZHkvbWV0YWRhdGEgdGhhdCB3b3VsZCBub3Qgcm91bmQtdHJpcCB0aHJvdWdoIEpTT05cbiAgICogdW5jaGFuZ2VkIChgb2JqZWN0LmlzU2VyaWFsaXphYmxlVmFsdWVgKTsgYFJhbmdlRXJyb3JgIHdoZW4gdGhlIGVuY29kZWRcbiAgICogZW52ZWxvcGUgZXhjZWVkcyB0aGUgYE5PVElGWWAgcGF5bG9hZCBsaW1pdCwgd2hpY2ggdGhlIGF1dG9tYXRpYyBtZXRhZGF0YVxuICAgKiBjb3VudHMgYWdhaW5zdCAtIHNlbmQgYSByZWZlcmVuY2UgYW5kIGxldCB0aGUgcmVjZWl2ZXIgZmV0Y2ggdGhlIHBheWxvYWQuXG4gICAqIFRocm93cyBpZiB0aGUgYnVzIGlzIGNsb3NlZC5cbiAgICovXG4gIGFzeW5jIGJyb2FkY2FzdDxUQm9keSBleHRlbmRzIFNlcmlhbGl6YWJsZVZhbHVlPihcbiAgICB0b3BpYzogc3RyaW5nLFxuICAgIGlucHV0OiBUb3BpY1B1Ymxpc2hJbnB1dDxUQm9keT4sXG4gICk6IFByb21pc2U8VG9waWNNZXNzYWdlPFRCb2R5Pj4ge1xuICAgIGlmICghdG9waWMudHJpbSgpKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiVG9waWMgbXVzdCBub3QgYmUgZW1wdHlcIik7XG4gICAgaWYgKCFpbnB1dC50eXBlLnRyaW0oKSkgdGhyb3cgbmV3IFR5cGVFcnJvcihcIk1lc3NhZ2UgdHlwZSBtdXN0IG5vdCBiZSBlbXB0eVwiKTtcbiAgICBpZiAoXG4gICAgICAhb2JqZWN0LmlzU2VyaWFsaXphYmxlVmFsdWUoaW5wdXQubWV0YWRhdGEgPz8ge30pIHx8XG4gICAgICAhb2JqZWN0LmlzU2VyaWFsaXphYmxlVmFsdWUoaW5wdXQuYm9keSlcbiAgICApIHtcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJNZXNzYWdlIG1ldGFkYXRhIGFuZCBib2R5IG11c3QgYmUgSlNPTiBzZXJpYWxpemFibGUgd2l0aG91dCBjb2VyY2lvblwiKTtcbiAgICB9XG4gICAgaWYgKHRoaXMuY2xvc2VkKSB0aHJvdyBuZXcgRXJyb3IoXCJQb3N0Z3JlcyB0b3BpYyBidXMgaXMgY2xvc2VkXCIpO1xuICAgIGNvbnN0IGF1dG9tYXRpYyA9IGF3YWl0IHRoaXMucmVzb2x2ZU1ldGFkYXRhKCk7XG4gICAgY29uc3QgbWVzc2FnZTogVG9waWNNZXNzYWdlPFRCb2R5PiA9IHtcbiAgICAgIGlkOiBoYXNoLmlkKCksXG4gICAgICB0b3BpYyxcbiAgICAgIHR5cGU6IGlucHV0LnR5cGUsXG4gICAgICBtZXRhZGF0YTogeyAuLi5hdXRvbWF0aWMsIC4uLmlucHV0Lm1ldGFkYXRhIH0sXG4gICAgICBib2R5OiBpbnB1dC5ib2R5LFxuICAgICAgcHVibGlzaGVkQXQ6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICB9O1xuICAgIGxldCBlbmNvZGVkOiBzdHJpbmc7XG4gICAgdHJ5IHtcbiAgICAgIGVuY29kZWQgPSBKU09OLnN0cmluZ2lmeShtZXNzYWdlKTtcbiAgICB9IGNhdGNoIChjYXVzZSkge1xuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihgTWVzc2FnZSBtdXN0IGJlIEpTT04gc2VyaWFsaXphYmxlOiAke2Vycm9yLmVycm9yTWVzc2FnZShjYXVzZSl9YCk7XG4gICAgfVxuICAgIGlmICghZGVjb2RlKGVuY29kZWQpKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiTWVzc2FnZSB0eXBlLCBtZXRhZGF0YSwgYW5kIGJvZHkgbXVzdCBiZSBKU09OIHNlcmlhbGl6YWJsZVwiKTtcbiAgICB9XG4gICAgLy8gT25seSB0aGUgZW52ZWxvcGUgcGF5bG9hZCBpcyBib3VuZGVkIGJ5IHRoZSBgTk9USUZZYCBsaW1pdC4gQSBwb2ludGVyXG4gICAgLy8gbm90aWZpY2F0aW9uIGlzIGEgZml4ZWQgaGFuZGZ1bCBvZiBieXRlcywgc28gcGVyc2lzdGVuY2Ugd2l0aFxuICAgIC8vIGBwYXlsb2FkOiBcInBvaW50ZXJcImAgbGlmdHMgdGhlIGNhcCBlbnRpcmVseS5cbiAgICBpZiAoXG4gICAgICBCdWZmZXIuYnl0ZUxlbmd0aChlbmNvZGVkLCBcInV0ZjhcIikgPiBNQVhfTk9USUZZX0JZVEVTICYmXG4gICAgICB0aGlzLnBlcnNpc3RlbmNlPy5wYXlsb2FkICE9PSBcInBvaW50ZXJcIlxuICAgICkge1xuICAgICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoYFBvc3RncmVzIG5vdGlmaWNhdGlvbiBleGNlZWRzICR7TUFYX05PVElGWV9CWVRFU30gYnl0ZXNgKTtcbiAgICB9XG4gICAgaWYgKCF0aGlzLnBlcnNpc3RlbmNlKSB7XG4gICAgICBhd2FpdCB0aGlzLnBvb2wucXVlcnkoXCJTRUxFQ1QgcGdfbm90aWZ5KCQxLCAkMilcIiwgW3RoaXMuY2hhbm5lbE5hbWUsIGVuY29kZWRdKTtcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKHRoaXMucGVyc2lzdGVuY2UucHJvdmlzaW9uKSB7XG4gICAgICAgIHRoaXMucHJvdmlzaW9uaW5nID8/PSBwcm92aXNpb25NZXNzYWdlQnVzU2NoZW1hKHRoaXMucG9vbCwgdGhpcy5wZXJzaXN0ZW5jZSk7XG4gICAgICAgIGF3YWl0IHRoaXMucHJvdmlzaW9uaW5nO1xuICAgICAgfVxuICAgICAgY29uc3QgY2xpZW50ID0gYXdhaXQgdGhpcy5wb29sLmNvbm5lY3QoKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGNsaWVudC5xdWVyeShcIkJFR0lOXCIpO1xuICAgICAgICBhd2FpdCBwZXJzaXN0ZWROb3RpZnkoXG4gICAgICAgICAgY2xpZW50LFxuICAgICAgICAgIHRoaXMuY2hhbm5lbE5hbWUsXG4gICAgICAgICAgdG9waWMsXG4gICAgICAgICAgbWVzc2FnZSxcbiAgICAgICAgICBlbmNvZGVkLFxuICAgICAgICAgIHRoaXMucGVyc2lzdGVuY2UsXG4gICAgICAgICAgaW5wdXQuc2NvcGUgPz8gdGhpcy5wZXJzaXN0ZW5jZS5zY29wZSxcbiAgICAgICAgICBpbnB1dC50dGwgPz8gdGhpcy5wZXJzaXN0ZW5jZS50dGwsXG4gICAgICAgICk7XG4gICAgICAgIGF3YWl0IGNsaWVudC5xdWVyeShcIkNPTU1JVFwiKTtcbiAgICAgIH0gY2F0Y2ggKGNhdXNlKSB7XG4gICAgICAgIGF3YWl0IGNsaWVudC5xdWVyeShcIlJPTExCQUNLXCIpLmNhdGNoKCgpID0+IHVuZGVmaW5lZCk7XG4gICAgICAgIHRocm93IGNhdXNlO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgY2xpZW50LnJlbGVhc2UoKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG1lc3NhZ2U7XG4gIH1cblxuICBhc3luYyBoaXN0b3J5PFRCb2R5IGV4dGVuZHMgU2VyaWFsaXphYmxlVmFsdWU+KFxuICAgIHRvcGljOiBzdHJpbmcsXG4gICAgb3B0aW9uczogeyBhZnRlcj86IHN0cmluZzsgbGltaXQ/OiBudW1iZXI7IHNjb3BlPzogVG9waWNQZXJzaXN0ZW5jZVNjb3BlIH0gPSB7fSxcbiAgKTogUHJvbWlzZTxUb3BpY0hpc3RvcnlQYWdlPFRCb2R5Pj4ge1xuICAgIGlmICghdGhpcy5wZXJzaXN0ZW5jZSkgdGhyb3cgbmV3IEVycm9yKFwiUG9zdGdyZXMgdG9waWMgYnVzIHBlcnNpc3RlbmNlIGlzIGRpc2FibGVkXCIpO1xuICAgIGlmICh0aGlzLnBlcnNpc3RlbmNlLnByb3Zpc2lvbikge1xuICAgICAgdGhpcy5wcm92aXNpb25pbmcgPz89IHByb3Zpc2lvbk1lc3NhZ2VCdXNTY2hlbWEodGhpcy5wb29sLCB0aGlzLnBlcnNpc3RlbmNlKTtcbiAgICAgIGF3YWl0IHRoaXMucHJvdmlzaW9uaW5nO1xuICAgIH1cbiAgICByZXR1cm4gaGlzdG9yeTxUQm9keT4odGhpcy5wb29sLCB0aGlzLmNoYW5uZWxOYW1lLCB0b3BpYywgdGhpcy5wZXJzaXN0ZW5jZSwgb3B0aW9ucyk7XG4gIH1cblxuICBhc3luYyBjbGVhbnVwRXhwaXJlZChcbiAgICBvcHRpb25zOiB7IHNjb3BlPzogVG9waWNQZXJzaXN0ZW5jZVNjb3BlOyBsaW1pdD86IG51bWJlciB9ID0ge30sXG4gICk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgaWYgKCF0aGlzLnBlcnNpc3RlbmNlKSB0aHJvdyBuZXcgRXJyb3IoXCJQb3N0Z3JlcyB0b3BpYyBidXMgcGVyc2lzdGVuY2UgaXMgZGlzYWJsZWRcIik7XG4gICAgcmV0dXJuIGNsZWFudXBFeHBpcmVkKFxuICAgICAgdGhpcy5wb29sLFxuICAgICAgdGhpcy5wZXJzaXN0ZW5jZSxcbiAgICAgIG9wdGlvbnMuc2NvcGUgPz8gdGhpcy5wZXJzaXN0ZW5jZS5zY29wZSxcbiAgICAgIG9wdGlvbnMubGltaXQsXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdWJzY3JpYmUgdG8gYHRvcGljYCwgcmV0dXJuaW5nIHRoZSBmdW5jdGlvbiB0aGF0IHVuc3Vic2NyaWJlcy5cbiAgICpcbiAgICogQ29ubmVjdHMgb24gZmlyc3QgdXNlLiBTZXZlcmFsIGxpc3RlbmVycyBtYXkgc2hhcmUgYSB0b3BpYzsgZWFjaCBpcyBjYWxsZWRcbiAgICogb25jZSBwZXIgbWVzc2FnZS4gT25seSBtZXNzYWdlcyBwdWJsaXNoZWQgQUZURVIgdGhpcyByZXNvbHZlcyBhcnJpdmUsIHNvXG4gICAqIHN1YnNjcmliZSBiZWZvcmUgdHJpZ2dlcmluZyB3aGF0ZXZlciB5b3UgZXhwZWN0IHRvIG9ic2VydmUuXG4gICAqXG4gICAqIFRoZSByZXR1cm5lZCBmdW5jdGlvbiByZW1vdmVzIGp1c3QgdGhpcyBsaXN0ZW5lciBhbmQgaXMgc2FmZSB0byBjYWxsIHR3aWNlLlxuICAgKiBUaGUgY29ubmVjdGlvbiBzdGF5cyBvcGVuIG9uY2UgdGhlIGxhc3QgbGlzdGVuZXIgbGVhdmVzIC0ge0BsaW5rIGNsb3NlfVxuICAgKiByZWxlYXNlcyBpdCAtIHNvIGEgYnVzIHRoYXQgc3Vic2NyaWJlcyBhbmQgdW5zdWJzY3JpYmVzIHBlciByZXF1ZXN0IGRvZXMgbm90XG4gICAqIGNodXJuIGNvbm5lY3Rpb25zLlxuICAgKi9cbiAgYXN5bmMgbGlzdGVuPFRCb2R5IGV4dGVuZHMgU2VyaWFsaXphYmxlVmFsdWU+KFxuICAgIHRvcGljOiBzdHJpbmcsXG4gICAgbGlzdGVuZXI6IFRvcGljTGlzdGVuZXI8VEJvZHk+LFxuICApOiBQcm9taXNlPCgpID0+IFByb21pc2U8dm9pZD4+IHtcbiAgICBpZiAoIXRvcGljLnRyaW0oKSkgdGhyb3cgbmV3IFR5cGVFcnJvcihcIlRvcGljIG11c3Qgbm90IGJlIGVtcHR5XCIpO1xuICAgIGF3YWl0IHRoaXMuc3RhcnQoKTtcbiAgICBjb25zdCBsaXN0ZW5lcnMgPSB0aGlzLmxpc3RlbmVycy5nZXQodG9waWMpID8/IG5ldyBTZXQ8VG9waWNMaXN0ZW5lcj4oKTtcbiAgICBsaXN0ZW5lcnMuYWRkKGxpc3RlbmVyIGFzIFRvcGljTGlzdGVuZXIpO1xuICAgIHRoaXMubGlzdGVuZXJzLnNldCh0b3BpYywgbGlzdGVuZXJzKTtcbiAgICByZXR1cm4gYXN5bmMgKCkgPT4ge1xuICAgICAgbGlzdGVuZXJzLmRlbGV0ZShsaXN0ZW5lciBhcyBUb3BpY0xpc3RlbmVyKTtcbiAgICAgIGlmIChsaXN0ZW5lcnMuc2l6ZSA9PT0gMCkgdGhpcy5saXN0ZW5lcnMuZGVsZXRlKHRvcGljKTtcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1aWxkIHRoZSBhdXRvbWF0aWMgaGFsZiBvZiBhIG1lc3NhZ2UncyBtZXRhZGF0YS5cbiAgICpcbiAgICogUHJlY2VkZW5jZSwgd2Vha2VzdCBmaXJzdDogbWFjaGluZS9wcm9jZXNzIGNvbnRleHQsIHRoZW4gQXBwS2l0IHNlbmRlclxuICAgKiBpZGVudGl0eSwgdGhlbiB0aGlzIGJ1cydzIGNvbmZpZ3VyZWQgbWV0YWRhdGEuIFRoZSBjYWxsZXIncyBwZXItbWVzc2FnZVxuICAgKiBtZXRhZGF0YSBpcyBsYXllcmVkIG92ZXIgdGhlIHJlc3VsdCBpbiB7QGxpbmsgYnJvYWRjYXN0fSwgc28gdGhlIG1vc3Qgc3BlY2lmaWNcbiAgICogc291cmNlIGFsd2F5cyB3aW5zIGFuZCBub3RoaW5nIGhlcmUgY2FuIG92ZXJ3cml0ZSBhbiBleHBsaWNpdCBrZXkuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHJlc29sdmVNZXRhZGF0YSgpOiBQcm9taXNlPFRvcGljTWV0YWRhdGE+IHtcbiAgICBjb25zdCBzZW5kZXIgPSBhd2FpdCBzZW5kZXJNZXRhZGF0YSgpO1xuICAgIGNvbnN0IGNvbmZpZ3VyZWQgPVxuICAgICAgdHlwZW9mIHRoaXMubWV0YWRhdGEgPT09IFwiZnVuY3Rpb25cIiA/IGF3YWl0IHRoaXMubWV0YWRhdGEoKSA6ICh0aGlzLm1ldGFkYXRhID8/IHt9KTtcbiAgICByZXR1cm4geyAuLi5tYWNoaW5lTWV0YWRhdGEoKSwgLi4uc2VuZGVyLCAuLi5jb25maWd1cmVkIH07XG4gIH1cblxuICAvKipcbiAgICogUmVsZWFzZSB0aGUgbm90aWZpY2F0aW9uIGNvbm5lY3Rpb24gYW5kIHN0b3AgZGVsaXZlcmluZyBtZXNzYWdlcy4gSWRlbXBvdGVudC5cbiAgICpcbiAgICogQ2FuY2VscyBhbnkgcGVuZGluZyByZWNvbm5lY3QsIGRyb3BzIGFsbCBsaXN0ZW5lcnMsIHRoZW4gYFVOTElTVEVOYHMgYW5kXG4gICAqIHJldHVybnMgdGhlIGNsaWVudCB0byB0aGUgcG9vbC4gQSBmYWlsZWQgYFVOTElTVEVOYCBpcyByZXBvcnRlZCB0byB0aGUgcG9vbCBhc1xuICAgKiBhIHJlbGVhc2UgZXJyb3Igc28gdGhlIGNvbm5lY3Rpb24gaXMgRElTQ0FSREVEIHJhdGhlciB0aGFuIGhhbmRlZCB0byB0aGUgbmV4dFxuICAgKiBjYWxsZXIgc3RpbGwgc3Vic2NyaWJlZCB0byB0aGUgY2hhbm5lbC4gRG9lcyBub3QgdGhyb3c7IHRoZSBidXMgc3RheXMgY2xvc2VkLlxuICAgKi9cbiAgYXN5bmMgY2xvc2UoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuY2xvc2VkKSByZXR1cm47XG4gICAgdGhpcy5jbG9zZWQgPSB0cnVlO1xuICAgIHRoaXMucmVjb25uZWN0QWJvcnQuYWJvcnQobmV3IEVycm9yKFwiUG9zdGdyZXMgdG9waWMgYnVzIGlzIGNsb3NlZFwiKSk7XG4gICAgYXdhaXQgdGhpcy5zdGFydGluZz8uY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgICBhd2FpdCB0aGlzLnJlY29ubmVjdGluZz8uY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgICBjb25zdCBjbGllbnQgPSB0aGlzLmNsaWVudDtcbiAgICB0aGlzLmNsaWVudCA9IHVuZGVmaW5lZDtcbiAgICB0aGlzLmxpc3RlbmVycy5jbGVhcigpO1xuICAgIGlmICghY2xpZW50KSByZXR1cm47XG4gICAgY2xpZW50LnJlbW92ZUxpc3RlbmVyKFwibm90aWZpY2F0aW9uXCIsIHRoaXMuaGFuZGxlTm90aWZpY2F0aW9uKTtcbiAgICBjbGllbnQucmVtb3ZlTGlzdGVuZXIoXCJlcnJvclwiLCB0aGlzLmhhbmRsZUNsaWVudEVycm9yKTtcbiAgICBsZXQgcmVsZWFzZUVycm9yOiBFcnJvciB8IHVuZGVmaW5lZDtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgY2xpZW50LnF1ZXJ5KGBVTkxJU1RFTiAke3F1b3RlSWRlbnRpZmllcih0aGlzLmNoYW5uZWxOYW1lKX1gKTtcbiAgICB9IGNhdGNoIChjYXVzZSkge1xuICAgICAgcmVsZWFzZUVycm9yID0gZXJyb3IudG9FcnJvcihjYXVzZSk7XG4gICAgfVxuICAgIGNsaWVudC5yZWxlYXNlKHJlbGVhc2VFcnJvcik7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgb3V0IG9uZSBjbGllbnQsIGF0dGFjaCB0aGUgaGFuZGxlcnMsIGFuZCBgTElTVEVOYC5cbiAgICpcbiAgICogVGhlIGhhbmRsZXJzIGFyZSBhdHRhY2hlZCBCRUZPUkUgdGhlIGBMSVNURU5gIHJvdW5kIHRyaXAgc28gYSBub3RpZmljYXRpb24gb3JcbiAgICogZXJyb3IgYXJyaXZpbmcgbWlkLXNldHVwIGlzIG5vdCBtaXNzZWQuIEFueSBmYWlsdXJlIC0gaW5jbHVkaW5nIHRoZSBidXMgYmVpbmdcbiAgICogY2xvc2VkIHdoaWxlIHRoZSBjb25uZWN0IHdhcyBpbiBmbGlnaHQgLSBkZXRhY2hlcyB0aGUgaGFuZGxlcnMgYW5kIHJlbGVhc2VzXG4gICAqIHRoZSBjbGllbnQgYXMgZXJyb3JlZCwgc28gYSBoYWxmLWNvbmZpZ3VyZWQgY29ubmVjdGlvbiBuZXZlciByZXR1cm5zIHRvIHRoZVxuICAgKiBwb29sLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBjb25uZWN0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGNsaWVudCA9IGF3YWl0IHRoaXMucG9vbC5jb25uZWN0KCk7XG4gICAgdHJ5IHtcbiAgICAgIGNsaWVudC5vbihcIm5vdGlmaWNhdGlvblwiLCB0aGlzLmhhbmRsZU5vdGlmaWNhdGlvbik7XG4gICAgICBjbGllbnQub24oXCJlcnJvclwiLCB0aGlzLmhhbmRsZUNsaWVudEVycm9yKTtcbiAgICAgIGF3YWl0IGNsaWVudC5xdWVyeShgTElTVEVOICR7cXVvdGVJZGVudGlmaWVyKHRoaXMuY2hhbm5lbE5hbWUpfWApO1xuICAgICAgaWYgKHRoaXMuY2xvc2VkKSB0aHJvdyBuZXcgRXJyb3IoXCJQb3N0Z3JlcyB0b3BpYyBidXMgaXMgY2xvc2VkXCIpO1xuICAgICAgdGhpcy5jbGllbnQgPSBjbGllbnQ7XG4gICAgfSBjYXRjaCAoY2F1c2UpIHtcbiAgICAgIGNsaWVudC5yZW1vdmVMaXN0ZW5lcihcIm5vdGlmaWNhdGlvblwiLCB0aGlzLmhhbmRsZU5vdGlmaWNhdGlvbik7XG4gICAgICBjbGllbnQucmVtb3ZlTGlzdGVuZXIoXCJlcnJvclwiLCB0aGlzLmhhbmRsZUNsaWVudEVycm9yKTtcbiAgICAgIGNsaWVudC5yZWxlYXNlKGVycm9yLnRvRXJyb3IoY2F1c2UpKTtcbiAgICAgIHRocm93IGNhdXNlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSb3V0ZSBvbmUgaW5ib3VuZCBub3RpZmljYXRpb24gdG8gdGhlIHRvcGljJ3MgbGlzdGVuZXJzLlxuICAgKlxuICAgKiBJZ25vcmVzIG90aGVyIGNoYW5uZWxzIGFuZCB1bmRlY29kYWJsZSBwYXlsb2FkcyAtIHRoZSBjaGFubmVsIGlzIHNoYXJlZCwgc29cbiAgICogYm90aCBhcmUgb3JkaW5hcnkgdHJhZmZpYy4gTGlzdGVuZXJzIGFyZSBpbnZva2VkIGNvbmN1cnJlbnRseSBhbmQgdGhlaXJcbiAgICogcmVqZWN0aW9ucyBnbyB0byBgb25FcnJvcmAsIGtlZXBpbmcgb25lIHNsb3cgb3IgYnJva2VuIHN1YnNjcmliZXIgZnJvbVxuICAgKiBzdGFsbGluZyB0aGUgbm90aWZpY2F0aW9uIGNvbm5lY3Rpb24uXG4gICAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGhhbmRsZU5vdGlmaWNhdGlvbiA9IChub3RpZmljYXRpb246IE5vdGlmaWNhdGlvbik6IHZvaWQgPT4ge1xuICAgIGlmIChub3RpZmljYXRpb24uY2hhbm5lbCAhPT0gdGhpcy5jaGFubmVsTmFtZSkgcmV0dXJuO1xuICAgIGNvbnN0IG1lc3NhZ2UgPSBkZWNvZGUobm90aWZpY2F0aW9uLnBheWxvYWQpO1xuICAgIGlmIChtZXNzYWdlKSB7XG4gICAgICB0aGlzLmRlbGl2ZXIobWVzc2FnZSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIGBwYXlsb2FkOiBcInBvaW50ZXJcImAgY2FycmllcyBvbmx5IHJvdXRpbmcgYW5kIGlkZW50aXR5LCBzbyB0aGUgZW52ZWxvcGUgaGFzXG4gICAgLy8gdG8gYmUgcmVhZCBiYWNrIGJlZm9yZSBhbnl0aGluZyBjYW4gYmUgZGVsaXZlcmVkLiBPbmx5IGF0dGVtcHRlZCB3aGVuIHRoaXNcbiAgICAvLyBidXMgaXMgY29uZmlndXJlZCBmb3IgcGVyc2lzdGVuY2U7IG90aGVyd2lzZSB0aGUgcGF5bG9hZCBpcyBmb3JlaWduIHRyYWZmaWNcbiAgICAvLyBvbiBhIHNoYXJlZCBjaGFubmVsIGFuZCBpZ25vcmVkIGFzIGJlZm9yZS5cbiAgICBjb25zdCBwb2ludGVyID0gdGhpcy5wZXJzaXN0ZW5jZSA/IGRlY29kZVBvaW50ZXIobm90aWZpY2F0aW9uLnBheWxvYWQpIDogdW5kZWZpbmVkO1xuICAgIGlmICghcG9pbnRlcikgcmV0dXJuO1xuICAgIGlmICghdGhpcy5saXN0ZW5lcnMuaGFzKHBvaW50ZXIudG9waWMpKSByZXR1cm47XG4gICAgcmVhZFBvaW50ZXIodGhpcy5wb29sLCB0aGlzLmNoYW5uZWxOYW1lLCBwb2ludGVyLCB0aGlzLnBlcnNpc3RlbmNlISlcbiAgICAgIC50aGVuKChzdG9yZWQpID0+IHtcbiAgICAgICAgaWYgKHN0b3JlZCkgdGhpcy5kZWxpdmVyKHN0b3JlZCk7XG4gICAgICB9KVxuICAgICAgLmNhdGNoKHRoaXMub25FcnJvcik7XG4gIH07XG5cbiAgLyoqIEhhbmQgb25lIGRlY29kZWQgbWVzc2FnZSB0byB0aGUgdG9waWMncyBsaXN0ZW5lcnMuICovXG4gIHByaXZhdGUgZGVsaXZlcihtZXNzYWdlOiBUb3BpY01lc3NhZ2UpOiB2b2lkIHtcbiAgICBmb3IgKGNvbnN0IGxpc3RlbmVyIG9mIHRoaXMubGlzdGVuZXJzLmdldChtZXNzYWdlLnRvcGljKSA/PyBbXSkge1xuICAgICAgUHJvbWlzZS5yZXNvbHZlKGxpc3RlbmVyKG1lc3NhZ2UpKS5jYXRjaCh0aGlzLm9uRXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBIYW5kbGUgdGhlIG5vdGlmaWNhdGlvbiBjb25uZWN0aW9uIGR5aW5nLCB3aGljaCBgcGdgIHJlcG9ydHMgYXMgYW4gYGVycm9yYFxuICAgKiBldmVudCByYXRoZXIgdGhhbiBhIHJlamVjdGVkIHF1ZXJ5LlxuICAgKlxuICAgKiBUaGUgY2xpZW50IGlzIHVudXNhYmxlIGF0IHRoaXMgcG9pbnQsIHNvIGl0IGlzIGRldGFjaGVkIGFuZCByZWxlYXNlZCBhc1xuICAgKiBlcnJvcmVkICh3aGljaCBkaXNjYXJkcyBpdCkgYmVmb3JlIGFueXRoaW5nIGVsc2UuIFJlY29ubmVjdGlvbiBvbmx5IHN0YXJ0c1xuICAgKiB3aGVuIHRoZXJlIGlzIHN0aWxsIHNvbWVvbmUgdG8gZGVsaXZlciB0bywgc28gYW4gaWRsZSBvciBjbG9zaW5nIGJ1cyBkb2VzIG5vdFxuICAgKiBob2xkIGEgY29ubmVjdGlvbiBvcGVuIGNoYXNpbmcgYSBjaGFubmVsIG5vYm9keSByZWFkcy5cbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgaGFuZGxlQ2xpZW50RXJyb3IgPSAoY2F1c2U6IEVycm9yKTogdm9pZCA9PiB7XG4gICAgdGhpcy5vbkVycm9yKGNhdXNlKTtcbiAgICBjb25zdCBjbGllbnQgPSB0aGlzLmNsaWVudDtcbiAgICBpZiAoIWNsaWVudCkgcmV0dXJuO1xuICAgIHRoaXMuY2xpZW50ID0gdW5kZWZpbmVkO1xuICAgIGNsaWVudC5yZW1vdmVMaXN0ZW5lcihcIm5vdGlmaWNhdGlvblwiLCB0aGlzLmhhbmRsZU5vdGlmaWNhdGlvbik7XG4gICAgY2xpZW50LnJlbW92ZUxpc3RlbmVyKFwiZXJyb3JcIiwgdGhpcy5oYW5kbGVDbGllbnRFcnJvcik7XG4gICAgY2xpZW50LnJlbGVhc2UoY2F1c2UpO1xuICAgIGlmICh0aGlzLmNsb3NlZCB8fCB0aGlzLmxpc3RlbmVycy5zaXplID09PSAwKSByZXR1cm47XG4gICAgdGhpcy5yZWNvbm5lY3RpbmcgPz89IHRoaXMucmVjb25uZWN0KCkuZmluYWxseSgoKSA9PiB7XG4gICAgICB0aGlzLnJlY29ubmVjdGluZyA9IHVuZGVmaW5lZDtcbiAgICB9KTtcbiAgfTtcblxuICAvKipcbiAgICogUmUtZXN0YWJsaXNoIHRoZSBub3RpZmljYXRpb24gY29ubmVjdGlvbiB3aXRoIGJvdW5kZWQgZXhwb25lbnRpYWwgYmFja29mZi5cbiAgICpcbiAgICogVGhlIGZpcnN0IGF0dGVtcHQgaXMgaW1tZWRpYXRlLCBzaW5jZSB0aGUgY29tbW9uIGNhc2UgaXMgYSBzaW5nbGUgZHJvcHBlZFxuICAgKiBjb25uZWN0aW9uIHRoYXQgcmVjb25uZWN0cyBhdCBvbmNlOyBzdWJzZXF1ZW50IGRlbGF5cyBkb3VibGUgZnJvbSAyNTBtcyB1cCB0b1xuICAgKiA1cyBhbmQgc3RheSB0aGVyZS4gUmV0cmllcyBpbmRlZmluaXRlbHkgcmF0aGVyIHRoYW4gZ2l2aW5nIHVwLCBiZWNhdXNlIGEgUG9zdGdyZXMgcmVzdGFydFxuICAgKiBvciBhIHJvdGF0ZWQgTGFrZWJhc2UgY3JlZGVudGlhbCBpcyBhIHJlY292ZXJhYmxlIG91dGFnZSBhbmQgYSBzaWxlbnRseSBkZWFkXG4gICAqIGxpc3RlbmVyIGlzIHdvcnNlIHRoYW4gYSBub2lzeSBvbmUuIFN0b3BzIHdoZW4gdGhlIGJ1cyBjbG9zZXMgb3IgdGhlIGxhc3RcbiAgICogbGlzdGVuZXIgbGVhdmVzLCBhbmQgcmVwb3J0cyBldmVyeSBmYWlsZWQgYXR0ZW1wdCB0aHJvdWdoIGBvbkVycm9yYC5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcmVjb25uZWN0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGxldCBkZWxheSA9IDA7XG4gICAgd2hpbGUgKCF0aGlzLmNsb3NlZCAmJiB0aGlzLmxpc3RlbmVycy5zaXplID4gMCkge1xuICAgICAgaWYgKGRlbGF5ID4gMCkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IGFzeW5jVXRpbC5zbGVlcChkZWxheSwgdGhpcy5yZWNvbm5lY3RBYm9ydC5zaWduYWwpO1xuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMuc3RhcnQoKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSBjYXRjaCAoY2F1c2UpIHtcbiAgICAgICAgaWYgKHRoaXMuY2xvc2VkKSByZXR1cm47XG4gICAgICAgIHRoaXMub25FcnJvcihjYXVzZSk7XG4gICAgICAgIGRlbGF5ID0gZGVsYXkgPT09IDAgPyBNSU5fUkVDT05ORUNUX0RFTEFZX01TIDogTWF0aC5taW4oZGVsYXkgKiAyLCBNQVhfUkVDT05ORUNUX0RFTEFZX01TKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cbiJdfQ==
|
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.
|
|
31
|
+
"@dbx-tools/shared-core": "0.6.88",
|
|
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.
|
|
48
|
+
"version": "0.6.88",
|
|
49
49
|
"types": "./lib/index.d.ts",
|
|
50
50
|
"type": "module",
|
|
51
51
|
"exports": {
|
package/src/persistence.ts
CHANGED
|
@@ -24,29 +24,46 @@ export interface ResolvedTopicBusPersistenceOptions {
|
|
|
24
24
|
cleanupBatchSize: number;
|
|
25
25
|
provision: boolean;
|
|
26
26
|
}
|
|
27
|
-
export interface StoredTopicMessage<
|
|
27
|
+
export interface StoredTopicMessage<
|
|
28
|
+
TBody extends object.SerializableValue = object.SerializableValue,
|
|
29
|
+
> {
|
|
28
30
|
cursor: string;
|
|
29
31
|
expiresAt: string | null;
|
|
30
32
|
scope: TopicPersistenceScope;
|
|
31
33
|
message: TopicMessage<TBody>;
|
|
32
34
|
}
|
|
33
|
-
export interface TopicHistoryPage<
|
|
35
|
+
export interface TopicHistoryPage<
|
|
36
|
+
TBody extends object.SerializableValue = object.SerializableValue,
|
|
37
|
+
> {
|
|
34
38
|
messages: StoredTopicMessage<TBody>[];
|
|
35
39
|
nextCursor?: string;
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
const DEFAULT_TTL = "24 hours";
|
|
43
|
+
/**
|
|
44
|
+
* Pointer-payload version. A listener that does not recognize the version treats
|
|
45
|
+
* the notification as foreign traffic rather than guessing at its shape.
|
|
46
|
+
*/
|
|
47
|
+
export const POINTER_VERSION = 1;
|
|
39
48
|
const quote = (value: string): string => `"${value.replaceAll('"', '""')}"`;
|
|
40
|
-
const table = (options: ResolvedTopicBusPersistenceOptions, scope: TopicPersistenceScope): string =>
|
|
49
|
+
const table = (options: ResolvedTopicBusPersistenceOptions, scope: TopicPersistenceScope): string =>
|
|
50
|
+
`${quote(options.schema)}.${quote(options.tables[scope])}`;
|
|
41
51
|
|
|
42
|
-
export function resolvePersistenceOptions(
|
|
52
|
+
export function resolvePersistenceOptions(
|
|
53
|
+
value: true | TopicBusPersistenceOptions,
|
|
54
|
+
): ResolvedTopicBusPersistenceOptions {
|
|
43
55
|
const configured = value === true ? {} : value;
|
|
44
56
|
const scope = configured.scope ?? "open";
|
|
45
|
-
if (scope !== "open" && scope !== "restricted")
|
|
57
|
+
if (scope !== "open" && scope !== "restricted") {
|
|
58
|
+
throw new TypeError(`Unknown persistence scope: ${String(scope)}`);
|
|
59
|
+
}
|
|
46
60
|
return {
|
|
47
61
|
schema: configured.schema ?? "dbx_message_bus",
|
|
48
62
|
scope,
|
|
49
|
-
tables: {
|
|
63
|
+
tables: {
|
|
64
|
+
open: configured.tables?.open ?? "open_messages",
|
|
65
|
+
restricted: configured.tables?.restricted ?? "restricted_messages",
|
|
66
|
+
},
|
|
50
67
|
ttl: configured.ttl ?? DEFAULT_TTL,
|
|
51
68
|
payload: configured.payload ?? "envelope",
|
|
52
69
|
cleanupBatchSize: configured.cleanupBatchSize ?? 1000,
|
|
@@ -54,21 +71,38 @@ export function resolvePersistenceOptions(value: true | TopicBusPersistenceOptio
|
|
|
54
71
|
};
|
|
55
72
|
}
|
|
56
73
|
|
|
57
|
-
export async function provisionMessageBusSchema(
|
|
74
|
+
export async function provisionMessageBusSchema(
|
|
75
|
+
pool: PgPoolLike,
|
|
76
|
+
options: ResolvedTopicBusPersistenceOptions,
|
|
77
|
+
): Promise<void> {
|
|
58
78
|
await withAdvisoryTransactionLock(pool, ["dbx_message_bus", "schema"], async (client) => {
|
|
59
79
|
await client.query(`CREATE SCHEMA IF NOT EXISTS ${quote(options.schema)}`);
|
|
60
|
-
await client.query(
|
|
80
|
+
await client.query(
|
|
81
|
+
`CREATE TABLE IF NOT EXISTS ${quote(options.schema)}.${quote("schema_version")} (version INTEGER PRIMARY KEY)`,
|
|
82
|
+
);
|
|
61
83
|
for (const scope of ["open", "restricted"] as const) {
|
|
62
84
|
const name = table(options, scope);
|
|
63
|
-
await client.query(
|
|
64
|
-
|
|
65
|
-
|
|
85
|
+
await client.query(
|
|
86
|
+
`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'))`,
|
|
87
|
+
);
|
|
88
|
+
await client.query(
|
|
89
|
+
`CREATE INDEX IF NOT EXISTS ${quote(`${options.tables[scope]}_replay_idx`)} ON ${name} (channel, topic, sequence)`,
|
|
90
|
+
);
|
|
91
|
+
await client.query(
|
|
92
|
+
`CREATE INDEX IF NOT EXISTS ${quote(`${options.tables[scope]}_expiry_idx`)} ON ${name} (expires_at) WHERE expires_at IS NOT NULL`,
|
|
93
|
+
);
|
|
66
94
|
}
|
|
67
|
-
await client.query(
|
|
95
|
+
await client.query(
|
|
96
|
+
`INSERT INTO ${quote(options.schema)}.${quote("schema_version")} (version) VALUES (1) ON CONFLICT (version) DO NOTHING`,
|
|
97
|
+
);
|
|
68
98
|
});
|
|
69
99
|
}
|
|
70
100
|
|
|
71
|
-
export function messageBusGrantStatements(
|
|
101
|
+
export function messageBusGrantStatements(
|
|
102
|
+
roles: string | readonly string[],
|
|
103
|
+
scope: TopicPersistenceScope,
|
|
104
|
+
options: ResolvedTopicBusPersistenceOptions,
|
|
105
|
+
): string[] {
|
|
72
106
|
const selected = table(options, scope);
|
|
73
107
|
return (typeof roles === "string" ? [roles] : roles).flatMap((role) => [
|
|
74
108
|
`GRANT USAGE ON SCHEMA ${quote(options.schema)} TO ${quote(role)};`,
|
|
@@ -83,33 +117,148 @@ function cursor(scope: TopicPersistenceScope, sequence: string | number): string
|
|
|
83
117
|
function after(value: string | undefined, scope: TopicPersistenceScope): string {
|
|
84
118
|
if (!value) return "0";
|
|
85
119
|
const decoded = JSON.parse(Buffer.from(value, "base64url").toString()) as [string, string];
|
|
86
|
-
if (decoded[0] !== scope)
|
|
120
|
+
if (decoded[0] !== scope) {
|
|
121
|
+
throw new TypeError("History cursor belongs to another persistence scope");
|
|
122
|
+
}
|
|
87
123
|
return decoded[1];
|
|
88
124
|
}
|
|
89
125
|
export function ttlMilliseconds(value: DurationInput | false): number | null {
|
|
90
126
|
if (value === false) return null;
|
|
91
127
|
const milliseconds = object.toDuration(value);
|
|
92
|
-
if (milliseconds === undefined || milliseconds <= 0)
|
|
128
|
+
if (milliseconds === undefined || milliseconds <= 0) {
|
|
129
|
+
throw new TypeError(`Invalid persistence TTL: ${String(value)}`);
|
|
130
|
+
}
|
|
93
131
|
return milliseconds;
|
|
94
132
|
}
|
|
95
133
|
|
|
96
|
-
export async function cleanupExpired(
|
|
97
|
-
|
|
134
|
+
export async function cleanupExpired(
|
|
135
|
+
queryable: PgQueryable,
|
|
136
|
+
options: ResolvedTopicBusPersistenceOptions,
|
|
137
|
+
scope: TopicPersistenceScope,
|
|
138
|
+
limit = options.cleanupBatchSize,
|
|
139
|
+
): Promise<number> {
|
|
140
|
+
const result = await queryable.query(
|
|
141
|
+
`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`,
|
|
142
|
+
[limit],
|
|
143
|
+
);
|
|
98
144
|
return result.rowCount ?? 0;
|
|
99
145
|
}
|
|
100
146
|
|
|
101
|
-
type HistoryRow = QueryResultRow & {
|
|
102
|
-
|
|
147
|
+
type HistoryRow = QueryResultRow & {
|
|
148
|
+
sequence: string;
|
|
149
|
+
expires_at: Date | string | null;
|
|
150
|
+
envelope: TopicMessage;
|
|
151
|
+
};
|
|
152
|
+
export async function history<TBody extends object.SerializableValue>(
|
|
153
|
+
queryable: PgQueryable,
|
|
154
|
+
channel: string,
|
|
155
|
+
topic: string,
|
|
156
|
+
options: ResolvedTopicBusPersistenceOptions,
|
|
157
|
+
input: { after?: string; limit?: number; scope?: TopicPersistenceScope } = {},
|
|
158
|
+
): Promise<TopicHistoryPage<TBody>> {
|
|
103
159
|
const scope = input.scope ?? options.scope;
|
|
104
160
|
const limit = input.limit ?? 100;
|
|
105
|
-
const result = await queryable.query<HistoryRow>(
|
|
106
|
-
|
|
107
|
-
|
|
161
|
+
const result = await queryable.query<HistoryRow>(
|
|
162
|
+
`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`,
|
|
163
|
+
[channel, topic, after(input.after, scope), limit],
|
|
164
|
+
);
|
|
165
|
+
const messages = result.rows.map((row) => ({
|
|
166
|
+
cursor: cursor(scope, row.sequence),
|
|
167
|
+
expiresAt: row.expires_at === null ? null : new Date(row.expires_at).toISOString(),
|
|
168
|
+
scope,
|
|
169
|
+
message: row.envelope as TopicMessage<TBody>,
|
|
170
|
+
}));
|
|
171
|
+
return {
|
|
172
|
+
messages,
|
|
173
|
+
...(messages.length === limit ? { nextCursor: messages.at(-1)!.cursor } : {}),
|
|
174
|
+
};
|
|
108
175
|
}
|
|
109
176
|
|
|
110
|
-
export async function persistedNotify(
|
|
177
|
+
export async function persistedNotify(
|
|
178
|
+
client: PgQueryable,
|
|
179
|
+
channel: string,
|
|
180
|
+
topic: string,
|
|
181
|
+
message: TopicMessage,
|
|
182
|
+
encoded: string,
|
|
183
|
+
options: ResolvedTopicBusPersistenceOptions,
|
|
184
|
+
scope: TopicPersistenceScope,
|
|
185
|
+
ttl: DurationInput | false,
|
|
186
|
+
): Promise<void> {
|
|
111
187
|
await cleanupExpired(client, options, scope);
|
|
112
188
|
const milliseconds = ttlMilliseconds(ttl);
|
|
113
|
-
await client.query
|
|
114
|
-
|
|
189
|
+
const inserted = await client.query<QueryResultRow & { sequence: string }>(
|
|
190
|
+
`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) RETURNING sequence`,
|
|
191
|
+
[channel, topic, message.id, message.publishedAt, milliseconds, encoded],
|
|
192
|
+
);
|
|
193
|
+
// The row and the notification commit together, so a pointer is never delivered
|
|
194
|
+
// before the row it names is readable - `NOTIFY` is delivered at COMMIT, not at
|
|
195
|
+
// statement time.
|
|
196
|
+
const payload =
|
|
197
|
+
options.payload === "pointer"
|
|
198
|
+
? pointerPayload(scope, topic, message.id, inserted.rows[0]?.sequence ?? "0")
|
|
199
|
+
: encoded;
|
|
200
|
+
await client.query("SELECT pg_notify($1, $2)", [channel, payload]);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* The `payload: "pointer"` notification body: routing and identity only, so the
|
|
205
|
+
* size limit does not apply and a listener without the table grant learns that
|
|
206
|
+
* something happened without learning what.
|
|
207
|
+
*/
|
|
208
|
+
export function pointerPayload(
|
|
209
|
+
scope: TopicPersistenceScope,
|
|
210
|
+
topic: string,
|
|
211
|
+
id: string,
|
|
212
|
+
sequence: string | number,
|
|
213
|
+
): string {
|
|
214
|
+
return JSON.stringify({ v: POINTER_VERSION, scope, topic, id, sequence: String(sequence) });
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** A decoded pointer notification. */
|
|
218
|
+
export interface TopicPointer {
|
|
219
|
+
scope: TopicPersistenceScope;
|
|
220
|
+
topic: string;
|
|
221
|
+
id: string;
|
|
222
|
+
sequence: string;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Read a notification as a pointer, or `undefined` when it is not one. The channel
|
|
227
|
+
* is shared, so an unrecognized payload is ordinary traffic rather than an error.
|
|
228
|
+
*/
|
|
229
|
+
export function decodePointer(value: string | undefined): TopicPointer | undefined {
|
|
230
|
+
if (!value) return undefined;
|
|
231
|
+
let record: unknown;
|
|
232
|
+
try {
|
|
233
|
+
record = JSON.parse(value);
|
|
234
|
+
} catch {
|
|
235
|
+
return undefined;
|
|
236
|
+
}
|
|
237
|
+
if (!record || typeof record !== "object" || Array.isArray(record)) return undefined;
|
|
238
|
+
const candidate = record as Record<string, unknown>;
|
|
239
|
+
if (candidate.v !== POINTER_VERSION) return undefined;
|
|
240
|
+
const { scope, topic, id, sequence } = candidate;
|
|
241
|
+
if (scope !== "open" && scope !== "restricted") return undefined;
|
|
242
|
+
if (typeof topic !== "string" || typeof id !== "string" || typeof sequence !== "string") {
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
245
|
+
return { scope, topic, id, sequence };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Fetch the one stored envelope a pointer names. Returns `undefined` when the row
|
|
250
|
+
* is gone (TTL cleanup won the race) or the reader lacks the table's grant, both
|
|
251
|
+
* of which are expected on the `restricted` tier rather than errors.
|
|
252
|
+
*/
|
|
253
|
+
export async function readPointer<TBody extends object.SerializableValue>(
|
|
254
|
+
queryable: PgQueryable,
|
|
255
|
+
channel: string,
|
|
256
|
+
pointer: TopicPointer,
|
|
257
|
+
options: ResolvedTopicBusPersistenceOptions,
|
|
258
|
+
): Promise<TopicMessage<TBody> | undefined> {
|
|
259
|
+
const result = await queryable.query<QueryResultRow & { envelope: TopicMessage }>(
|
|
260
|
+
`SELECT envelope FROM ${table(options, pointer.scope)} WHERE channel = $1 AND message_id = $2 AND (expires_at IS NULL OR expires_at > clock_timestamp())`,
|
|
261
|
+
[channel, pointer.id],
|
|
262
|
+
);
|
|
263
|
+
return result.rows[0]?.envelope as TopicMessage<TBody> | undefined;
|
|
115
264
|
}
|
package/src/topic-bus.ts
CHANGED
|
@@ -29,7 +29,20 @@ 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 {
|
|
32
|
+
import {
|
|
33
|
+
cleanupExpired,
|
|
34
|
+
decodePointer,
|
|
35
|
+
history,
|
|
36
|
+
persistedNotify,
|
|
37
|
+
provisionMessageBusSchema,
|
|
38
|
+
readPointer,
|
|
39
|
+
resolvePersistenceOptions,
|
|
40
|
+
type DurationInput,
|
|
41
|
+
type ResolvedTopicBusPersistenceOptions,
|
|
42
|
+
type TopicBusPersistenceOptions,
|
|
43
|
+
type TopicHistoryPage,
|
|
44
|
+
type TopicPersistenceScope,
|
|
45
|
+
} from "./persistence.ts";
|
|
33
46
|
|
|
34
47
|
/**
|
|
35
48
|
* `@dbx-tools/shared-core` owns the JSON-round-trip rule; this alias just keeps the
|
|
@@ -413,7 +426,9 @@ export class PostgresTopicBus {
|
|
|
413
426
|
);
|
|
414
427
|
this.metadata = options.metadata;
|
|
415
428
|
this.onError = options.onError ?? (() => undefined);
|
|
416
|
-
this.persistence = options.persist
|
|
429
|
+
this.persistence = options.persist
|
|
430
|
+
? resolvePersistenceOptions(options.persist === true ? true : options.persist)
|
|
431
|
+
: undefined;
|
|
417
432
|
}
|
|
418
433
|
|
|
419
434
|
/**
|
|
@@ -479,11 +494,18 @@ export class PostgresTopicBus {
|
|
|
479
494
|
if (!decode(encoded)) {
|
|
480
495
|
throw new TypeError("Message type, metadata, and body must be JSON serializable");
|
|
481
496
|
}
|
|
482
|
-
|
|
497
|
+
// Only the envelope payload is bounded by the `NOTIFY` limit. A pointer
|
|
498
|
+
// notification is a fixed handful of bytes, so persistence with
|
|
499
|
+
// `payload: "pointer"` lifts the cap entirely.
|
|
500
|
+
if (
|
|
501
|
+
Buffer.byteLength(encoded, "utf8") > MAX_NOTIFY_BYTES &&
|
|
502
|
+
this.persistence?.payload !== "pointer"
|
|
503
|
+
) {
|
|
483
504
|
throw new RangeError(`Postgres notification exceeds ${MAX_NOTIFY_BYTES} bytes`);
|
|
484
505
|
}
|
|
485
|
-
if (!this.persistence)
|
|
486
|
-
|
|
506
|
+
if (!this.persistence) {
|
|
507
|
+
await this.pool.query("SELECT pg_notify($1, $2)", [this.channelName, encoded]);
|
|
508
|
+
} else {
|
|
487
509
|
if (this.persistence.provision) {
|
|
488
510
|
this.provisioning ??= provisionMessageBusSchema(this.pool, this.persistence);
|
|
489
511
|
await this.provisioning;
|
|
@@ -491,17 +513,31 @@ export class PostgresTopicBus {
|
|
|
491
513
|
const client = await this.pool.connect();
|
|
492
514
|
try {
|
|
493
515
|
await client.query("BEGIN");
|
|
494
|
-
await persistedNotify(
|
|
516
|
+
await persistedNotify(
|
|
517
|
+
client,
|
|
518
|
+
this.channelName,
|
|
519
|
+
topic,
|
|
520
|
+
message,
|
|
521
|
+
encoded,
|
|
522
|
+
this.persistence,
|
|
523
|
+
input.scope ?? this.persistence.scope,
|
|
524
|
+
input.ttl ?? this.persistence.ttl,
|
|
525
|
+
);
|
|
495
526
|
await client.query("COMMIT");
|
|
496
527
|
} catch (cause) {
|
|
497
528
|
await client.query("ROLLBACK").catch(() => undefined);
|
|
498
529
|
throw cause;
|
|
499
|
-
} finally {
|
|
530
|
+
} finally {
|
|
531
|
+
client.release();
|
|
532
|
+
}
|
|
500
533
|
}
|
|
501
534
|
return message;
|
|
502
535
|
}
|
|
503
536
|
|
|
504
|
-
async history<TBody extends SerializableValue>(
|
|
537
|
+
async history<TBody extends SerializableValue>(
|
|
538
|
+
topic: string,
|
|
539
|
+
options: { after?: string; limit?: number; scope?: TopicPersistenceScope } = {},
|
|
540
|
+
): Promise<TopicHistoryPage<TBody>> {
|
|
505
541
|
if (!this.persistence) throw new Error("Postgres topic bus persistence is disabled");
|
|
506
542
|
if (this.persistence.provision) {
|
|
507
543
|
this.provisioning ??= provisionMessageBusSchema(this.pool, this.persistence);
|
|
@@ -510,9 +546,16 @@ export class PostgresTopicBus {
|
|
|
510
546
|
return history<TBody>(this.pool, this.channelName, topic, this.persistence, options);
|
|
511
547
|
}
|
|
512
548
|
|
|
513
|
-
async cleanupExpired(
|
|
549
|
+
async cleanupExpired(
|
|
550
|
+
options: { scope?: TopicPersistenceScope; limit?: number } = {},
|
|
551
|
+
): Promise<number> {
|
|
514
552
|
if (!this.persistence) throw new Error("Postgres topic bus persistence is disabled");
|
|
515
|
-
return cleanupExpired(
|
|
553
|
+
return cleanupExpired(
|
|
554
|
+
this.pool,
|
|
555
|
+
this.persistence,
|
|
556
|
+
options.scope ?? this.persistence.scope,
|
|
557
|
+
options.limit,
|
|
558
|
+
);
|
|
516
559
|
}
|
|
517
560
|
|
|
518
561
|
/**
|
|
@@ -622,11 +665,30 @@ export class PostgresTopicBus {
|
|
|
622
665
|
private readonly handleNotification = (notification: Notification): void => {
|
|
623
666
|
if (notification.channel !== this.channelName) return;
|
|
624
667
|
const message = decode(notification.payload);
|
|
625
|
-
if (
|
|
668
|
+
if (message) {
|
|
669
|
+
this.deliver(message);
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
// `payload: "pointer"` carries only routing and identity, so the envelope has
|
|
673
|
+
// to be read back before anything can be delivered. Only attempted when this
|
|
674
|
+
// bus is configured for persistence; otherwise the payload is foreign traffic
|
|
675
|
+
// on a shared channel and ignored as before.
|
|
676
|
+
const pointer = this.persistence ? decodePointer(notification.payload) : undefined;
|
|
677
|
+
if (!pointer) return;
|
|
678
|
+
if (!this.listeners.has(pointer.topic)) return;
|
|
679
|
+
readPointer(this.pool, this.channelName, pointer, this.persistence!)
|
|
680
|
+
.then((stored) => {
|
|
681
|
+
if (stored) this.deliver(stored);
|
|
682
|
+
})
|
|
683
|
+
.catch(this.onError);
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
/** Hand one decoded message to the topic's listeners. */
|
|
687
|
+
private deliver(message: TopicMessage): void {
|
|
626
688
|
for (const listener of this.listeners.get(message.topic) ?? []) {
|
|
627
689
|
Promise.resolve(listener(message)).catch(this.onError);
|
|
628
690
|
}
|
|
629
|
-
}
|
|
691
|
+
}
|
|
630
692
|
|
|
631
693
|
/**
|
|
632
694
|
* Handle the notification connection dying, which `pg` reports as an `error`
|