@dbx-tools/postgres 0.6.62

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.
@@ -0,0 +1,506 @@
1
+ /**
2
+ * Topic fan-out over PostgreSQL `LISTEN`/`NOTIFY`, for telling every running
3
+ * instance of an app that something happened.
4
+ *
5
+ * The sibling `advisory-lock` module is about making sure only ONE connection
6
+ * does a thing; this one is the opposite - EVERY listening session gets every
7
+ * notification. That makes it the right primitive for live UI updates
8
+ * (an SSE stream per browser tab, a cache invalidation, a presence ping) and the
9
+ * wrong one for work distribution: there are no competing consumers, no acks, and
10
+ * no replay.
11
+ *
12
+ * Delivery is best-effort and live. `NOTIFY` reaches sessions that are listening
13
+ * at the moment it commits, so a listener that connects a second later never sees
14
+ * it, and a listener whose connection drops misses everything until the bus
15
+ * reconnects. Use a table or a queue when a subscriber needs durability.
16
+ *
17
+ * ONE CHANNEL, MANY TOPICS. Every bus instance listens on a single Postgres
18
+ * channel (`channel`, default `dbx_tools_topic_bus`) and filters by the
19
+ * envelope's `topic` in-process, so adding a topic costs no connection and no
20
+ * `LISTEN`. The tradeoff is that every listening session decodes every message on
21
+ * the channel; give a genuinely high-volume, unrelated stream its own `channel`
22
+ * rather than a topic.
23
+ *
24
+ * @module
25
+ */
26
+ import { hostname } from "node:os";
27
+ import { async as asyncUtil, error, hash, json, object, string } from "@dbx-tools/shared-core";
28
+ /** Channel parts used when a caller names no channel of its own. */
29
+ const DEFAULT_CHANNEL = "dbx_tools_topic_bus";
30
+ /**
31
+ * `NAMEDATALEN - 1`. Postgres TRUNCATES a longer channel name rather than
32
+ * rejecting it, which would split publishers and listeners onto different
33
+ * channels while every call looked like it succeeded.
34
+ */
35
+ const MAX_CHANNEL_LENGTH = 63;
36
+ /** Base-32 chars of the channel's identity suffix. Max 7 - the digest is 32 bits. */
37
+ const CHANNEL_HASH_LENGTH = 6;
38
+ /** Body used when the parts tokenize to nothing, or lead with a digit. */
39
+ const CHANNEL_FALLBACK = "bus";
40
+ /**
41
+ * Encoded-envelope ceiling. PostgreSQL caps a `NOTIFY` payload at 8000 bytes and
42
+ * fails the statement past that, so the bus rejects the message first with a size
43
+ * it can name. The margin below 8000 covers the server's own accounting.
44
+ */
45
+ const MAX_NOTIFY_BYTES = 7_900;
46
+ const MIN_RECONNECT_DELAY_MS = 250;
47
+ const MAX_RECONNECT_DELAY_MS = 5_000;
48
+ /**
49
+ * Cached result of the one optional-peer import, resolved to `undefined` when
50
+ * AppKit is not installed. Memoized so a bus in a plain Postgres process pays for
51
+ * the failed resolution once instead of per broadcast.
52
+ */
53
+ let appKitModule;
54
+ /**
55
+ * Drop keys whose value is `undefined`, so an unset environment variable leaves
56
+ * the key ABSENT rather than present-and-null. Absence is what lets caller
57
+ * metadata and later merge layers supply the key instead.
58
+ */
59
+ function definedMetadata(values) {
60
+ return Object.fromEntries(Object.entries(values).filter((entry) => {
61
+ return entry[1] !== undefined;
62
+ }));
63
+ }
64
+ /**
65
+ * Context every message gets for free: which project, host, process, and
66
+ * deployment published it.
67
+ *
68
+ * Read fresh per broadcast rather than cached, because a long-lived process can
69
+ * be re-parented (a deployment id appearing after boot). Keys that resolve to
70
+ * nothing are omitted. Public IP is only read from the environment here - the bus
71
+ * never makes a network call to discover it; a process that wants a discovered IP
72
+ * passes a {@link TopicMetadataProvider}.
73
+ *
74
+ * Deliberately NOT included: CPU architecture, runtime name, and runtime version.
75
+ * They are constant per deployment and cost payload bytes against the `NOTIFY`
76
+ * limit on every single message.
77
+ */
78
+ function machineMetadata() {
79
+ return definedMetadata({
80
+ project: string.firstNonEmpty([
81
+ process.env.DATABRICKS_APP_NAME,
82
+ process.env.DATABRICKS_BUNDLE_NAME,
83
+ process.env.PROJECT_NAME,
84
+ process.env.npm_package_name,
85
+ ]) ?? undefined,
86
+ publicIp: string.firstNonEmpty([
87
+ process.env.PUBLIC_IP,
88
+ process.env.DATABRICKS_PUBLIC_IP,
89
+ process.env.HOST_IP,
90
+ ]) ?? undefined,
91
+ hostname: hostname(),
92
+ cwd: process.cwd(),
93
+ platform: process.platform,
94
+ pid: process.pid,
95
+ environment: string.trimToNull(process.env.NODE_ENV) ?? undefined,
96
+ appName: string.trimToNull(process.env.DATABRICKS_APP_NAME) ?? undefined,
97
+ deploymentId: string.trimToNull(process.env.DATABRICKS_APP_DEPLOYMENT_ID) ?? undefined,
98
+ databricksHost: string.trimToNull(process.env.DATABRICKS_HOST) ?? undefined,
99
+ });
100
+ }
101
+ /**
102
+ * Identity of the signed-in user on whose behalf this broadcast happens, when the
103
+ * process can tell.
104
+ *
105
+ * `@databricks/appkit` is an OPTIONAL peer, so the import is lazy and a missing
106
+ * module is not an error - this is a plain Postgres package that adds sender
107
+ * identity when it happens to run inside an AppKit app. Outside an active
108
+ * per-request execution context AppKit throws, which means "no user here", so the
109
+ * result is empty metadata rather than a failed broadcast.
110
+ */
111
+ async function senderMetadata() {
112
+ appKitModule ??= import("@databricks/appkit")
113
+ .then((module) => module)
114
+ .catch(() => undefined);
115
+ const appkit = await appKitModule;
116
+ if (!appkit)
117
+ return {};
118
+ try {
119
+ const context = appkit.getExecutionContext();
120
+ return definedMetadata({
121
+ senderId: string.trimToNull(context.userId) ?? undefined,
122
+ senderName: string.trimToNull(context.userName) ?? undefined,
123
+ senderEmail: string.trimToNull(context.userEmail) ?? undefined,
124
+ });
125
+ }
126
+ catch {
127
+ return {};
128
+ }
129
+ }
130
+ /**
131
+ * Derive a legal Postgres channel name from whatever a caller used to identify
132
+ * the channel.
133
+ *
134
+ * Callers think in terms of what the channel IS - an app name, a tenant id, a
135
+ * `[env, feature]` pair, a config object - and none of those are identifiers.
136
+ * Rejecting them pushed the sanitizing onto every call site, which is how two
137
+ * services end up disagreeing about whether the channel is `my-app`, `my_app`,
138
+ * or `myApp` and silently never hear each other.
139
+ *
140
+ * The parts are tokenized and joined into an identifier, then a short hash of the
141
+ * ORIGINAL parts is appended. The hash is what makes the mapping trustworthy:
142
+ * tokenizing alone is lossy, so `my-app` and `my_app` and `myApp` would collapse
143
+ * onto one channel, and a name long enough to hit `NAMEDATALEN` would collide
144
+ * with anything sharing its leading tokens. With the suffix, the readable part
145
+ * stays readable and distinct inputs stay distinct.
146
+ *
147
+ * Deterministic across processes and runs, which is the whole point - two
148
+ * services given the same parts must land on the same channel without
149
+ * coordinating. Hash inputs are structure-aware, so `["a", "b"]` and `["a_b"]`
150
+ * differ, and object key order does not.
151
+ */
152
+ function channelName(parts) {
153
+ // Hash the CANONICAL form, the same rule `advisoryLockId` uses, so structure and
154
+ // types decide identity: `["a","b"]` differs from `["ab"]`, `1` from `"1"`, and
155
+ // object key order does not matter. Hashing the raw parts would instead lean on
156
+ // the hash module's canonicalizer, which folds every `Date` onto one token.
157
+ const suffix = hash.fnvHashWithOptions({ length: CHANNEL_HASH_LENGTH }, parts.map((part) => object.toStableKey(part)).join("\u0000"));
158
+ // Only parts that stringify to something a reader recognizes contribute to the
159
+ // readable half. An object would tokenize from `String(value)` as
160
+ // `object_object`, which is noise - it still shapes the hash, so identity is
161
+ // unaffected.
162
+ const labelled = parts.filter((part) => {
163
+ const type = typeof part;
164
+ return type === "string" || type === "number" || type === "boolean" || type === "bigint";
165
+ });
166
+ // Truncate rather than cap through the tokenizer: `trim` would DROP a single
167
+ // token longer than the budget, turning one long name into the bare fallback and
168
+ // making every long name look alike. The hash still separates them, but the
169
+ // channel is unreadable in a log.
170
+ const body = string
171
+ .toIdentifierWithOptions({ delimiter: "_" }, ...labelled)
172
+ .slice(0, MAX_CHANNEL_LENGTH - suffix.length - 1)
173
+ .replace(/_+$/, "");
174
+ // An identifier cannot start with a digit and the hash alphabet is
175
+ // digit-leading, so a numeric or empty body needs a letter in front.
176
+ const prefix = /^[A-Za-z_]/.test(body) ? body : `${CHANNEL_FALLBACK}_${body}`;
177
+ return `${prefix}_${suffix}`.replace(/_+/g, "_");
178
+ }
179
+ /** Quote a validated channel for `LISTEN`/`UNLISTEN`, which take no parameters. */
180
+ function quoteIdentifier(value) {
181
+ return `"${value.replaceAll('"', '""')}"`;
182
+ }
183
+ /**
184
+ * Parse a `NOTIFY` payload into an envelope, returning `undefined` for anything
185
+ * that is not one.
186
+ *
187
+ * The channel is shared and any Postgres session can `pg_notify` on it, so an
188
+ * unrecognized payload is expected input, not an exception. Publishers run this
189
+ * over their own encoded message too, which is how a body that stringifies but
190
+ * does not round-trip is caught before it ships.
191
+ */
192
+ function decode(value) {
193
+ if (!value)
194
+ return undefined;
195
+ const record = json.parseRecord(value);
196
+ if (!record ||
197
+ typeof record.id !== "string" ||
198
+ typeof record.topic !== "string" ||
199
+ typeof record.type !== "string" ||
200
+ typeof record.publishedAt !== "string" ||
201
+ !record.metadata ||
202
+ typeof record.metadata !== "object" ||
203
+ Array.isArray(record.metadata) ||
204
+ !("body" in record) ||
205
+ !object.isSerializableValue(record.metadata) ||
206
+ !object.isSerializableValue(record.body)) {
207
+ return undefined;
208
+ }
209
+ return {
210
+ id: record.id,
211
+ topic: record.topic,
212
+ type: record.type,
213
+ metadata: record.metadata,
214
+ body: record.body,
215
+ publishedAt: record.publishedAt,
216
+ };
217
+ }
218
+ /**
219
+ * Broadcasts structured messages by topic and delivers them to every process
220
+ * listening on the same channel.
221
+ *
222
+ * CONNECTION SHAPE. Publishing borrows a pooled connection per call, like any
223
+ * other query. Listening cannot: `LISTEN` is session state, so the bus holds ONE
224
+ * dedicated client out of the pool for as long as it has subscribers, no matter
225
+ * how many topics or listeners are registered. Size the pool with that one
226
+ * long-lived checkout in mind.
227
+ *
228
+ * LIFECYCLE. Construction is inert - nothing connects until the first
229
+ * {@link listen} (or an explicit {@link start}). {@link close} is required to give
230
+ * the connection back; a closed bus stays closed and throws on further use rather
231
+ * than silently reconnecting. Register it with the host's shutdown hook.
232
+ *
233
+ * FAILURE HANDLING. A lost notification connection reconnects on its own with
234
+ * bounded backoff while subscribers remain, reporting each failed attempt through
235
+ * `onError`. Messages published during the gap are lost - `NOTIFY` has no replay.
236
+ * A throwing or rejecting listener never affects the publisher or the other
237
+ * listeners; its failure goes to `onError`.
238
+ *
239
+ * Not safe to share one instance across unrelated channels - construct one bus
240
+ * per channel. The channel itself is DERIVED from the `channel` option rather
241
+ * than taken literally; see {@link PostgresTopicBusOptions.channel} and
242
+ * {@link PostgresTopicBus.channelName}.
243
+ */
244
+ export class PostgresTopicBus {
245
+ pool;
246
+ /**
247
+ * The resolved Postgres channel this bus listens and publishes on, derived from
248
+ * the `channel` option. Read it to confirm two processes agree, or to log what a
249
+ * set of parts actually resolved to.
250
+ */
251
+ channelName;
252
+ metadata;
253
+ onError;
254
+ listeners = new Map();
255
+ client;
256
+ starting;
257
+ reconnecting;
258
+ reconnectAbort = new AbortController();
259
+ closed = false;
260
+ constructor(pool, options = {}) {
261
+ this.pool = pool;
262
+ this.channelName = channelName(object.toOneOrMany(options.channel === undefined ? DEFAULT_CHANNEL : options.channel));
263
+ this.metadata = options.metadata;
264
+ this.onError = options.onError ?? (() => undefined);
265
+ }
266
+ /**
267
+ * Open the dedicated notification connection and `LISTEN`.
268
+ *
269
+ * Idempotent, and safe to call concurrently - overlapping calls await the same
270
+ * in-flight connect. {@link listen} calls this, so it is only needed to surface
271
+ * a connection problem at startup rather than on first subscribe. Throws if the
272
+ * bus is closed, or if the pool cannot hand out a connection.
273
+ */
274
+ async start() {
275
+ if (this.client)
276
+ return;
277
+ if (this.closed)
278
+ throw new Error("Postgres topic bus is closed");
279
+ this.starting ??= this.connect().finally(() => {
280
+ this.starting = undefined;
281
+ });
282
+ await this.starting;
283
+ }
284
+ /**
285
+ * Publish a message to `topic`, returning the envelope that was sent.
286
+ *
287
+ * Resolves once Postgres has accepted the `NOTIFY`, which says nothing about
288
+ * anyone receiving it: sessions not listening at that moment miss it. Publishing
289
+ * needs no {@link start} and no subscribers.
290
+ *
291
+ * Validation is deliberately front-loaded, since a message that fails on the
292
+ * wire is far harder to diagnose than one rejected at the call: `TypeError` for a
293
+ * blank topic or type, or a body/metadata that would not round-trip through JSON
294
+ * unchanged (`object.isSerializableValue`); `RangeError` when the encoded
295
+ * envelope exceeds the `NOTIFY` payload limit, which the automatic metadata
296
+ * counts against - send a reference and let the receiver fetch the payload.
297
+ * Throws if the bus is closed.
298
+ */
299
+ async broadcast(topic, input) {
300
+ if (!topic.trim())
301
+ throw new TypeError("Topic must not be empty");
302
+ if (!input.type.trim())
303
+ throw new TypeError("Message type must not be empty");
304
+ if (!object.isSerializableValue(input.metadata ?? {}) ||
305
+ !object.isSerializableValue(input.body)) {
306
+ throw new TypeError("Message metadata and body must be JSON serializable without coercion");
307
+ }
308
+ if (this.closed)
309
+ throw new Error("Postgres topic bus is closed");
310
+ const automatic = await this.resolveMetadata();
311
+ const message = {
312
+ id: hash.id(),
313
+ topic,
314
+ type: input.type,
315
+ metadata: { ...automatic, ...input.metadata },
316
+ body: input.body,
317
+ publishedAt: new Date().toISOString(),
318
+ };
319
+ let encoded;
320
+ try {
321
+ encoded = JSON.stringify(message);
322
+ }
323
+ catch (cause) {
324
+ throw new TypeError(`Message must be JSON serializable: ${error.errorMessage(cause)}`);
325
+ }
326
+ if (!decode(encoded)) {
327
+ throw new TypeError("Message type, metadata, and body must be JSON serializable");
328
+ }
329
+ if (Buffer.byteLength(encoded, "utf8") > MAX_NOTIFY_BYTES) {
330
+ throw new RangeError(`Postgres notification exceeds ${MAX_NOTIFY_BYTES} bytes`);
331
+ }
332
+ await this.pool.query("SELECT pg_notify($1, $2)", [this.channelName, encoded]);
333
+ return message;
334
+ }
335
+ /**
336
+ * Subscribe to `topic`, returning the function that unsubscribes.
337
+ *
338
+ * Connects on first use. Several listeners may share a topic; each is called
339
+ * once per message. Only messages published AFTER this resolves arrive, so
340
+ * subscribe before triggering whatever you expect to observe.
341
+ *
342
+ * The returned function removes just this listener and is safe to call twice.
343
+ * The connection stays open once the last listener leaves - {@link close}
344
+ * releases it - so a bus that subscribes and unsubscribes per request does not
345
+ * churn connections.
346
+ */
347
+ async listen(topic, listener) {
348
+ if (!topic.trim())
349
+ throw new TypeError("Topic must not be empty");
350
+ await this.start();
351
+ const listeners = this.listeners.get(topic) ?? new Set();
352
+ listeners.add(listener);
353
+ this.listeners.set(topic, listeners);
354
+ return async () => {
355
+ listeners.delete(listener);
356
+ if (listeners.size === 0)
357
+ this.listeners.delete(topic);
358
+ };
359
+ }
360
+ /**
361
+ * Build the automatic half of a message's metadata.
362
+ *
363
+ * Precedence, weakest first: machine/process context, then AppKit sender
364
+ * identity, then this bus's configured metadata. The caller's per-message
365
+ * metadata is layered over the result in {@link broadcast}, so the most specific
366
+ * source always wins and nothing here can overwrite an explicit key.
367
+ */
368
+ async resolveMetadata() {
369
+ const sender = await senderMetadata();
370
+ const configured = typeof this.metadata === "function" ? await this.metadata() : (this.metadata ?? {});
371
+ return { ...machineMetadata(), ...sender, ...configured };
372
+ }
373
+ /**
374
+ * Release the notification connection and stop delivering messages. Idempotent.
375
+ *
376
+ * Cancels any pending reconnect, drops all listeners, then `UNLISTEN`s and
377
+ * returns the client to the pool. A failed `UNLISTEN` is reported to the pool as
378
+ * a release error so the connection is DISCARDED rather than handed to the next
379
+ * caller still subscribed to the channel. Does not throw; the bus stays closed.
380
+ */
381
+ async close() {
382
+ if (this.closed)
383
+ return;
384
+ this.closed = true;
385
+ this.reconnectAbort.abort(new Error("Postgres topic bus is closed"));
386
+ await this.starting?.catch(() => undefined);
387
+ await this.reconnecting?.catch(() => undefined);
388
+ const client = this.client;
389
+ this.client = undefined;
390
+ this.listeners.clear();
391
+ if (!client)
392
+ return;
393
+ client.removeListener("notification", this.handleNotification);
394
+ client.removeListener("error", this.handleClientError);
395
+ let releaseError;
396
+ try {
397
+ await client.query(`UNLISTEN ${quoteIdentifier(this.channelName)}`);
398
+ }
399
+ catch (cause) {
400
+ releaseError = error.toError(cause);
401
+ }
402
+ client.release(releaseError);
403
+ }
404
+ /**
405
+ * Check out one client, attach the handlers, and `LISTEN`.
406
+ *
407
+ * The handlers are attached BEFORE the `LISTEN` round trip so a notification or
408
+ * error arriving mid-setup is not missed. Any failure - including the bus being
409
+ * closed while the connect was in flight - detaches the handlers and releases
410
+ * the client as errored, so a half-configured connection never returns to the
411
+ * pool.
412
+ */
413
+ async connect() {
414
+ const client = await this.pool.connect();
415
+ try {
416
+ client.on("notification", this.handleNotification);
417
+ client.on("error", this.handleClientError);
418
+ await client.query(`LISTEN ${quoteIdentifier(this.channelName)}`);
419
+ if (this.closed)
420
+ throw new Error("Postgres topic bus is closed");
421
+ this.client = client;
422
+ }
423
+ catch (cause) {
424
+ client.removeListener("notification", this.handleNotification);
425
+ client.removeListener("error", this.handleClientError);
426
+ client.release(error.toError(cause));
427
+ throw cause;
428
+ }
429
+ }
430
+ /**
431
+ * Route one inbound notification to the topic's listeners.
432
+ *
433
+ * Ignores other channels and undecodable payloads - the channel is shared, so
434
+ * both are ordinary traffic. Listeners are invoked concurrently and their
435
+ * rejections go to `onError`, keeping one slow or broken subscriber from
436
+ * stalling the notification connection.
437
+ */
438
+ handleNotification = (notification) => {
439
+ if (notification.channel !== this.channelName)
440
+ return;
441
+ const message = decode(notification.payload);
442
+ if (!message)
443
+ return;
444
+ for (const listener of this.listeners.get(message.topic) ?? []) {
445
+ Promise.resolve(listener(message)).catch(this.onError);
446
+ }
447
+ };
448
+ /**
449
+ * Handle the notification connection dying, which `pg` reports as an `error`
450
+ * event rather than a rejected query.
451
+ *
452
+ * The client is unusable at this point, so it is detached and released as
453
+ * errored (which discards it) before anything else. Reconnection only starts
454
+ * when there is still someone to deliver to, so an idle or closing bus does not
455
+ * hold a connection open chasing a channel nobody reads.
456
+ */
457
+ handleClientError = (cause) => {
458
+ this.onError(cause);
459
+ const client = this.client;
460
+ if (!client)
461
+ return;
462
+ this.client = undefined;
463
+ client.removeListener("notification", this.handleNotification);
464
+ client.removeListener("error", this.handleClientError);
465
+ client.release(cause);
466
+ if (this.closed || this.listeners.size === 0)
467
+ return;
468
+ this.reconnecting ??= this.reconnect().finally(() => {
469
+ this.reconnecting = undefined;
470
+ });
471
+ };
472
+ /**
473
+ * Re-establish the notification connection with bounded exponential backoff.
474
+ *
475
+ * The first attempt is immediate, since the common case is a single dropped
476
+ * connection that reconnects at once; subsequent delays double from 250ms up to
477
+ * 5s and stay there. Retries indefinitely rather than giving up, because a Postgres restart
478
+ * or a rotated Lakebase credential is a recoverable outage and a silently dead
479
+ * listener is worse than a noisy one. Stops when the bus closes or the last
480
+ * listener leaves, and reports every failed attempt through `onError`.
481
+ */
482
+ async reconnect() {
483
+ let delay = 0;
484
+ while (!this.closed && this.listeners.size > 0) {
485
+ if (delay > 0) {
486
+ try {
487
+ await asyncUtil.sleep(delay, this.reconnectAbort.signal);
488
+ }
489
+ catch {
490
+ return;
491
+ }
492
+ }
493
+ try {
494
+ await this.start();
495
+ return;
496
+ }
497
+ catch (cause) {
498
+ if (this.closed)
499
+ return;
500
+ this.onError(cause);
501
+ delay = delay === 0 ? MIN_RECONNECT_DELAY_MS : Math.min(delay * 2, MAX_RECONNECT_DELAY_MS);
502
+ }
503
+ }
504
+ }
505
+ }
506
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9waWMtYnVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3RvcGljLWJ1cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBd0JHO0FBRUgsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUNuQyxPQUFPLEVBQUUsS0FBSyxJQUFJLFNBQVMsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFXL0Ysb0VBQW9FO0FBQ3BFLE1BQU0sZUFBZSxHQUFHLHFCQUFxQixDQUFDO0FBQzlDOzs7O0dBSUc7QUFDSCxNQUFNLGtCQUFrQixHQUFHLEVBQUUsQ0FBQztBQUM5QixxRkFBcUY7QUFDckYsTUFBTSxtQkFBbUIsR0FBRyxDQUFDLENBQUM7QUFDOUIsMEVBQTBFO0FBQzFFLE1BQU0sZ0JBQWdCLEdBQUcsS0FBSyxDQUFDO0FBQy9COzs7O0dBSUc7QUFDSCxNQUFNLGdCQUFnQixHQUFHLEtBQUssQ0FBQztBQUMvQixNQUFNLHNCQUFzQixHQUFHLEdBQUcsQ0FBQztBQUNuQyxNQUFNLHNCQUFzQixHQUFHLEtBQUssQ0FBQztBQWtCckM7Ozs7R0FJRztBQUNILElBQUksWUFBMkQsQ0FBQztBQTZHaEU7Ozs7R0FJRztBQUNILFNBQVMsZUFBZSxDQUFDLE1BQXFEO0lBQzVFLE9BQU8sTUFBTSxDQUFDLFdBQVcsQ0FDdkIsTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxLQUFLLEVBQXdDLEVBQUU7UUFDNUUsT0FBTyxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssU0FBUyxDQUFDO0lBQ2hDLENBQUMsQ0FBQyxDQUNILENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNILFNBQVMsZUFBZTtJQUN0QixPQUFPLGVBQWUsQ0FBQztR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Q2xELElBQUksQ0FBQyxZQUFZLEdBQUcsU0FBUyxDQUFDO1FBQ2hDLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDO0lBRUY7Ozs7Ozs7OztPQVNHO0lBQ0ssS0FBSyxDQUFDLFNBQVM7UUFDckIsSUFBSSxLQUFLLEdBQUcsQ0FBQyxDQUFDO1FBQ2QsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDL0MsSUFBSSxLQUFLLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ2QsSUFBSSxDQUFDO29CQUNILE1BQU0sU0FBUyxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLGNBQWMsQ0FBQyxNQUFNLENBQUMsQ0FBQztnQkFDM0QsQ0FBQztnQkFBQyxNQUFNLENBQUM7b0JBQ1AsT0FBTztnQkFDVCxDQUFDO1lBQ0gsQ0FBQztZQUNELElBQUksQ0FBQztnQkFDSCxNQUFNLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDbkIsT0FBTztZQUNULENBQUM7WUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO2dCQUNmLElBQUksSUFBSSxDQUFDLE1BQU07b0JBQUUsT0FBTztnQkFDeEIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDcEIsS0FBSyxHQUFHLEtBQUssS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLHNCQUFzQixDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssR0FBRyxDQUFDLEVBQUUsc0JBQXNCLENBQUMsQ0FBQztZQUM3RixDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVG9waWMgZmFuLW91dCBvdmVyIFBvc3RncmVTUUwgYExJU1RFTmAvYE5PVElGWWAsIGZvciB0ZWxsaW5nIGV2ZXJ5IHJ1bm5pbmdcbiAqIGluc3RhbmNlIG9mIGFuIGFwcCB0aGF0IHNvbWV0aGluZyBoYXBwZW5lZC5cbiAqXG4gKiBUaGUgc2libGluZyBgYWR2aXNvcnktbG9ja2AgbW9kdWxlIGlzIGFib3V0IG1ha2luZyBzdXJlIG9ubHkgT05FIGNvbm5lY3Rpb25cbiAqIGRvZXMgYSB0aGluZzsgdGhpcyBvbmUgaXMgdGhlIG9wcG9zaXRlIC0gRVZFUlkgbGlzdGVuaW5nIHNlc3Npb24gZ2V0cyBldmVyeVxuICogbm90aWZpY2F0aW9uLiBUaGF0IG1ha2VzIGl0IHRoZSByaWdodCBwcmltaXRpdmUgZm9yIGxpdmUgVUkgdXBkYXRlc1xuICogKGFuIFNTRSBzdHJlYW0gcGVyIGJyb3dzZXIgdGFiLCBhIGNhY2hlIGludmFsaWRhdGlvbiwgYSBwcmVzZW5jZSBwaW5nKSBhbmQgdGhlXG4gKiB3cm9uZyBvbmUgZm9yIHdvcmsgZGlzdHJpYnV0aW9uOiB0aGVyZSBhcmUgbm8gY29tcGV0aW5nIGNvbnN1bWVycywgbm8gYWNrcywgYW5kXG4gKiBubyByZXBsYXkuXG4gKlxuICogRGVsaXZlcnkgaXMgYmVzdC1lZmZvcnQgYW5kIGxpdmUuIGBOT1RJRllgIHJlYWNoZXMgc2Vzc2lvbnMgdGhhdCBhcmUgbGlzdGVuaW5nXG4gKiBhdCB0aGUgbW9tZW50IGl0IGNvbW1pdHMsIHNvIGEgbGlzdGVuZXIgdGhhdCBjb25uZWN0cyBhIHNlY29uZCBsYXRlciBuZXZlciBzZWVzXG4gKiBpdCwgYW5kIGEgbGlzdGVuZXIgd2hvc2UgY29ubmVjdGlvbiBkcm9wcyBtaXNzZXMgZXZlcnl0aGluZyB1bnRpbCB0aGUgYnVzXG4gKiByZWNvbm5lY3RzLiBVc2UgYSB0YWJsZSBvciBhIHF1ZXVlIHdoZW4gYSBzdWJzY3JpYmVyIG5lZWRzIGR1cmFiaWxpdHkuXG4gKlxuICogT05FIENIQU5ORUwsIE1BTlkgVE9QSUNTLiBFdmVyeSBidXMgaW5zdGFuY2UgbGlzdGVucyBvbiBhIHNpbmdsZSBQb3N0Z3Jlc1xuICogY2hhbm5lbCAoYGNoYW5uZWxgLCBkZWZhdWx0IGBkYnhfdG9vbHNfdG9waWNfYnVzYCkgYW5kIGZpbHRlcnMgYnkgdGhlXG4gKiBlbnZlbG9wZSdzIGB0b3BpY2AgaW4tcHJvY2Vzcywgc28gYWRkaW5nIGEgdG9waWMgY29zdHMgbm8gY29ubmVjdGlvbiBhbmQgbm9cbiAqIGBMSVNURU5gLiBUaGUgdHJhZGVvZmYgaXMgdGhhdCBldmVyeSBsaXN0ZW5pbmcgc2Vzc2lvbiBkZWNvZGVzIGV2ZXJ5IG1lc3NhZ2Ugb25cbiAqIHRoZSBjaGFubmVsOyBnaXZlIGEgZ2VudWluZWx5IGhpZ2gtdm9sdW1lLCB1bnJlbGF0ZWQgc3RyZWFtIGl0cyBvd24gYGNoYW5uZWxgXG4gKiByYXRoZXIgdGhhbiBhIHRvcGljLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBob3N0bmFtZSB9IGZyb20gXCJub2RlOm9zXCI7XG5pbXBvcnQgeyBhc3luYyBhcyBhc3luY1V0aWwsIGVycm9yLCBoYXNoLCBqc29uLCBvYmplY3QsIHN0cmluZyB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5pbXBvcnQgdHlwZSB7IE5vdGlmaWNhdGlvbiwgUG9vbENsaWVudCB9IGZyb20gXCJwZ1wiO1xuXG5pbXBvcnQgdHlwZSB7IFBnUG9vbExpa2UsIFBnUXVlcnlhYmxlIH0gZnJvbSBcIi4vYWR2aXNvcnktbG9jay50c1wiO1xuXG4vKipcbiAqIGBAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlYCBvd25zIHRoZSBKU09OLXJvdW5kLXRyaXAgcnVsZTsgdGhpcyBhbGlhcyBqdXN0IGtlZXBzIHRoZVxuICogZ2VuZXJpYyBzaWduYXR1cmVzIGJlbG93IHJlYWRhYmxlLiBDb25zdW1lcnMgaW1wb3J0IHRoZSB0eXBlIGZyb20gc2hhcmVkLWNvcmUuXG4gKi9cbnR5cGUgU2VyaWFsaXphYmxlVmFsdWUgPSBvYmplY3QuU2VyaWFsaXphYmxlVmFsdWU7XG5cbi8qKiBDaGFubmVsIHBhcnRzIHVzZWQgd2hlbiBhIGNhbGxlciBuYW1lcyBubyBjaGFubmVsIG9mIGl0cyBvd24uICovXG5jb25zdCBERUZBVUxUX0NIQU5ORUwgPSBcImRieF90b29sc190b3BpY19idXNcIjtcbi8qKlxuICogYE5BTUVEQVRBTEVOIC0gMWAuIFBvc3RncmVzIFRSVU5DQVRFUyBhIGxvbmdlciBjaGFubmVsIG5hbWUgcmF0aGVyIHRoYW5cbiAqIHJlamVjdGluZyBpdCwgd2hpY2ggd291bGQgc3BsaXQgcHVibGlzaGVycyBhbmQgbGlzdGVuZXJzIG9udG8gZGlmZmVyZW50XG4gKiBjaGFubmVscyB3aGlsZSBldmVyeSBjYWxsIGxvb2tlZCBsaWtlIGl0IHN1Y2NlZWRlZC5cbiAqL1xuY29uc3QgTUFYX0NIQU5ORUxfTEVOR1RIID0gNjM7XG4vKiogQmFzZS0zMiBjaGFycyBvZiB0aGUgY2hhbm5lbCdzIGlkZW50aXR5IHN1ZmZpeC4gTWF4IDcgLSB0aGUgZGlnZXN0IGlzIDMyIGJpdHMuICovXG5jb25zdCBDSEFOTkVMX0hBU0hfTEVOR1RIID0gNjtcbi8qKiBCb2R5IHVzZWQgd2hlbiB0aGUgcGFydHMgdG9rZW5pemUgdG8gbm90aGluZywgb3IgbGVhZCB3aXRoIGEgZGlnaXQuICovXG5jb25zdCBDSEFOTkVMX0ZBTExCQUNLID0gXCJidXNcIjtcbi8qKlxuICogRW5jb2RlZC1lbnZlbG9wZSBjZWlsaW5nLiBQb3N0Z3JlU1FMIGNhcHMgYSBgTk9USUZZYCBwYXlsb2FkIGF0IDgwMDAgYnl0ZXMgYW5kXG4gKiBmYWlscyB0aGUgc3RhdGVtZW50IHBhc3QgdGhhdCwgc28gdGhlIGJ1cyByZWplY3RzIHRoZSBtZXNzYWdlIGZpcnN0IHdpdGggYSBzaXplXG4gKiBpdCBjYW4gbmFtZS4gVGhlIG1hcmdpbiBiZWxvdyA4MDAwIGNvdmVycyB0aGUgc2VydmVyJ3Mgb3duIGFjY291bnRpbmcuXG4gKi9cbmNvbnN0IE1BWF9OT1RJRllfQllURVMgPSA3XzkwMDtcbmNvbnN0IE1JTl9SRUNPTk5FQ1RfREVMQVlfTVMgPSAyNTA7XG5jb25zdCBNQVhfUkVDT05ORUNUX0RFTEFZX01TID0gNV8wMDA7XG5cbi8qKlxuICogVGhlIHN1YnNldCBvZiBBcHBLaXQncyBwZXItcmVxdWVzdCBleGVjdXRpb24gY29udGV4dCB0aGUgYnVzIHJlYWRzIGZvciBzZW5kZXJcbiAqIGlkZW50aXR5LiBGaWVsZHMgYXJlIGB1bmtub3duYCBiZWNhdXNlIHRoaXMgaXMgYSBzdHJ1Y3R1cmFsIHZpZXcgb2YgYW4gT1BUSU9OQUxcbiAqIHBlZXI6IHRoZSB2YWx1ZXMgYXJlIHRyaW1tZWQgYW5kIHZhbGlkYXRlZCByYXRoZXIgdGhhbiB0cnVzdGVkLlxuICovXG50eXBlIEFwcEtpdEV4ZWN1dGlvbkNvbnRleHQgPSB7XG4gIHVzZXJFbWFpbD86IHVua25vd247XG4gIHVzZXJJZD86IHVua25vd247XG4gIHVzZXJOYW1lPzogdW5rbm93bjtcbn07XG5cbi8qKiBTdHJ1Y3R1cmFsIHZpZXcgb2YgYEBkYXRhYnJpY2tzL2FwcGtpdGAsIGltcG9ydGVkIGxhemlseSBhbmQgbmV2ZXIgcmVxdWlyZWQuICovXG50eXBlIEFwcEtpdE1vZHVsZSA9IHtcbiAgZ2V0RXhlY3V0aW9uQ29udGV4dCgpOiBBcHBLaXRFeGVjdXRpb25Db250ZXh0O1xufTtcblxuLyoqXG4gKiBDYWNoZWQgcmVzdWx0IG9mIHRoZSBvbmUgb3B0aW9uYWwtcGVlciBpbXBvcnQsIHJlc29sdmVkIHRvIGB1bmRlZmluZWRgIHdoZW5cbiAqIEFwcEtpdCBpcyBub3QgaW5zdGFsbGVkLiBNZW1vaXplZCBzbyBhIGJ1cyBpbiBhIHBsYWluIFBvc3RncmVzIHByb2Nlc3MgcGF5cyBmb3JcbiAqIHRoZSBmYWlsZWQgcmVzb2x1dGlvbiBvbmNlIGluc3RlYWQgb2YgcGVyIGJyb2FkY2FzdC5cbiAqL1xubGV0IGFwcEtpdE1vZHVsZTogUHJvbWlzZTxBcHBLaXRNb2R1bGUgfCB1bmRlZmluZWQ+IHwgdW5kZWZpbmVkO1xuXG4vKipcbiAqIEZsYXQta2V5ZWQgY29udGV4dCB0cmF2ZWxsaW5nIGFsb25nc2lkZSBhIG1lc3NhZ2UgYm9keTogd2hvIHNlbnQgaXQsIGZyb21cbiAqIHdoZXJlLCBpbiB3aGljaCBkZXBsb3ltZW50LiBWYWx1ZXMgbWF5IG5lc3QsIGJ1dCB0aGUga2V5cyBhcmUgdGhlIGFkZHJlc3NhYmxlXG4gKiBwYXJ0IC0gYSBsaXN0ZW5lciBmaWx0ZXJpbmcgb3IgbGFiZWxsaW5nIG1lc3NhZ2VzIHJlYWRzIGBtZXRhZGF0YS51c2VyYCwgbm90IGFcbiAqIHBhdGggaW50byB0aGUgYm9keS5cbiAqL1xuZXhwb3J0IHR5cGUgVG9waWNNZXRhZGF0YSA9IFJlY29yZDxzdHJpbmcsIFNlcmlhbGl6YWJsZVZhbHVlPjtcblxuLyoqXG4gKiBUaGUgd2lyZSBlbnZlbG9wZSBldmVyeSBzdWJzY3JpYmVyIHJlY2VpdmVzLCBhbmQgd2hhdCB7QGxpbmtcbiAqIFBvc3RncmVzVG9waWNCdXMuYnJvYWRjYXN0fSByZXR1cm5zIHRvIHRoZSBwdWJsaXNoZXIuXG4gKlxuICogYGlkYCwgYHRvcGljYCwgYW5kIGBwdWJsaXNoZWRBdGAgYXJlIGFzc2lnbmVkIGJ5IHRoZSBidXM7IGB0eXBlYCwgYG1ldGFkYXRhYCxcbiAqIGFuZCBgYm9keWAgY29tZSBmcm9tIHRoZSBjYWxsZXIgKHdpdGggYXV0b21hdGljIGNvbnRleHQgbWVyZ2VkIHVuZGVyXG4gKiBgbWV0YWRhdGFgKS4gVGhlIHNoYXBlIGlzIHN0YWJsZSBlbm91Z2ggdG8gaGFuZCBzdHJhaWdodCB0byBhbiBTU0UgYGRhdGE6YFxuICogZnJhbWUuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVG9waWNNZXNzYWdlPFRCb2R5IGV4dGVuZHMgU2VyaWFsaXphYmxlVmFsdWUgPSBTZXJpYWxpemFibGVWYWx1ZT4ge1xuICAvKipcbiAgICogUGVyLW1lc3NhZ2UgaWRlbnRpdHkgZ2VuZXJhdGVkIGJ5IHRoZSBwdWJsaXNoZXIsIHVuaXF1ZSBhY3Jvc3MgaW5zdGFuY2VzLlxuICAgKiBTdWl0YWJsZSBmb3IgZGVkdXBlIHdoZW4gYSBjbGllbnQgcmVjb25uZWN0cyBhbmQgZm9yIGFuIFNTRSBgaWQ6YCBmaWVsZC4gTm90XG4gICAqIG9yZGVyZWQsIGFuZCBub3QgYSBkYXRhYmFzZSBrZXkuXG4gICAqL1xuICBpZDogc3RyaW5nO1xuICAvKiogVGhlIHRvcGljIHRoaXMgd2FzIGJyb2FkY2FzdCBvbjsgbGlzdGVuZXJzIG9uIG90aGVyIHRvcGljcyBuZXZlciBzZWUgaXQuICovXG4gIHRvcGljOiBzdHJpbmc7XG4gIC8qKiBDYWxsZXItY2hvc2VuIGV2ZW50IG5hbWUsIGUuZy4gYG9yZGVyLnVwZGF0ZWRgLiBOZXZlciBlbXB0eS4gKi9cbiAgdHlwZTogc3RyaW5nO1xuICAvKiogQXV0b21hdGljIGNvbnRleHQgbWVyZ2VkIHdpdGggY2FsbGVyIG1ldGFkYXRhLiBTZWUge0BsaW5rIFRvcGljTWV0YWRhdGF9LiAqL1xuICBtZXRhZGF0YTogVG9waWNNZXRhZGF0YTtcbiAgLyoqIFRoZSBjYWxsZXIncyBwYXlsb2FkLCB1bmNoYW5nZWQuICovXG4gIGJvZHk6IFRCb2R5O1xuICAvKipcbiAgICogSVNPLTg2MDEgcHVibGlzaCB0aW1lIGZyb20gdGhlIFBVQkxJU0hJTkcgcHJvY2VzcydzIGNsb2NrLCBub3QgdGhlIGRhdGFiYXNlJ3MuXG4gICAqIEZpbmUgZm9yIGRpc3BsYXk7IGRvIG5vdCBvcmRlciBtZXNzYWdlcyBmcm9tIGRpZmZlcmVudCBpbnN0YW5jZXMgYnkgaXQuXG4gICAqL1xuICBwdWJsaXNoZWRBdDogc3RyaW5nO1xufVxuXG4vKiogV2hhdCBhIGNhbGxlciBzdXBwbGllcyB0byB7QGxpbmsgUG9zdGdyZXNUb3BpY0J1cy5icm9hZGNhc3R9LiAqL1xuZXhwb3J0IGludGVyZmFjZSBUb3BpY1B1Ymxpc2hJbnB1dDxUQm9keSBleHRlbmRzIFNlcmlhbGl6YWJsZVZhbHVlID0gU2VyaWFsaXphYmxlVmFsdWU+IHtcbiAgLyoqIEV2ZW50IG5hbWUsIGUuZy4gYGNoYXQubWVzc2FnZWAuIE11c3QgYmUgbm9uLWJsYW5rLiAqL1xuICB0eXBlOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBDb250ZXh0IHRvIGF0dGFjaC4gV2lucyBvdmVyIGFueSBhdXRvbWF0aWMga2V5IG9mIHRoZSBzYW1lIG5hbWUsIHNvIGEgY2FsbGVyXG4gICAqIGNhbiBvdmVycmlkZSBhIG1hY2hpbmUgZGVmYXVsdCAoYHByb2plY3RgKSBvciBhZGQgaXRzIG93biAoYHRyYWNlSWRgKS5cbiAgICovXG4gIG1ldGFkYXRhPzogVG9waWNNZXRhZGF0YTtcbiAgLyoqIFRoZSBwYXlsb2FkLiBNdXN0IHNhdGlzZnkgYG9iamVjdC5pc1NlcmlhbGl6YWJsZVZhbHVlYC4gKi9cbiAgYm9keTogVEJvZHk7XG59XG5cbi8qKlxuICogU3Vic2NyaWJlciBjYWxsYmFjay4gSW52b2tlZCBvbmNlIHBlciBtYXRjaGluZyBtZXNzYWdlIG9uIHRoZSBub3RpZmljYXRpb25cbiAqIGNvbm5lY3Rpb24ncyBjYWxsYmFjaywgc28gaXQgc2hvdWxkIG5vdCBibG9jazogYSByZXR1cm5lZCBwcm9taXNlIGlzIGF3YWl0ZWRcbiAqIG9ubHkgdG8gcm91dGUgYSByZWplY3Rpb24gdG8gYG9uRXJyb3JgLCBhbmQgbGlzdGVuZXJzIGZvciBvbmUgbWVzc2FnZSBydW5cbiAqIGNvbmN1cnJlbnRseSByYXRoZXIgdGhhbiBpbiByZWdpc3RyYXRpb24gb3JkZXIuXG4gKlxuICogYFRCb2R5YCBpcyB1bmNoZWNrZWQgYXQgcnVudGltZS4gVGhlIGJ1cyBndWFyYW50ZWVzIHRoZSBib2R5IGlzIHNlcmlhbGl6YWJsZSxcbiAqIG5vdCB0aGF0IGl0IG1hdGNoZXMgdGhlIHR5cGUgcGFyYW1ldGVyLCBzbyB2YWxpZGF0ZSBhbnl0aGluZyBhIGxpc3RlbmVyXG4gKiBicmFuY2hlcyBvbi5cbiAqL1xuZXhwb3J0IHR5cGUgVG9waWNMaXN0ZW5lcjxUQm9keSBleHRlbmRzIFNlcmlhbGl6YWJsZVZhbHVlID0gU2VyaWFsaXphYmxlVmFsdWU+ID0gKFxuICBtZXNzYWdlOiBUb3BpY01lc3NhZ2U8VEJvZHk+LFxuKSA9PiB2b2lkIHwgUHJvbWlzZUxpa2U8dm9pZD47XG5cbi8qKlxuICogUmVzb2x2ZXMgbWV0YWRhdGEgYXQgcHVibGlzaCB0aW1lIGluc3RlYWQgb2YgY29uc3RydWN0aW9uIHRpbWUsIGZvciBjb250ZXh0IGFcbiAqIHByb2Nlc3MgbGVhcm5zIGxhdGUgb3IgYXN5bmNocm9ub3VzbHkgLSBhIGRpc2NvdmVyZWQgcHVibGljIElQLCBhbiBpbnN0YW5jZSBpZFxuICogZnJvbSBhIGNvbnRyb2wgcGxhbmUuIENhbGxlZCBvbiBldmVyeSBicm9hZGNhc3QsIHNvIG1lbW9pemUgYW55dGhpbmcgZXhwZW5zaXZlO1xuICogYSByZWplY3Rpb24gZmFpbHMgdGhlIGJyb2FkY2FzdC5cbiAqL1xuZXhwb3J0IHR5cGUgVG9waWNNZXRhZGF0YVByb3ZpZGVyID0gKCkgPT4gVG9waWNNZXRhZGF0YSB8IFByb21pc2VMaWtlPFRvcGljTWV0YWRhdGE+O1xuXG4vKiogQ29uc3RydWN0aW9uIG9wdGlvbnMgZm9yIHtAbGluayBQb3N0Z3Jlc1RvcGljQnVzfS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUG9zdGdyZXNUb3BpY0J1c09wdGlvbnMge1xuICAvKipcbiAgICogV2hhdCBpZGVudGlmaWVzIHRoaXMgY2hhbm5lbCAtIGFueXRoaW5nLCBub3QganVzdCBhbiBpZGVudGlmaWVyOiBhIG5hbWUsIGFuXG4gICAqIGlkLCBhIGBbZW52LCBmZWF0dXJlXWAgcGFpciwgYSBjb25maWcgb2JqZWN0LiBUaGUgcGFydHMgYXJlIHRva2VuaXplZCBpbnRvIGFcbiAgICogbGVnYWwgUG9zdGdyZXMgY2hhbm5lbCBuYW1lIHdpdGggYSBzaG9ydCBoYXNoIG9mIHRoZSBvcmlnaW5hbHMgYXBwZW5kZWQsIHNvXG4gICAqIHRoZSBkZXJpdmF0aW9uIGlzIGRldGVybWluaXN0aWMgYW5kIG5vIGNhbGwgc2l0ZSBoYXMgdG8gc2FuaXRpemUuIFNlZVxuICAgKiB7QGxpbmsgUG9zdGdyZXNUb3BpY0J1cy5jaGFubmVsTmFtZX0gZm9yIHRoZSByZXNvbHZlZCBuYW1lLlxuICAgKlxuICAgKiBPbmUgdmFsdWUgb3IgbWFueTogYW4gYXJyYXkgaXMgcmVhZCBhcyBtdWx0aXBsZSBwYXJ0c1xuICAgKiAoe0BsaW5rIG9iamVjdC5PbmVPck1hbnl9KSwgYW55dGhpbmcgZWxzZSBhcyBhIHNpbmdsZSBwYXJ0LiBTb1xuICAgKiBgW1wiYmlsbGluZ1wiLCBcInByb2RcIl1gIGFuZCBgXCJiaWxsaW5nX3Byb2RcImAgYXJlIGRpZmZlcmVudCBjaGFubmVscywgc2luY2UgdGhlXG4gICAqIGhhc2ggc2VlcyBkaWZmZXJlbnQgc3RydWN0dXJlLlxuICAgKlxuICAgKiBFdmVyeSBwYXJ0aWNpcGF0aW5nIHByb2Nlc3MgbXVzdCBwYXNzIEVRVUlWQUxFTlQgcGFydHMsIHNpbmNlIGEgZGlmZmVyZW50XG4gICAqIHNwZWxsaW5nIGhhc2hlcyB0byBhIGRpZmZlcmVudCBjaGFubmVsLiBEZWZhdWx0cyB0byBhIHNoYXJlZFxuICAgKiBgZGJ4X3Rvb2xzX3RvcGljX2J1c2AgY2hhbm5lbC5cbiAgICovXG4gIGNoYW5uZWw/OiB1bmtub3duO1xuICAvKipcbiAgICogRXh0cmEgY29udGV4dCBhZGRlZCB0byBldmVyeSBtZXNzYWdlIHRoaXMgYnVzIHB1Ymxpc2hlcywgZWl0aGVyIGEgZml4ZWRcbiAgICogcmVjb3JkIG9yIGEge0BsaW5rIFRvcGljTWV0YWRhdGFQcm92aWRlcn0gY2FsbGVkIHBlciBicm9hZGNhc3QuIE92ZXJyaWRlc1xuICAgKiBhdXRvbWF0aWMgbWFjaGluZSBrZXlzOyBwZXItY2FsbCBgbWV0YWRhdGFgIG92ZXJyaWRlcyB0aGlzLlxuICAgKi9cbiAgbWV0YWRhdGE/OiBUb3BpY01ldGFkYXRhIHwgVG9waWNNZXRhZGF0YVByb3ZpZGVyO1xuICAvKipcbiAgICogU2luayBmb3IgZmFpbHVyZXMgdGhhdCBoYXZlIG5vIGNhbGxlciB0byB0aHJvdyB0bzogYSBsaXN0ZW5lciB0aGF0IHJlamVjdGVkLFxuICAgKiBhIGRyb3BwZWQgbm90aWZpY2F0aW9uIGNvbm5lY3Rpb24sIGEgZmFpbGVkIHJlY29ubmVjdCBhdHRlbXB0LiBEZWZhdWx0cyB0b1xuICAgKiBzd2FsbG93aW5nIHRoZW0sIHNvIHdpcmUgdGhpcyB0byBhIGxvZ2dlciBpbiBhbnl0aGluZyBsb25nLXJ1bm5pbmcuXG4gICAqL1xuICBvbkVycm9yPzogKGNhdXNlOiB1bmtub3duKSA9PiB2b2lkO1xufVxuXG4vKipcbiAqIERyb3Aga2V5cyB3aG9zZSB2YWx1ZSBpcyBgdW5kZWZpbmVkYCwgc28gYW4gdW5zZXQgZW52aXJvbm1lbnQgdmFyaWFibGUgbGVhdmVzXG4gKiB0aGUga2V5IEFCU0VOVCByYXRoZXIgdGhhbiBwcmVzZW50LWFuZC1udWxsLiBBYnNlbmNlIGlzIHdoYXQgbGV0cyBjYWxsZXJcbiAqIG1ldGFkYXRhIGFuZCBsYXRlciBtZXJnZSBsYXllcnMgc3VwcGx5IHRoZSBrZXkgaW5zdGVhZC5cbiAqL1xuZnVuY3Rpb24gZGVmaW5lZE1ldGFkYXRhKHZhbHVlczogUmVjb3JkPHN0cmluZywgU2VyaWFsaXphYmxlVmFsdWUgfCB1bmRlZmluZWQ+KTogVG9waWNNZXRhZGF0YSB7XG4gIHJldHVybiBPYmplY3QuZnJvbUVudHJpZXMoXG4gICAgT2JqZWN0LmVudHJpZXModmFsdWVzKS5maWx0ZXIoKGVudHJ5KTogZW50cnkgaXMgW3N0cmluZywgU2VyaWFsaXphYmxlVmFsdWVdID0+IHtcbiAgICAgIHJldHVybiBlbnRyeVsxXSAhPT0gdW5kZWZpbmVkO1xuICAgIH0pLFxuICApO1xufVxuXG4vKipcbiAqIENvbnRleHQgZXZlcnkgbWVzc2FnZSBnZXRzIGZvciBmcmVlOiB3aGljaCBwcm9qZWN0LCBob3N0LCBwcm9jZXNzLCBhbmRcbiAqIGRlcGxveW1lbnQgcHVibGlzaGVkIGl0LlxuICpcbiAqIFJlYWQgZnJlc2ggcGVyIGJyb2FkY2FzdCByYXRoZXIgdGhhbiBjYWNoZWQsIGJlY2F1c2UgYSBsb25nLWxpdmVkIHByb2Nlc3MgY2FuXG4gKiBiZSByZS1wYXJlbnRlZCAoYSBkZXBsb3ltZW50IGlkIGFwcGVhcmluZyBhZnRlciBib290KS4gS2V5cyB0aGF0IHJlc29sdmUgdG9cbiAqIG5vdGhpbmcgYXJlIG9taXR0ZWQuIFB1YmxpYyBJUCBpcyBvbmx5IHJlYWQgZnJvbSB0aGUgZW52aXJvbm1lbnQgaGVyZSAtIHRoZSBidXNcbiAqIG5ldmVyIG1ha2VzIGEgbmV0d29yayBjYWxsIHRvIGRpc2NvdmVyIGl0OyBhIHByb2Nlc3MgdGhhdCB3YW50cyBhIGRpc2NvdmVyZWQgSVBcbiAqIHBhc3NlcyBhIHtAbGluayBUb3BpY01ldGFkYXRhUHJvdmlkZXJ9LlxuICpcbiAqIERlbGliZXJhdGVseSBOT1QgaW5jbHVkZWQ6IENQVSBhcmNoaXRlY3R1cmUsIHJ1bnRpbWUgbmFtZSwgYW5kIHJ1bnRpbWUgdmVyc2lvbi5cbiAqIFRoZXkgYXJlIGNvbnN0YW50IHBlciBkZXBsb3ltZW50IGFuZCBjb3N0IHBheWxvYWQgYnl0ZXMgYWdhaW5zdCB0aGUgYE5PVElGWWBcbiAqIGxpbWl0IG9uIGV2ZXJ5IHNpbmdsZSBtZXNzYWdlLlxuICovXG5mdW5jdGlvbiBtYWNoaW5lTWV0YWRhdGEoKTogVG9waWNNZXRhZGF0YSB7XG4gIHJldHVybiBkZWZpbmVkTWV0YWRhdGEoe1xuICAgIHByb2plY3Q6XG4gICAgICBzdHJpbmcuZmlyc3ROb25FbXB0eShbXG4gICAgICAgIHByb2Nlc3MuZW52LkRBVEFCUklDS1NfQVBQX05BTUUsXG4gICAgICAgIHByb2Nlc3MuZW52LkRBVEFCUklDS1NfQlVORExFX05BTUUsXG4gICAgICAgIHByb2Nlc3MuZW52LlBST0pFQ1RfTkFNRSxcbiAgICAgICAgcHJvY2Vzcy5lbnYubnBtX3BhY2thZ2VfbmFtZSxcbiAgICAgIF0pID8/IHVuZGVmaW5lZCxcbiAgICBwdWJsaWNJcDpcbiAgICAgIHN0cmluZy5maXJzdE5vbkVtcHR5KFtcbiAgICAgICAgcHJvY2Vzcy5lbnYuUFVCTElDX0lQLFxuICAgICAgICBwcm9jZXNzLmVudi5EQVRBQlJJQ0tTX1BVQkxJQ19JUCxcbiAgICAgICAgcHJvY2Vzcy5lbnYuSE9TVF9JUCxcbiAgICAgIF0pID8/IHVuZGVmaW5lZCxcbiAgICBob3N0bmFtZTogaG9zdG5hbWUoKSxcbiAgICBjd2Q6IHByb2Nlc3MuY3dkKCksXG4gICAgcGxhdGZvcm06IHByb2Nlc3MucGxhdGZvcm0sXG4gICAgcGlkOiBwcm9jZXNzLnBpZCxcbiAgICBlbnZpcm9ubWVudDogc3RyaW5nLnRyaW1Ub051bGwocHJvY2Vzcy5lbnYuTk9ERV9FTlYpID8/IHVuZGVmaW5lZCxcbiAgICBhcHBOYW1lOiBzdHJpbmcudHJpbVRvTnVsbChwcm9jZXNzLmVudi5EQVRBQlJJQ0tTX0FQUF9OQU1FKSA/PyB1bmRlZmluZWQsXG4gICAgZGVwbG95bWVudElkOiBzdHJpbmcudHJpbVRvTnVsbChwcm9jZXNzLmVudi5EQVRBQlJJQ0tTX0FQUF9ERVBMT1lNRU5UX0lEKSA/PyB1bmRlZmluZWQsXG4gICAgZGF0YWJyaWNrc0hvc3Q6IHN0cmluZy50cmltVG9OdWxsKHByb2Nlc3MuZW52LkRBVEFCUklDS1NfSE9TVCkgPz8gdW5kZWZpbmVkLFxuICB9KTtcbn1cblxuLyoqXG4gKiBJZGVudGl0eSBvZiB0aGUgc2lnbmVkLWluIHVzZXIgb24gd2hvc2UgYmVoYWxmIHRoaXMgYnJvYWRjYXN0IGhhcHBlbnMsIHdoZW4gdGhlXG4gKiBwcm9jZXNzIGNhbiB0ZWxsLlxuICpcbiAqIGBAZGF0YWJyaWNrcy9hcHBraXRgIGlzIGFuIE9QVElPTkFMIHBlZXIsIHNvIHRoZSBpbXBvcnQgaXMgbGF6eSBhbmQgYSBtaXNzaW5nXG4gKiBtb2R1bGUgaXMgbm90IGFuIGVycm9yIC0gdGhpcyBpcyBhIHBsYWluIFBvc3RncmVzIHBhY2thZ2UgdGhhdCBhZGRzIHNlbmRlclxuICogaWRlbnRpdHkgd2hlbiBpdCBoYXBwZW5zIHRvIHJ1biBpbnNpZGUgYW4gQXBwS2l0IGFwcC4gT3V0c2lkZSBhbiBhY3RpdmVcbiAqIHBlci1yZXF1ZXN0IGV4ZWN1dGlvbiBjb250ZXh0IEFwcEtpdCB0aHJvd3MsIHdoaWNoIG1lYW5zIFwibm8gdXNlciBoZXJlXCIsIHNvIHRoZVxuICogcmVzdWx0IGlzIGVtcHR5IG1ldGFkYXRhIHJhdGhlciB0aGFuIGEgZmFpbGVkIGJyb2FkY2FzdC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gc2VuZGVyTWV0YWRhdGEoKTogUHJvbWlzZTxUb3BpY01ldGFkYXRhPiB7XG4gIGFwcEtpdE1vZHVsZSA/Pz0gaW1wb3J0KFwiQGRhdGFicmlja3MvYXBwa2l0XCIpXG4gICAgLnRoZW4oKG1vZHVsZSkgPT4gbW9kdWxlIGFzIEFwcEtpdE1vZHVsZSlcbiAgICAuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgY29uc3QgYXBwa2l0ID0gYXdhaXQgYXBwS2l0TW9kdWxlO1xuICBpZiAoIWFwcGtpdCkgcmV0dXJuIHt9O1xuICB0cnkge1xuICAgIGNvbnN0IGNvbnRleHQgPSBhcHBraXQuZ2V0RXhlY3V0aW9uQ29udGV4dCgpO1xuICAgIHJldHVybiBkZWZpbmVkTWV0YWRhdGEoe1xuICAgICAgc2VuZGVySWQ6IHN0cmluZy50cmltVG9OdWxsKGNvbnRleHQudXNlcklkKSA/PyB1bmRlZmluZWQsXG4gICAgICBzZW5kZXJOYW1lOiBzdHJpbmcudHJpbVRvTnVsbChjb250ZXh0LnVzZXJOYW1lKSA/PyB1bmRlZmluZWQsXG4gICAgICBzZW5kZXJFbWFpbDogc3RyaW5nLnRyaW1Ub051bGwoY29udGV4dC51c2VyRW1haWwpID8/IHVuZGVmaW5lZCxcbiAgICB9KTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHt9O1xuICB9XG59XG5cbi8qKlxuICogRGVyaXZlIGEgbGVnYWwgUG9zdGdyZXMgY2hhbm5lbCBuYW1lIGZyb20gd2hhdGV2ZXIgYSBjYWxsZXIgdXNlZCB0byBpZGVudGlmeVxuICogdGhlIGNoYW5uZWwuXG4gKlxuICogQ2FsbGVycyB0aGluayBpbiB0ZXJtcyBvZiB3aGF0IHRoZSBjaGFubmVsIElTIC0gYW4gYXBwIG5hbWUsIGEgdGVuYW50IGlkLCBhXG4gKiBgW2VudiwgZmVhdHVyZV1gIHBhaXIsIGEgY29uZmlnIG9iamVjdCAtIGFuZCBub25lIG9mIHRob3NlIGFyZSBpZGVudGlmaWVycy5cbiAqIFJlamVjdGluZyB0aGVtIHB1c2hlZCB0aGUgc2FuaXRpemluZyBvbnRvIGV2ZXJ5IGNhbGwgc2l0ZSwgd2hpY2ggaXMgaG93IHR3b1xuICogc2VydmljZXMgZW5kIHVwIGRpc2FncmVlaW5nIGFib3V0IHdoZXRoZXIgdGhlIGNoYW5uZWwgaXMgYG15LWFwcGAsIGBteV9hcHBgLFxuICogb3IgYG15QXBwYCBhbmQgc2lsZW50bHkgbmV2ZXIgaGVhciBlYWNoIG90aGVyLlxuICpcbiAqIFRoZSBwYXJ0cyBhcmUgdG9rZW5pemVkIGFuZCBqb2luZWQgaW50byBhbiBpZGVudGlmaWVyLCB0aGVuIGEgc2hvcnQgaGFzaCBvZiB0aGVcbiAqIE9SSUdJTkFMIHBhcnRzIGlzIGFwcGVuZGVkLiBUaGUgaGFzaCBpcyB3aGF0IG1ha2VzIHRoZSBtYXBwaW5nIHRydXN0d29ydGh5OlxuICogdG9rZW5pemluZyBhbG9uZSBpcyBsb3NzeSwgc28gYG15LWFwcGAgYW5kIGBteV9hcHBgIGFuZCBgbXlBcHBgIHdvdWxkIGNvbGxhcHNlXG4gKiBvbnRvIG9uZSBjaGFubmVsLCBhbmQgYSBuYW1lIGxvbmcgZW5vdWdoIHRvIGhpdCBgTkFNRURBVEFMRU5gIHdvdWxkIGNvbGxpZGVcbiAqIHdpdGggYW55dGhpbmcgc2hhcmluZyBpdHMgbGVhZGluZyB0b2tlbnMuIFdpdGggdGhlIHN1ZmZpeCwgdGhlIHJlYWRhYmxlIHBhcnRcbiAqIHN0YXlzIHJlYWRhYmxlIGFuZCBkaXN0aW5jdCBpbnB1dHMgc3RheSBkaXN0aW5jdC5cbiAqXG4gKiBEZXRlcm1pbmlzdGljIGFjcm9zcyBwcm9jZXNzZXMgYW5kIHJ1bnMsIHdoaWNoIGlzIHRoZSB3aG9sZSBwb2ludCAtIHR3b1xuICogc2VydmljZXMgZ2l2ZW4gdGhlIHNhbWUgcGFydHMgbXVzdCBsYW5kIG9uIHRoZSBzYW1lIGNoYW5uZWwgd2l0aG91dFxuICogY29vcmRpbmF0aW5nLiBIYXNoIGlucHV0cyBhcmUgc3RydWN0dXJlLWF3YXJlLCBzbyBgW1wiYVwiLCBcImJcIl1gIGFuZCBgW1wiYV9iXCJdYFxuICogZGlmZmVyLCBhbmQgb2JqZWN0IGtleSBvcmRlciBkb2VzIG5vdC5cbiAqL1xuZnVuY3Rpb24gY2hhbm5lbE5hbWUocGFydHM6IG9iamVjdC5PbmVPck1hbnk8dW5rbm93bj4pOiBzdHJpbmcge1xuICAvLyBIYXNoIHRoZSBDQU5PTklDQUwgZm9ybSwgdGhlIHNhbWUgcnVsZSBgYWR2aXNvcnlMb2NrSWRgIHVzZXMsIHNvIHN0cnVjdHVyZSBhbmRcbiAgLy8gdHlwZXMgZGVjaWRlIGlkZW50aXR5OiBgW1wiYVwiLFwiYlwiXWAgZGlmZmVycyBmcm9tIGBbXCJhYlwiXWAsIGAxYCBmcm9tIGBcIjFcImAsIGFuZFxuICAvLyBvYmplY3Qga2V5IG9yZGVyIGRvZXMgbm90IG1hdHRlci4gSGFzaGluZyB0aGUgcmF3IHBhcnRzIHdvdWxkIGluc3RlYWQgbGVhbiBvblxuICAvLyB0aGUgaGFzaCBtb2R1bGUncyBjYW5vbmljYWxpemVyLCB3aGljaCBmb2xkcyBldmVyeSBgRGF0ZWAgb250byBvbmUgdG9rZW4uXG4gIGNvbnN0IHN1ZmZpeCA9IGhhc2guZm52SGFzaFdpdGhPcHRpb25zKFxuICAgIHsgbGVuZ3RoOiBDSEFOTkVMX0hBU0hfTEVOR1RIIH0sXG4gICAgcGFydHMubWFwKChwYXJ0KSA9PiBvYmplY3QudG9TdGFibGVLZXkocGFydCkpLmpvaW4oXCJcXHUwMDAwXCIpLFxuICApO1xuICAvLyBPbmx5IHBhcnRzIHRoYXQgc3RyaW5naWZ5IHRvIHNvbWV0aGluZyBhIHJlYWRlciByZWNvZ25pemVzIGNvbnRyaWJ1dGUgdG8gdGhlXG4gIC8vIHJlYWRhYmxlIGhhbGYuIEFuIG9iamVjdCB3b3VsZCB0b2tlbml6ZSBmcm9tIGBTdHJpbmcodmFsdWUpYCBhc1xuICAvLyBgb2JqZWN0X29iamVjdGAsIHdoaWNoIGlzIG5vaXNlIC0gaXQgc3RpbGwgc2hhcGVzIHRoZSBoYXNoLCBzbyBpZGVudGl0eSBpc1xuICAvLyB1bmFmZmVjdGVkLlxuICBjb25zdCBsYWJlbGxlZCA9IHBhcnRzLmZpbHRlcigocGFydCkgPT4ge1xuICAgIGNvbnN0IHR5cGUgPSB0eXBlb2YgcGFydDtcbiAgICByZXR1cm4gdHlwZSA9PT0gXCJzdHJpbmdcIiB8fCB0eXBlID09PSBcIm51bWJlclwiIHx8IHR5cGUgPT09IFwiYm9vbGVhblwiIHx8IHR5cGUgPT09IFwiYmlnaW50XCI7XG4gIH0pO1xuICAvLyBUcnVuY2F0ZSByYXRoZXIgdGhhbiBjYXAgdGhyb3VnaCB0aGUgdG9rZW5pemVyOiBgdHJpbWAgd291bGQgRFJPUCBhIHNpbmdsZVxuICAvLyB0b2tlbiBsb25nZXIgdGhhbiB0aGUgYnVkZ2V0LCB0dXJuaW5nIG9uZSBsb25nIG5hbWUgaW50byB0aGUgYmFyZSBmYWxsYmFjayBhbmRcbiAgLy8gbWFraW5nIGV2ZXJ5IGxvbmcgbmFtZSBsb29rIGFsaWtlLiBUaGUgaGFzaCBzdGlsbCBzZXBhcmF0ZXMgdGhlbSwgYnV0IHRoZVxuICAvLyBjaGFubmVsIGlzIHVucmVhZGFibGUgaW4gYSBsb2cuXG4gIGNvbnN0IGJvZHkgPSBzdHJpbmdcbiAgICAudG9JZGVudGlmaWVyV2l0aE9wdGlvbnMoeyBkZWxpbWl0ZXI6IFwiX1wiIH0sIC4uLmxhYmVsbGVkKVxuICAgIC5zbGljZSgwLCBNQVhfQ0hBTk5FTF9MRU5HVEggLSBzdWZmaXgubGVuZ3RoIC0gMSlcbiAgICAucmVwbGFjZSgvXyskLywgXCJcIik7XG4gIC8vIEFuIGlkZW50aWZpZXIgY2Fubm90IHN0YXJ0IHdpdGggYSBkaWdpdCBhbmQgdGhlIGhhc2ggYWxwaGFiZXQgaXNcbiAgLy8gZGlnaXQtbGVhZGluZywgc28gYSBudW1lcmljIG9yIGVtcHR5IGJvZHkgbmVlZHMgYSBsZXR0ZXIgaW4gZnJvbnQuXG4gIGNvbnN0IHByZWZpeCA9IC9eW0EtWmEtel9dLy50ZXN0KGJvZHkpID8gYm9keSA6IGAke0NIQU5ORUxfRkFMTEJBQ0t9XyR7Ym9keX1gO1xuICByZXR1cm4gYCR7cHJlZml4fV8ke3N1ZmZpeH1gLnJlcGxhY2UoL18rL2csIFwiX1wiKTtcbn1cblxuLyoqIFF1b3RlIGEgdmFsaWRhdGVkIGNoYW5uZWwgZm9yIGBMSVNURU5gL2BVTkxJU1RFTmAsIHdoaWNoIHRha2Ugbm8gcGFyYW1ldGVycy4gKi9cbmZ1bmN0aW9uIHF1b3RlSWRlbnRpZmllcih2YWx1ZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGBcIiR7dmFsdWUucmVwbGFjZUFsbCgnXCInLCAnXCJcIicpfVwiYDtcbn1cblxuLyoqXG4gKiBQYXJzZSBhIGBOT1RJRllgIHBheWxvYWQgaW50byBhbiBlbnZlbG9wZSwgcmV0dXJuaW5nIGB1bmRlZmluZWRgIGZvciBhbnl0aGluZ1xuICogdGhhdCBpcyBub3Qgb25lLlxuICpcbiAqIFRoZSBjaGFubmVsIGlzIHNoYXJlZCBhbmQgYW55IFBvc3RncmVzIHNlc3Npb24gY2FuIGBwZ19ub3RpZnlgIG9uIGl0LCBzbyBhblxuICogdW5yZWNvZ25pemVkIHBheWxvYWQgaXMgZXhwZWN0ZWQgaW5wdXQsIG5vdCBhbiBleGNlcHRpb24uIFB1Ymxpc2hlcnMgcnVuIHRoaXNcbiAqIG92ZXIgdGhlaXIgb3duIGVuY29kZWQgbWVzc2FnZSB0b28sIHdoaWNoIGlzIGhvdyBhIGJvZHkgdGhhdCBzdHJpbmdpZmllcyBidXRcbiAqIGRvZXMgbm90IHJvdW5kLXRyaXAgaXMgY2F1Z2h0IGJlZm9yZSBpdCBzaGlwcy5cbiAqL1xuZnVuY3Rpb24gZGVjb2RlKHZhbHVlOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBUb3BpY01lc3NhZ2UgfCB1bmRlZmluZWQge1xuICBpZiAoIXZhbHVlKSByZXR1cm4gdW5kZWZpbmVkO1xuICBjb25zdCByZWNvcmQgPSBqc29uLnBhcnNlUmVjb3JkKHZhbHVlKTtcbiAgaWYgKFxuICAgICFyZWNvcmQgfHxcbiAgICB0eXBlb2YgcmVjb3JkLmlkICE9PSBcInN0cmluZ1wiIHx8XG4gICAgdHlwZW9mIHJlY29yZC50b3BpYyAhPT0gXCJzdHJpbmdcIiB8fFxuICAgIHR5cGVvZiByZWNvcmQudHlwZSAhPT0gXCJzdHJpbmdcIiB8fFxuICAgIHR5cGVvZiByZWNvcmQucHVibGlzaGVkQXQgIT09IFwic3RyaW5nXCIgfHxcbiAgICAhcmVjb3JkLm1ldGFkYXRhIHx8XG4gICAgdHlwZW9mIHJlY29yZC5tZXRhZGF0YSAhPT0gXCJvYmplY3RcIiB8fFxuICAgIEFycmF5LmlzQXJyYXkocmVjb3JkLm1ldGFkYXRhKSB8fFxuICAgICEoXCJib2R5XCIgaW4gcmVjb3JkKSB8fFxuICAgICFvYmplY3QuaXNTZXJpYWxpemFibGVWYWx1ZShyZWNvcmQubWV0YWRhdGEpIHx8XG4gICAgIW9iamVjdC5pc1NlcmlhbGl6YWJsZVZhbHVlKHJlY29yZC5ib2R5KVxuICApIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIHJldHVybiB7XG4gICAgaWQ6IHJlY29yZC5pZCxcbiAgICB0b3BpYzogcmVjb3JkLnRvcGljLFxuICAgIHR5cGU6IHJlY29yZC50eXBlLFxuICAgIG1ldGFkYXRhOiByZWNvcmQubWV0YWRhdGEgYXMgVG9waWNNZXRhZGF0YSxcbiAgICBib2R5OiByZWNvcmQuYm9keSBhcyBTZXJpYWxpemFibGVWYWx1ZSxcbiAgICBwdWJsaXNoZWRBdDogcmVjb3JkLnB1Ymxpc2hlZEF0LFxuICB9O1xufVxuXG4vKipcbiAqIEJyb2FkY2FzdHMgc3RydWN0dXJlZCBtZXNzYWdlcyBieSB0b3BpYyBhbmQgZGVsaXZlcnMgdGhlbSB0byBldmVyeSBwcm9jZXNzXG4gKiBsaXN0ZW5pbmcgb24gdGhlIHNhbWUgY2hhbm5lbC5cbiAqXG4gKiBDT05ORUNUSU9OIFNIQVBFLiBQdWJsaXNoaW5nIGJvcnJvd3MgYSBwb29sZWQgY29ubmVjdGlvbiBwZXIgY2FsbCwgbGlrZSBhbnlcbiAqIG90aGVyIHF1ZXJ5LiBMaXN0ZW5pbmcgY2Fubm90OiBgTElTVEVOYCBpcyBzZXNzaW9uIHN0YXRlLCBzbyB0aGUgYnVzIGhvbGRzIE9ORVxuICogZGVkaWNhdGVkIGNsaWVudCBvdXQgb2YgdGhlIHBvb2wgZm9yIGFzIGxvbmcgYXMgaXQgaGFzIHN1YnNjcmliZXJzLCBubyBtYXR0ZXJcbiAqIGhvdyBtYW55IHRvcGljcyBvciBsaXN0ZW5lcnMgYXJlIHJlZ2lzdGVyZWQuIFNpemUgdGhlIHBvb2wgd2l0aCB0aGF0IG9uZVxuICogbG9uZy1saXZlZCBjaGVja291dCBpbiBtaW5kLlxuICpcbiAqIExJRkVDWUNMRS4gQ29uc3RydWN0aW9uIGlzIGluZXJ0IC0gbm90aGluZyBjb25uZWN0cyB1bnRpbCB0aGUgZmlyc3RcbiAqIHtAbGluayBsaXN0ZW59IChvciBhbiBleHBsaWNpdCB7QGxpbmsgc3RhcnR9KS4ge0BsaW5rIGNsb3NlfSBpcyByZXF1aXJlZCB0byBnaXZlXG4gKiB0aGUgY29ubmVjdGlvbiBiYWNrOyBhIGNsb3NlZCBidXMgc3RheXMgY2xvc2VkIGFuZCB0aHJvd3Mgb24gZnVydGhlciB1c2UgcmF0aGVyXG4gKiB0aGFuIHNpbGVudGx5IHJlY29ubmVjdGluZy4gUmVnaXN0ZXIgaXQgd2l0aCB0aGUgaG9zdCdzIHNodXRkb3duIGhvb2suXG4gKlxuICogRkFJTFVSRSBIQU5ETElORy4gQSBsb3N0IG5vdGlmaWNhdGlvbiBjb25uZWN0aW9uIHJlY29ubmVjdHMgb24gaXRzIG93biB3aXRoXG4gKiBib3VuZGVkIGJhY2tvZmYgd2hpbGUgc3Vic2NyaWJlcnMgcmVtYWluLCByZXBvcnRpbmcgZWFjaCBmYWlsZWQgYXR0ZW1wdCB0aHJvdWdoXG4gKiBgb25FcnJvcmAuIE1lc3NhZ2VzIHB1Ymxpc2hlZCBkdXJpbmcgdGhlIGdhcCBhcmUgbG9zdCAtIGBOT1RJRllgIGhhcyBubyByZXBsYXkuXG4gKiBBIHRocm93aW5nIG9yIHJlamVjdGluZyBsaXN0ZW5lciBuZXZlciBhZmZlY3RzIHRoZSBwdWJsaXNoZXIgb3IgdGhlIG90aGVyXG4gKiBsaXN0ZW5lcnM7IGl0cyBmYWlsdXJlIGdvZXMgdG8gYG9uRXJyb3JgLlxuICpcbiAqIE5vdCBzYWZlIHRvIHNoYXJlIG9uZSBpbnN0YW5jZSBhY3Jvc3MgdW5yZWxhdGVkIGNoYW5uZWxzIC0gY29uc3RydWN0IG9uZSBidXNcbiAqIHBlciBjaGFubmVsLiBUaGUgY2hhbm5lbCBpdHNlbGYgaXMgREVSSVZFRCBmcm9tIHRoZSBgY2hhbm5lbGAgb3B0aW9uIHJhdGhlclxuICogdGhhbiB0YWtlbiBsaXRlcmFsbHk7IHNlZSB7QGxpbmsgUG9zdGdyZXNUb3BpY0J1c09wdGlvbnMuY2hhbm5lbH0gYW5kXG4gKiB7QGxpbmsgUG9zdGdyZXNUb3BpY0J1cy5jaGFubmVsTmFtZX0uXG4gKi9cbmV4cG9ydCBjbGFzcyBQb3N0Z3Jlc1RvcGljQnVzIHtcbiAgLyoqXG4gICAqIFRoZSByZXNvbHZlZCBQb3N0Z3JlcyBjaGFubmVsIHRoaXMgYnVzIGxpc3RlbnMgYW5kIHB1Ymxpc2hlcyBvbiwgZGVyaXZlZCBmcm9tXG4gICAqIHRoZSBgY2hhbm5lbGAgb3B0aW9uLiBSZWFkIGl0IHRvIGNvbmZpcm0gdHdvIHByb2Nlc3NlcyBhZ3JlZSwgb3IgdG8gbG9nIHdoYXQgYVxuICAgKiBzZXQgb2YgcGFydHMgYWN0dWFsbHkgcmVzb2x2ZWQgdG8uXG4gICAqL1xuICByZWFkb25seSBjaGFubmVsTmFtZTogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRvbmx5IG1ldGFkYXRhOiBUb3BpY01ldGFkYXRhIHwgVG9waWNNZXRhZGF0YVByb3ZpZGVyIHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIHJlYWRvbmx5IG9uRXJyb3I6IChjYXVzZTogdW5rbm93bikgPT4gdm9pZDtcbiAgcHJpdmF0ZSByZWFkb25seSBsaXN0ZW5lcnMgPSBuZXcgTWFwPHN0cmluZywgU2V0PFRvcGljTGlzdGVuZXI+PigpO1xuICBwcml2YXRlIGNsaWVudDogUG9vbENsaWVudCB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSBzdGFydGluZzogUHJvbWlzZTx2b2lkPiB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSByZWNvbm5lY3Rpbmc6IFByb21pc2U8dm9pZD4gfCB1bmRlZmluZWQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgcmVjb25uZWN0QWJvcnQgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG4gIHByaXZhdGUgY2xvc2VkID0gZmFsc2U7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSBwb29sOiBQZ1Bvb2xMaWtlICYgUGdRdWVyeWFibGUsXG4gICAgb3B0aW9uczogUG9zdGdyZXNUb3BpY0J1c09wdGlvbnMgPSB7fSxcbiAgKSB7XG4gICAgdGhpcy5jaGFubmVsTmFtZSA9IGNoYW5uZWxOYW1lKFxuICAgICAgb2JqZWN0LnRvT25lT3JNYW55KG9wdGlvbnMuY2hhbm5lbCA9PT0gdW5kZWZpbmVkID8gREVGQVVMVF9DSEFOTkVMIDogb3B0aW9ucy5jaGFubmVsKSxcbiAgICApO1xuICAgIHRoaXMubWV0YWRhdGEgPSBvcHRpb25zLm1ldGFkYXRhO1xuICAgIHRoaXMub25FcnJvciA9IG9wdGlvbnMub25FcnJvciA/PyAoKCkgPT4gdW5kZWZpbmVkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBPcGVuIHRoZSBkZWRpY2F0ZWQgbm90aWZpY2F0aW9uIGNvbm5lY3Rpb24gYW5kIGBMSVNURU5gLlxuICAgKlxuICAgKiBJZGVtcG90ZW50LCBhbmQgc2FmZSB0byBjYWxsIGNvbmN1cnJlbnRseSAtIG92ZXJsYXBwaW5nIGNhbGxzIGF3YWl0IHRoZSBzYW1lXG4gICAqIGluLWZsaWdodCBjb25uZWN0LiB7QGxpbmsgbGlzdGVufSBjYWxscyB0aGlzLCBzbyBpdCBpcyBvbmx5IG5lZWRlZCB0byBzdXJmYWNlXG4gICAqIGEgY29ubmVjdGlvbiBwcm9ibGVtIGF0IHN0YXJ0dXAgcmF0aGVyIHRoYW4gb24gZmlyc3Qgc3Vic2NyaWJlLiBUaHJvd3MgaWYgdGhlXG4gICAqIGJ1cyBpcyBjbG9zZWQsIG9yIGlmIHRoZSBwb29sIGNhbm5vdCBoYW5kIG91dCBhIGNvbm5lY3Rpb24uXG4gICAqL1xuICBhc3luYyBzdGFydCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5jbGllbnQpIHJldHVybjtcbiAgICBpZiAodGhpcy5jbG9zZWQpIHRocm93IG5ldyBFcnJvcihcIlBvc3RncmVzIHRvcGljIGJ1cyBpcyBjbG9zZWRcIik7XG4gICAgdGhpcy5zdGFydGluZyA/Pz0gdGhpcy5jb25uZWN0KCkuZmluYWxseSgoKSA9PiB7XG4gICAgICB0aGlzLnN0YXJ0aW5nID0gdW5kZWZpbmVkO1xuICAgIH0pO1xuICAgIGF3YWl0IHRoaXMuc3RhcnRpbmc7XG4gIH1cblxuICAvKipcbiAgICogUHVibGlzaCBhIG1lc3NhZ2UgdG8gYHRvcGljYCwgcmV0dXJuaW5nIHRoZSBlbnZlbG9wZSB0aGF0IHdhcyBzZW50LlxuICAgKlxuICAgKiBSZXNvbHZlcyBvbmNlIFBvc3RncmVzIGhhcyBhY2NlcHRlZCB0aGUgYE5PVElGWWAsIHdoaWNoIHNheXMgbm90aGluZyBhYm91dFxuICAgKiBhbnlvbmUgcmVjZWl2aW5nIGl0OiBzZXNzaW9ucyBub3QgbGlzdGVuaW5nIGF0IHRoYXQgbW9tZW50IG1pc3MgaXQuIFB1Ymxpc2hpbmdcbiAgICogbmVlZHMgbm8ge0BsaW5rIHN0YXJ0fSBhbmQgbm8gc3Vic2NyaWJlcnMuXG4gICAqXG4gICAqIFZhbGlkYXRpb24gaXMgZGVsaWJlcmF0ZWx5IGZyb250LWxvYWRlZCwgc2luY2UgYSBtZXNzYWdlIHRoYXQgZmFpbHMgb24gdGhlXG4gICAqIHdpcmUgaXMgZmFyIGhhcmRlciB0byBkaWFnbm9zZSB0aGFuIG9uZSByZWplY3RlZCBhdCB0aGUgY2FsbDogYFR5cGVFcnJvcmAgZm9yIGFcbiAgICogYmxhbmsgdG9waWMgb3IgdHlwZSwgb3IgYSBib2R5L21ldGFkYXRhIHRoYXQgd291bGQgbm90IHJvdW5kLXRyaXAgdGhyb3VnaCBKU09OXG4gICAqIHVuY2hhbmdlZCAoYG9iamVjdC5pc1NlcmlhbGl6YWJsZVZhbHVlYCk7IGBSYW5nZUVycm9yYCB3aGVuIHRoZSBlbmNvZGVkXG4gICAqIGVudmVsb3BlIGV4Y2VlZHMgdGhlIGBOT1RJRllgIHBheWxvYWQgbGltaXQsIHdoaWNoIHRoZSBhdXRvbWF0aWMgbWV0YWRhdGFcbiAgICogY291bnRzIGFnYWluc3QgLSBzZW5kIGEgcmVmZXJlbmNlIGFuZCBsZXQgdGhlIHJlY2VpdmVyIGZldGNoIHRoZSBwYXlsb2FkLlxuICAgKiBUaHJvd3MgaWYgdGhlIGJ1cyBpcyBjbG9zZWQuXG4gICAqL1xuICBhc3luYyBicm9hZGNhc3Q8VEJvZHkgZXh0ZW5kcyBTZXJpYWxpemFibGVWYWx1ZT4oXG4gICAgdG9waWM6IHN0cmluZyxcbiAgICBpbnB1dDogVG9waWNQdWJsaXNoSW5wdXQ8VEJvZHk+LFxuICApOiBQcm9taXNlPFRvcGljTWVzc2FnZTxUQm9keT4+IHtcbiAgICBpZiAoIXRvcGljLnRyaW0oKSkgdGhyb3cgbmV3IFR5cGVFcnJvcihcIlRvcGljIG11c3Qgbm90IGJlIGVtcHR5XCIpO1xuICAgIGlmICghaW5wdXQudHlwZS50cmltKCkpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJNZXNzYWdlIHR5cGUgbXVzdCBub3QgYmUgZW1wdHlcIik7XG4gICAgaWYgKFxuICAgICAgIW9iamVjdC5pc1NlcmlhbGl6YWJsZVZhbHVlKGlucHV0Lm1ldGFkYXRhID8/IHt9KSB8fFxuICAgICAgIW9iamVjdC5pc1NlcmlhbGl6YWJsZVZhbHVlKGlucHV0LmJvZHkpXG4gICAgKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiTWVzc2FnZSBtZXRhZGF0YSBhbmQgYm9keSBtdXN0IGJlIEpTT04gc2VyaWFsaXphYmxlIHdpdGhvdXQgY29lcmNpb25cIik7XG4gICAgfVxuICAgIGlmICh0aGlzLmNsb3NlZCkgdGhyb3cgbmV3IEVycm9yKFwiUG9zdGdyZXMgdG9waWMgYnVzIGlzIGNsb3NlZFwiKTtcbiAgICBjb25zdCBhdXRvbWF0aWMgPSBhd2FpdCB0aGlzLnJlc29sdmVNZXRhZGF0YSgpO1xuICAgIGNvbnN0IG1lc3NhZ2U6IFRvcGljTWVzc2FnZTxUQm9keT4gPSB7XG4gICAgICBpZDogaGFzaC5pZCgpLFxuICAgICAgdG9waWMsXG4gICAgICB0eXBlOiBpbnB1dC50eXBlLFxuICAgICAgbWV0YWRhdGE6IHsgLi4uYXV0b21hdGljLCAuLi5pbnB1dC5tZXRhZGF0YSB9LFxuICAgICAgYm9keTogaW5wdXQuYm9keSxcbiAgICAgIHB1Ymxpc2hlZEF0OiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgfTtcbiAgICBsZXQgZW5jb2RlZDogc3RyaW5nO1xuICAgIHRyeSB7XG4gICAgICBlbmNvZGVkID0gSlNPTi5zdHJpbmdpZnkobWVzc2FnZSk7XG4gICAgfSBjYXRjaCAoY2F1c2UpIHtcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoYE1lc3NhZ2UgbXVzdCBiZSBKU09OIHNlcmlhbGl6YWJsZTogJHtlcnJvci5lcnJvck1lc3NhZ2UoY2F1c2UpfWApO1xuICAgIH1cbiAgICBpZiAoIWRlY29kZShlbmNvZGVkKSkge1xuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIk1lc3NhZ2UgdHlwZSwgbWV0YWRhdGEsIGFuZCBib2R5IG11c3QgYmUgSlNPTiBzZXJpYWxpemFibGVcIik7XG4gICAgfVxuICAgIGlmIChCdWZmZXIuYnl0ZUxlbmd0aChlbmNvZGVkLCBcInV0ZjhcIikgPiBNQVhfTk9USUZZX0JZVEVTKSB7XG4gICAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcihgUG9zdGdyZXMgbm90aWZpY2F0aW9uIGV4Y2VlZHMgJHtNQVhfTk9USUZZX0JZVEVTfSBieXRlc2ApO1xuICAgIH1cbiAgICBhd2FpdCB0aGlzLnBvb2wucXVlcnkoXCJTRUxFQ1QgcGdfbm90aWZ5KCQxLCAkMilcIiwgW3RoaXMuY2hhbm5lbE5hbWUsIGVuY29kZWRdKTtcbiAgICByZXR1cm4gbWVzc2FnZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdWJzY3JpYmUgdG8gYHRvcGljYCwgcmV0dXJuaW5nIHRoZSBmdW5jdGlvbiB0aGF0IHVuc3Vic2NyaWJlcy5cbiAgICpcbiAgICogQ29ubmVjdHMgb24gZmlyc3QgdXNlLiBTZXZlcmFsIGxpc3RlbmVycyBtYXkgc2hhcmUgYSB0b3BpYzsgZWFjaCBpcyBjYWxsZWRcbiAgICogb25jZSBwZXIgbWVzc2FnZS4gT25seSBtZXNzYWdlcyBwdWJsaXNoZWQgQUZURVIgdGhpcyByZXNvbHZlcyBhcnJpdmUsIHNvXG4gICAqIHN1YnNjcmliZSBiZWZvcmUgdHJpZ2dlcmluZyB3aGF0ZXZlciB5b3UgZXhwZWN0IHRvIG9ic2VydmUuXG4gICAqXG4gICAqIFRoZSByZXR1cm5lZCBmdW5jdGlvbiByZW1vdmVzIGp1c3QgdGhpcyBsaXN0ZW5lciBhbmQgaXMgc2FmZSB0byBjYWxsIHR3aWNlLlxuICAgKiBUaGUgY29ubmVjdGlvbiBzdGF5cyBvcGVuIG9uY2UgdGhlIGxhc3QgbGlzdGVuZXIgbGVhdmVzIC0ge0BsaW5rIGNsb3NlfVxuICAgKiByZWxlYXNlcyBpdCAtIHNvIGEgYnVzIHRoYXQgc3Vic2NyaWJlcyBhbmQgdW5zdWJzY3JpYmVzIHBlciByZXF1ZXN0IGRvZXMgbm90XG4gICAqIGNodXJuIGNvbm5lY3Rpb25zLlxuICAgKi9cbiAgYXN5bmMgbGlzdGVuPFRCb2R5IGV4dGVuZHMgU2VyaWFsaXphYmxlVmFsdWU+KFxuICAgIHRvcGljOiBzdHJpbmcsXG4gICAgbGlzdGVuZXI6IFRvcGljTGlzdGVuZXI8VEJvZHk+LFxuICApOiBQcm9taXNlPCgpID0+IFByb21pc2U8dm9pZD4+IHtcbiAgICBpZiAoIXRvcGljLnRyaW0oKSkgdGhyb3cgbmV3IFR5cGVFcnJvcihcIlRvcGljIG11c3Qgbm90IGJlIGVtcHR5XCIpO1xuICAgIGF3YWl0IHRoaXMuc3RhcnQoKTtcbiAgICBjb25zdCBsaXN0ZW5lcnMgPSB0aGlzLmxpc3RlbmVycy5nZXQodG9waWMpID8/IG5ldyBTZXQ8VG9waWNMaXN0ZW5lcj4oKTtcbiAgICBsaXN0ZW5lcnMuYWRkKGxpc3RlbmVyIGFzIFRvcGljTGlzdGVuZXIpO1xuICAgIHRoaXMubGlzdGVuZXJzLnNldCh0b3BpYywgbGlzdGVuZXJzKTtcbiAgICByZXR1cm4gYXN5bmMgKCkgPT4ge1xuICAgICAgbGlzdGVuZXJzLmRlbGV0ZShsaXN0ZW5lciBhcyBUb3BpY0xpc3RlbmVyKTtcbiAgICAgIGlmIChsaXN0ZW5lcnMuc2l6ZSA9PT0gMCkgdGhpcy5saXN0ZW5lcnMuZGVsZXRlKHRvcGljKTtcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1aWxkIHRoZSBhdXRvbWF0aWMgaGFsZiBvZiBhIG1lc3NhZ2UncyBtZXRhZGF0YS5cbiAgICpcbiAgICogUHJlY2VkZW5jZSwgd2Vha2VzdCBmaXJzdDogbWFjaGluZS9wcm9jZXNzIGNvbnRleHQsIHRoZW4gQXBwS2l0IHNlbmRlclxuICAgKiBpZGVudGl0eSwgdGhlbiB0aGlzIGJ1cydzIGNvbmZpZ3VyZWQgbWV0YWRhdGEuIFRoZSBjYWxsZXIncyBwZXItbWVzc2FnZVxuICAgKiBtZXRhZGF0YSBpcyBsYXllcmVkIG92ZXIgdGhlIHJlc3VsdCBpbiB7QGxpbmsgYnJvYWRjYXN0fSwgc28gdGhlIG1vc3Qgc3BlY2lmaWNcbiAgICogc291cmNlIGFsd2F5cyB3aW5zIGFuZCBub3RoaW5nIGhlcmUgY2FuIG92ZXJ3cml0ZSBhbiBleHBsaWNpdCBrZXkuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHJlc29sdmVNZXRhZGF0YSgpOiBQcm9taXNlPFRvcGljTWV0YWRhdGE+IHtcbiAgICBjb25zdCBzZW5kZXIgPSBhd2FpdCBzZW5kZXJNZXRhZGF0YSgpO1xuICAgIGNvbnN0IGNvbmZpZ3VyZWQgPVxuICAgICAgdHlwZW9mIHRoaXMubWV0YWRhdGEgPT09IFwiZnVuY3Rpb25cIiA/IGF3YWl0IHRoaXMubWV0YWRhdGEoKSA6ICh0aGlzLm1ldGFkYXRhID8/IHt9KTtcbiAgICByZXR1cm4geyAuLi5tYWNoaW5lTWV0YWRhdGEoKSwgLi4uc2VuZGVyLCAuLi5jb25maWd1cmVkIH07XG4gIH1cblxuICAvKipcbiAgICogUmVsZWFzZSB0aGUgbm90aWZpY2F0aW9uIGNvbm5lY3Rpb24gYW5kIHN0b3AgZGVsaXZlcmluZyBtZXNzYWdlcy4gSWRlbXBvdGVudC5cbiAgICpcbiAgICogQ2FuY2VscyBhbnkgcGVuZGluZyByZWNvbm5lY3QsIGRyb3BzIGFsbCBsaXN0ZW5lcnMsIHRoZW4gYFVOTElTVEVOYHMgYW5kXG4gICAqIHJldHVybnMgdGhlIGNsaWVudCB0byB0aGUgcG9vbC4gQSBmYWlsZWQgYFVOTElTVEVOYCBpcyByZXBvcnRlZCB0byB0aGUgcG9vbCBhc1xuICAgKiBhIHJlbGVhc2UgZXJyb3Igc28gdGhlIGNvbm5lY3Rpb24gaXMgRElTQ0FSREVEIHJhdGhlciB0aGFuIGhhbmRlZCB0byB0aGUgbmV4dFxuICAgKiBjYWxsZXIgc3RpbGwgc3Vic2NyaWJlZCB0byB0aGUgY2hhbm5lbC4gRG9lcyBub3QgdGhyb3c7IHRoZSBidXMgc3RheXMgY2xvc2VkLlxuICAgKi9cbiAgYXN5bmMgY2xvc2UoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuY2xvc2VkKSByZXR1cm47XG4gICAgdGhpcy5jbG9zZWQgPSB0cnVlO1xuICAgIHRoaXMucmVjb25uZWN0QWJvcnQuYWJvcnQobmV3IEVycm9yKFwiUG9zdGdyZXMgdG9waWMgYnVzIGlzIGNsb3NlZFwiKSk7XG4gICAgYXdhaXQgdGhpcy5zdGFydGluZz8uY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgICBhd2FpdCB0aGlzLnJlY29ubmVjdGluZz8uY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgICBjb25zdCBjbGllbnQgPSB0aGlzLmNsaWVudDtcbiAgICB0aGlzLmNsaWVudCA9IHVuZGVmaW5lZDtcbiAgICB0aGlzLmxpc3RlbmVycy5jbGVhcigpO1xuICAgIGlmICghY2xpZW50KSByZXR1cm47XG4gICAgY2xpZW50LnJlbW92ZUxpc3RlbmVyKFwibm90aWZpY2F0aW9uXCIsIHRoaXMuaGFuZGxlTm90aWZpY2F0aW9uKTtcbiAgICBjbGllbnQucmVtb3ZlTGlzdGVuZXIoXCJlcnJvclwiLCB0aGlzLmhhbmRsZUNsaWVudEVycm9yKTtcbiAgICBsZXQgcmVsZWFzZUVycm9yOiBFcnJvciB8IHVuZGVmaW5lZDtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgY2xpZW50LnF1ZXJ5KGBVTkxJU1RFTiAke3F1b3RlSWRlbnRpZmllcih0aGlzLmNoYW5uZWxOYW1lKX1gKTtcbiAgICB9IGNhdGNoIChjYXVzZSkge1xuICAgICAgcmVsZWFzZUVycm9yID0gZXJyb3IudG9FcnJvcihjYXVzZSk7XG4gICAgfVxuICAgIGNsaWVudC5yZWxlYXNlKHJlbGVhc2VFcnJvcik7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgb3V0IG9uZSBjbGllbnQsIGF0dGFjaCB0aGUgaGFuZGxlcnMsIGFuZCBgTElTVEVOYC5cbiAgICpcbiAgICogVGhlIGhhbmRsZXJzIGFyZSBhdHRhY2hlZCBCRUZPUkUgdGhlIGBMSVNURU5gIHJvdW5kIHRyaXAgc28gYSBub3RpZmljYXRpb24gb3JcbiAgICogZXJyb3IgYXJyaXZpbmcgbWlkLXNldHVwIGlzIG5vdCBtaXNzZWQuIEFueSBmYWlsdXJlIC0gaW5jbHVkaW5nIHRoZSBidXMgYmVpbmdcbiAgICogY2xvc2VkIHdoaWxlIHRoZSBjb25uZWN0IHdhcyBpbiBmbGlnaHQgLSBkZXRhY2hlcyB0aGUgaGFuZGxlcnMgYW5kIHJlbGVhc2VzXG4gICAqIHRoZSBjbGllbnQgYXMgZXJyb3JlZCwgc28gYSBoYWxmLWNvbmZpZ3VyZWQgY29ubmVjdGlvbiBuZXZlciByZXR1cm5zIHRvIHRoZVxuICAgKiBwb29sLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBjb25uZWN0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGNsaWVudCA9IGF3YWl0IHRoaXMucG9vbC5jb25uZWN0KCk7XG4gICAgdHJ5IHtcbiAgICAgIGNsaWVudC5vbihcIm5vdGlmaWNhdGlvblwiLCB0aGlzLmhhbmRsZU5vdGlmaWNhdGlvbik7XG4gICAgICBjbGllbnQub24oXCJlcnJvclwiLCB0aGlzLmhhbmRsZUNsaWVudEVycm9yKTtcbiAgICAgIGF3YWl0IGNsaWVudC5xdWVyeShgTElTVEVOICR7cXVvdGVJZGVudGlmaWVyKHRoaXMuY2hhbm5lbE5hbWUpfWApO1xuICAgICAgaWYgKHRoaXMuY2xvc2VkKSB0aHJvdyBuZXcgRXJyb3IoXCJQb3N0Z3JlcyB0b3BpYyBidXMgaXMgY2xvc2VkXCIpO1xuICAgICAgdGhpcy5jbGllbnQgPSBjbGllbnQ7XG4gICAgfSBjYXRjaCAoY2F1c2UpIHtcbiAgICAgIGNsaWVudC5yZW1vdmVMaXN0ZW5lcihcIm5vdGlmaWNhdGlvblwiLCB0aGlzLmhhbmRsZU5vdGlmaWNhdGlvbik7XG4gICAgICBjbGllbnQucmVtb3ZlTGlzdGVuZXIoXCJlcnJvclwiLCB0aGlzLmhhbmRsZUNsaWVudEVycm9yKTtcbiAgICAgIGNsaWVudC5yZWxlYXNlKGVycm9yLnRvRXJyb3IoY2F1c2UpKTtcbiAgICAgIHRocm93IGNhdXNlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSb3V0ZSBvbmUgaW5ib3VuZCBub3RpZmljYXRpb24gdG8gdGhlIHRvcGljJ3MgbGlzdGVuZXJzLlxuICAgKlxuICAgKiBJZ25vcmVzIG90aGVyIGNoYW5uZWxzIGFuZCB1bmRlY29kYWJsZSBwYXlsb2FkcyAtIHRoZSBjaGFubmVsIGlzIHNoYXJlZCwgc29cbiAgICogYm90aCBhcmUgb3JkaW5hcnkgdHJhZmZpYy4gTGlzdGVuZXJzIGFyZSBpbnZva2VkIGNvbmN1cnJlbnRseSBhbmQgdGhlaXJcbiAgICogcmVqZWN0aW9ucyBnbyB0byBgb25FcnJvcmAsIGtlZXBpbmcgb25lIHNsb3cgb3IgYnJva2VuIHN1YnNjcmliZXIgZnJvbVxuICAgKiBzdGFsbGluZyB0aGUgbm90aWZpY2F0aW9uIGNvbm5lY3Rpb24uXG4gICAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGhhbmRsZU5vdGlmaWNhdGlvbiA9IChub3RpZmljYXRpb246IE5vdGlmaWNhdGlvbik6IHZvaWQgPT4ge1xuICAgIGlmIChub3RpZmljYXRpb24uY2hhbm5lbCAhPT0gdGhpcy5jaGFubmVsTmFtZSkgcmV0dXJuO1xuICAgIGNvbnN0IG1lc3NhZ2UgPSBkZWNvZGUobm90aWZpY2F0aW9uLnBheWxvYWQpO1xuICAgIGlmICghbWVzc2FnZSkgcmV0dXJuO1xuICAgIGZvciAoY29uc3QgbGlzdGVuZXIgb2YgdGhpcy5saXN0ZW5lcnMuZ2V0KG1lc3NhZ2UudG9waWMpID8/IFtdKSB7XG4gICAgICBQcm9taXNlLnJlc29sdmUobGlzdGVuZXIobWVzc2FnZSkpLmNhdGNoKHRoaXMub25FcnJvcik7XG4gICAgfVxuICB9O1xuXG4gIC8qKlxuICAgKiBIYW5kbGUgdGhlIG5vdGlmaWNhdGlvbiBjb25uZWN0aW9uIGR5aW5nLCB3aGljaCBgcGdgIHJlcG9ydHMgYXMgYW4gYGVycm9yYFxuICAgKiBldmVudCByYXRoZXIgdGhhbiBhIHJlamVjdGVkIHF1ZXJ5LlxuICAgKlxuICAgKiBUaGUgY2xpZW50IGlzIHVudXNhYmxlIGF0IHRoaXMgcG9pbnQsIHNvIGl0IGlzIGRldGFjaGVkIGFuZCByZWxlYXNlZCBhc1xuICAgKiBlcnJvcmVkICh3aGljaCBkaXNjYXJkcyBpdCkgYmVmb3JlIGFueXRoaW5nIGVsc2UuIFJlY29ubmVjdGlvbiBvbmx5IHN0YXJ0c1xuICAgKiB3aGVuIHRoZXJlIGlzIHN0aWxsIHNvbWVvbmUgdG8gZGVsaXZlciB0bywgc28gYW4gaWRsZSBvciBjbG9zaW5nIGJ1cyBkb2VzIG5vdFxuICAgKiBob2xkIGEgY29ubmVjdGlvbiBvcGVuIGNoYXNpbmcgYSBjaGFubmVsIG5vYm9keSByZWFkcy5cbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgaGFuZGxlQ2xpZW50RXJyb3IgPSAoY2F1c2U6IEVycm9yKTogdm9pZCA9PiB7XG4gICAgdGhpcy5vbkVycm9yKGNhdXNlKTtcbiAgICBjb25zdCBjbGllbnQgPSB0aGlzLmNsaWVudDtcbiAgICBpZiAoIWNsaWVudCkgcmV0dXJuO1xuICAgIHRoaXMuY2xpZW50ID0gdW5kZWZpbmVkO1xuICAgIGNsaWVudC5yZW1vdmVMaXN0ZW5lcihcIm5vdGlmaWNhdGlvblwiLCB0aGlzLmhhbmRsZU5vdGlmaWNhdGlvbik7XG4gICAgY2xpZW50LnJlbW92ZUxpc3RlbmVyKFwiZXJyb3JcIiwgdGhpcy5oYW5kbGVDbGllbnRFcnJvcik7XG4gICAgY2xpZW50LnJlbGVhc2UoY2F1c2UpO1xuICAgIGlmICh0aGlzLmNsb3NlZCB8fCB0aGlzLmxpc3RlbmVycy5zaXplID09PSAwKSByZXR1cm47XG4gICAgdGhpcy5yZWNvbm5lY3RpbmcgPz89IHRoaXMucmVjb25uZWN0KCkuZmluYWxseSgoKSA9PiB7XG4gICAgICB0aGlzLnJlY29ubmVjdGluZyA9IHVuZGVmaW5lZDtcbiAgICB9KTtcbiAgfTtcblxuICAvKipcbiAgICogUmUtZXN0YWJsaXNoIHRoZSBub3RpZmljYXRpb24gY29ubmVjdGlvbiB3aXRoIGJvdW5kZWQgZXhwb25lbnRpYWwgYmFja29mZi5cbiAgICpcbiAgICogVGhlIGZpcnN0IGF0dGVtcHQgaXMgaW1tZWRpYXRlLCBzaW5jZSB0aGUgY29tbW9uIGNhc2UgaXMgYSBzaW5nbGUgZHJvcHBlZFxuICAgKiBjb25uZWN0aW9uIHRoYXQgcmVjb25uZWN0cyBhdCBvbmNlOyBzdWJzZXF1ZW50IGRlbGF5cyBkb3VibGUgZnJvbSAyNTBtcyB1cCB0b1xuICAgKiA1cyBhbmQgc3RheSB0aGVyZS4gUmV0cmllcyBpbmRlZmluaXRlbHkgcmF0aGVyIHRoYW4gZ2l2aW5nIHVwLCBiZWNhdXNlIGEgUG9zdGdyZXMgcmVzdGFydFxuICAgKiBvciBhIHJvdGF0ZWQgTGFrZWJhc2UgY3JlZGVudGlhbCBpcyBhIHJlY292ZXJhYmxlIG91dGFnZSBhbmQgYSBzaWxlbnRseSBkZWFkXG4gICAqIGxpc3RlbmVyIGlzIHdvcnNlIHRoYW4gYSBub2lzeSBvbmUuIFN0b3BzIHdoZW4gdGhlIGJ1cyBjbG9zZXMgb3IgdGhlIGxhc3RcbiAgICogbGlzdGVuZXIgbGVhdmVzLCBhbmQgcmVwb3J0cyBldmVyeSBmYWlsZWQgYXR0ZW1wdCB0aHJvdWdoIGBvbkVycm9yYC5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcmVjb25uZWN0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGxldCBkZWxheSA9IDA7XG4gICAgd2hpbGUgKCF0aGlzLmNsb3NlZCAmJiB0aGlzLmxpc3RlbmVycy5zaXplID4gMCkge1xuICAgICAgaWYgKGRlbGF5ID4gMCkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IGFzeW5jVXRpbC5zbGVlcChkZWxheSwgdGhpcy5yZWNvbm5lY3RBYm9ydC5zaWduYWwpO1xuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMuc3RhcnQoKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSBjYXRjaCAoY2F1c2UpIHtcbiAgICAgICAgaWYgKHRoaXMuY2xvc2VkKSByZXR1cm47XG4gICAgICAgIHRoaXMub25FcnJvcihjYXVzZSk7XG4gICAgICAgIGRlbGF5ID0gZGVsYXkgPT09IDAgPyBNSU5fUkVDT05ORUNUX0RFTEFZX01TIDogTWF0aC5taW4oZGVsYXkgKiAyLCBNQVhfUkVDT05ORUNUX0RFTEFZX01TKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1 @@
1
+ {"root":["../src/advisory-lock.ts","../src/topic-bus.ts","../index.ts"],"version":"5.9.3"}