velocious 1.0.606 → 1.0.607

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.
Files changed (64) hide show
  1. package/README.md +44 -1
  2. package/build/background-jobs/job-semantics.js +145 -0
  3. package/build/background-jobs/local-adapter.js +161 -0
  4. package/build/background-jobs/local-dispatcher.js +418 -0
  5. package/build/background-jobs/local-job-registry.js +59 -0
  6. package/build/background-jobs/local-store.js +1219 -0
  7. package/build/background-jobs/store.js +33 -97
  8. package/build/background-jobs/types.js +26 -1
  9. package/build/configuration-types.js +3 -1
  10. package/build/configuration.js +16 -1
  11. package/build/database/drivers/sqlite/index.js +46 -41
  12. package/build/environment-handlers/browser.js +10 -0
  13. package/build/src/background-jobs/job-semantics.d.ts +65 -0
  14. package/build/src/background-jobs/job-semantics.d.ts.map +1 -0
  15. package/build/src/background-jobs/job-semantics.js +125 -0
  16. package/build/src/background-jobs/local-adapter.d.ts +161 -0
  17. package/build/src/background-jobs/local-adapter.d.ts.map +1 -0
  18. package/build/src/background-jobs/local-adapter.js +141 -0
  19. package/build/src/background-jobs/local-dispatcher.d.ts +185 -0
  20. package/build/src/background-jobs/local-dispatcher.d.ts.map +1 -0
  21. package/build/src/background-jobs/local-dispatcher.js +383 -0
  22. package/build/src/background-jobs/local-job-registry.d.ts +26 -0
  23. package/build/src/background-jobs/local-job-registry.d.ts.map +1 -0
  24. package/build/src/background-jobs/local-job-registry.js +51 -0
  25. package/build/src/background-jobs/local-store.d.ts +364 -0
  26. package/build/src/background-jobs/local-store.d.ts.map +1 -0
  27. package/build/src/background-jobs/local-store.js +1078 -0
  28. package/build/src/background-jobs/store.d.ts +0 -9
  29. package/build/src/background-jobs/store.d.ts.map +1 -1
  30. package/build/src/background-jobs/store.js +18 -88
  31. package/build/src/background-jobs/types.d.ts +97 -2
  32. package/build/src/background-jobs/types.d.ts.map +1 -1
  33. package/build/src/background-jobs/types.js +27 -2
  34. package/build/src/configuration-types.d.ts +9 -2
  35. package/build/src/configuration-types.d.ts.map +1 -1
  36. package/build/src/configuration-types.js +4 -2
  37. package/build/src/configuration.d.ts +5 -0
  38. package/build/src/configuration.d.ts.map +1 -1
  39. package/build/src/configuration.js +15 -2
  40. package/build/src/database/drivers/sqlite/index.d.ts +8 -0
  41. package/build/src/database/drivers/sqlite/index.d.ts.map +1 -1
  42. package/build/src/database/drivers/sqlite/index.js +47 -41
  43. package/build/src/environment-handlers/browser.d.ts +9 -0
  44. package/build/src/environment-handlers/browser.d.ts.map +1 -1
  45. package/build/src/environment-handlers/browser.js +10 -1
  46. package/build/src/testing/test-runner.d.ts +42 -10
  47. package/build/src/testing/test-runner.d.ts.map +1 -1
  48. package/build/src/testing/test-runner.js +135 -35
  49. package/build/testing/test-runner.js +141 -33
  50. package/build/tsconfig.tsbuildinfo +1 -1
  51. package/package.json +1 -1
  52. package/scripts/test-browser.js +5 -1
  53. package/src/background-jobs/job-semantics.js +145 -0
  54. package/src/background-jobs/local-adapter.js +161 -0
  55. package/src/background-jobs/local-dispatcher.js +418 -0
  56. package/src/background-jobs/local-job-registry.js +59 -0
  57. package/src/background-jobs/local-store.js +1219 -0
  58. package/src/background-jobs/store.js +33 -97
  59. package/src/background-jobs/types.js +26 -1
  60. package/src/configuration-types.js +3 -1
  61. package/src/configuration.js +16 -1
  62. package/src/database/drivers/sqlite/index.js +46 -41
  63. package/src/environment-handlers/browser.js +10 -0
  64. package/src/testing/test-runner.js +141 -33
@@ -0,0 +1,185 @@
1
+ export type LocalBackgroundJobAcknowledgement = {
2
+ type: "completed";
3
+ } | {
4
+ type: "failed";
5
+ error: ReturnType<typeof JSON.parse>;
6
+ } | {
7
+ type: "rescheduled";
8
+ delayMs: number;
9
+ };
10
+ export type PendingLocalBackgroundJobAcknowledgement = {
11
+ /**
12
+ * - Durable transition still owned by this dispatcher.
13
+ */
14
+ acknowledgement: LocalBackgroundJobAcknowledgement;
15
+ /**
16
+ * - Fenced handoff being acknowledged.
17
+ */
18
+ handoff: import("./types.js").BackgroundJobHandoff;
19
+ /**
20
+ * - Claimed job snapshot.
21
+ */
22
+ job: import("./types.js").BackgroundJobRow;
23
+ };
24
+ /** Configuration-owned, event-driven in-process local dispatcher. */
25
+ export default class LocalBackgroundJobsDispatcher {
26
+ clock: import("./types.js").LocalBackgroundJobsClock;
27
+ configuration: import("../configuration.js").default;
28
+ registry: import("./local-job-registry.js").default;
29
+ store: import("./local-store.js").default;
30
+ _accepting: boolean;
31
+ _started: boolean;
32
+ /** @type {Promise<void> | null} */
33
+ _startPromise: Promise<void> | null;
34
+ /** @type {Promise<void> | null} */
35
+ _drainPromise: Promise<void> | null;
36
+ _redrain: boolean;
37
+ _wakeQueued: boolean;
38
+ /** @type {Set<Promise<void>>} */
39
+ _inFlight: Set<Promise<void>>;
40
+ /** @type {Map<string, PendingLocalBackgroundJobAcknowledgement>} */
41
+ _pendingAcknowledgements: Map<string, PendingLocalBackgroundJobAcknowledgement>;
42
+ /** @type {Set<() => void>} */
43
+ _idleWaiters: Set<() => void>;
44
+ /** @type {ReturnType<typeof setTimeout> | number | undefined} */
45
+ _scheduledTimer: ReturnType<typeof setTimeout> | number | undefined;
46
+ /** @type {ReturnType<typeof setTimeout> | number | undefined} */
47
+ _recoveryTimer: ReturnType<typeof setTimeout> | number | undefined;
48
+ /**
49
+ * Creates a dispatcher owned by one configuration and local store.
50
+ * @param {object} args - Dispatcher options.
51
+ * @param {import("../configuration.js").default} args.configuration - Owning configuration.
52
+ * @param {import("./types.js").LocalBackgroundJobsClock} args.clock - Dispatcher clock.
53
+ * @param {import("./local-job-registry.js").default} args.registry - Static job registry.
54
+ * @param {import("./local-store.js").default} args.store - Durable local store.
55
+ */
56
+ constructor({ configuration, clock, registry, store }: {
57
+ configuration: import("../configuration.js").default;
58
+ clock: import("./types.js").LocalBackgroundJobsClock;
59
+ registry: import("./local-job-registry.js").default;
60
+ store: import("./local-store.js").default;
61
+ });
62
+ /**
63
+ * Starts, recovers, and catches up the local dispatcher.
64
+ * @returns {Promise<void>} - Resolves after admission starts.
65
+ */
66
+ start(): Promise<void>;
67
+ /**
68
+ * Coalesces a dispatcher wake onto one tracked microtask.
69
+ * @returns {void} - No return value.
70
+ */
71
+ wake(): void;
72
+ /**
73
+ * Fills local capacity with short durable claims.
74
+ * @returns {Promise<void>} - Resolves after one stable drain pass.
75
+ */
76
+ _drain(): Promise<void>;
77
+ /**
78
+ * Runs one claimed performance without retaining its claim transaction connection.
79
+ * @param {{handoff: import("./types.js").BackgroundJobHandoff, job: import("./types.js").BackgroundJobRow}} args - Claimed job.
80
+ * @returns {void} - No return value.
81
+ */
82
+ _startPerformance({ handoff, job }: {
83
+ handoff: import("./types.js").BackgroundJobHandoff;
84
+ job: import("./types.js").BackgroundJobRow;
85
+ }): void;
86
+ /**
87
+ * Performs and acknowledges one durable handoff.
88
+ * @param {{handoff: import("./types.js").BackgroundJobHandoff, job: import("./types.js").BackgroundJobRow}} args - Claimed job.
89
+ * @returns {Promise<void>} - Resolves after acknowledgement.
90
+ */
91
+ _perform({ handoff, job }: {
92
+ handoff: import("./types.js").BackgroundJobHandoff;
93
+ job: import("./types.js").BackgroundJobRow;
94
+ }): Promise<void>;
95
+ /**
96
+ * Applies one fenced durable acknowledgement.
97
+ * @param {PendingLocalBackgroundJobAcknowledgement} args - Owned acknowledgement.
98
+ * @returns {Promise<void>} - Resolves after the durable transition is settled.
99
+ */
100
+ _acknowledge({ acknowledgement, handoff, job }: PendingLocalBackgroundJobAcknowledgement): Promise<void>;
101
+ /**
102
+ * Replays each retained acknowledgement once at an event-driven wake boundary.
103
+ * @param {{throwOnError?: boolean}} [args] - Recovery behavior.
104
+ * @returns {Promise<void>} - Resolves after one bounded recovery pass.
105
+ */
106
+ _retryPendingAcknowledgements({ throwOnError }?: {
107
+ throwOnError?: boolean;
108
+ }): Promise<void>;
109
+ /**
110
+ * Arms the exact next future job timer, chunking platform-sized delays.
111
+ * @returns {Promise<void>} - Resolves after timer reconciliation.
112
+ */
113
+ _armScheduledTimer(): Promise<void>;
114
+ /**
115
+ * Arms one bounded retry after an unexpected drain failure.
116
+ * @returns {void} - No return value.
117
+ */
118
+ _armRecoveryTimer(): void;
119
+ /**
120
+ * Waits for admission and every in-flight acknowledgement without polling.
121
+ * @returns {Promise<void>} - Resolves when idle.
122
+ */
123
+ waitForIdle(): Promise<void>;
124
+ /**
125
+ * Stops claims and waits for in-flight acknowledgement.
126
+ * @returns {Promise<void>} - Resolves after a graceful stop.
127
+ */
128
+ stop(): Promise<void>;
129
+ /**
130
+ * Reports whether dispatcher admission has started.
131
+ * @returns {boolean} - Whether dispatcher admission has started.
132
+ */
133
+ isReady(): boolean;
134
+ /**
135
+ * Reads the configuration-owned in-process performance cap.
136
+ * @returns {number} - Configuration-owned in-process performance cap.
137
+ */
138
+ _maxConcurrentJobs(): number;
139
+ /**
140
+ * Counts performances whose durable acknowledgement is still owned locally.
141
+ * @returns {number} - Active or pending-acknowledgement performances.
142
+ */
143
+ _ownedPerformanceCount(): number;
144
+ /**
145
+ * Reports whether no admission or acknowledgement work remains.
146
+ * @returns {boolean} - Whether the dispatcher is idle.
147
+ */
148
+ _isIdle(): boolean;
149
+ /**
150
+ * Resolves event-based idle waiters at a stable idle boundary.
151
+ * @returns {void} - No return value.
152
+ */
153
+ _resolveIdleWaiters(): void;
154
+ /**
155
+ * Emits an expected job failure through the standard job/all-error channels.
156
+ * @param {{error: ReturnType<typeof JSON.parse>, job: import("./types.js").BackgroundJobRow}} args - Failure transition.
157
+ * @returns {void} - No return value.
158
+ */
159
+ _emitBackgroundJobFailed({ error, job }: {
160
+ error: ReturnType<typeof JSON.parse>;
161
+ job: import("./types.js").BackgroundJobRow;
162
+ }): void;
163
+ /**
164
+ * Reports one failed durable acknowledgement attempt with its fence context.
165
+ * @param {PendingLocalBackgroundJobAcknowledgement & {error: ReturnType<typeof JSON.parse>}} args - Failed acknowledgement.
166
+ * @returns {void} - No return value.
167
+ */
168
+ _reportAcknowledgementError({ acknowledgement, error, handoff, job }: PendingLocalBackgroundJobAcknowledgement & {
169
+ error: ReturnType<typeof JSON.parse>;
170
+ }): void;
171
+ /**
172
+ * Reports an unexpected dispatcher failure through framework channels.
173
+ * @param {object} args - Unexpected failure.
174
+ * @param {Record<string, ReturnType<typeof JSON.parse>>} [args.context] - Additional failure context.
175
+ * @param {ReturnType<typeof JSON.parse>} args.error - Unexpected error.
176
+ * @param {string} args.stage - Dispatcher stage.
177
+ * @returns {void} - No return value.
178
+ */
179
+ _reportFrameworkError({ context, error, stage }: {
180
+ context?: Record<string, ReturnType<typeof JSON.parse>>;
181
+ error: ReturnType<typeof JSON.parse>;
182
+ stage: string;
183
+ }): void;
184
+ }
185
+ //# sourceMappingURL=local-dispatcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-dispatcher.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/local-dispatcher.js"],"names":[],"mappings":"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"}
@@ -0,0 +1,383 @@
1
+ // @ts-check
2
+ import BackgroundJobRescheduleSignal from "./reschedule-signal.js";
3
+ import performBackgroundJob from "./perform-job.js";
4
+ /** @typedef {{type: "completed"} | {type: "failed", error: ReturnType<typeof JSON.parse>} | {type: "rescheduled", delayMs: number}} LocalBackgroundJobAcknowledgement */
5
+ /**
6
+ * @typedef {object} PendingLocalBackgroundJobAcknowledgement
7
+ * @property {LocalBackgroundJobAcknowledgement} acknowledgement - Durable transition still owned by this dispatcher.
8
+ * @property {import("./types.js").BackgroundJobHandoff} handoff - Fenced handoff being acknowledged.
9
+ * @property {import("./types.js").BackgroundJobRow} job - Claimed job snapshot.
10
+ */
11
+ const MAX_TIMER_MS = 2_147_483_647;
12
+ const ERROR_RECOVERY_DELAY_MS = 1_000;
13
+ /** Configuration-owned, event-driven in-process local dispatcher. */
14
+ export default class LocalBackgroundJobsDispatcher {
15
+ /**
16
+ * Creates a dispatcher owned by one configuration and local store.
17
+ * @param {object} args - Dispatcher options.
18
+ * @param {import("../configuration.js").default} args.configuration - Owning configuration.
19
+ * @param {import("./types.js").LocalBackgroundJobsClock} args.clock - Dispatcher clock.
20
+ * @param {import("./local-job-registry.js").default} args.registry - Static job registry.
21
+ * @param {import("./local-store.js").default} args.store - Durable local store.
22
+ */
23
+ constructor({ configuration, clock, registry, store }) {
24
+ this.clock = clock;
25
+ this.configuration = configuration;
26
+ this.registry = registry;
27
+ this.store = store;
28
+ this._accepting = false;
29
+ this._started = false;
30
+ /** @type {Promise<void> | null} */
31
+ this._startPromise = null;
32
+ /** @type {Promise<void> | null} */
33
+ this._drainPromise = null;
34
+ this._redrain = false;
35
+ this._wakeQueued = false;
36
+ /** @type {Set<Promise<void>>} */
37
+ this._inFlight = new Set();
38
+ /** @type {Map<string, PendingLocalBackgroundJobAcknowledgement>} */
39
+ this._pendingAcknowledgements = new Map();
40
+ /** @type {Set<() => void>} */
41
+ this._idleWaiters = new Set();
42
+ /** @type {ReturnType<typeof setTimeout> | number | undefined} */
43
+ this._scheduledTimer = undefined;
44
+ /** @type {ReturnType<typeof setTimeout> | number | undefined} */
45
+ this._recoveryTimer = undefined;
46
+ }
47
+ /**
48
+ * Starts, recovers, and catches up the local dispatcher.
49
+ * @returns {Promise<void>} - Resolves after admission starts.
50
+ */
51
+ async start() {
52
+ if (this._started)
53
+ return;
54
+ if (this._startPromise)
55
+ return await this._startPromise;
56
+ this._startPromise = (async () => {
57
+ this.configuration.setCurrent();
58
+ this.registry.ensureReady();
59
+ await this.configuration.initialize({ type: "local-background-jobs" });
60
+ await this.store.ensureReady();
61
+ await this.store.reconcileQueueConcurrency();
62
+ const recoveredJobs = await this.store.recoverHandedOffJobs();
63
+ for (const job of recoveredJobs) {
64
+ this._emitBackgroundJobFailed({
65
+ error: new Error(job.lastError || "Local background job recovered after an interrupted dispatcher"),
66
+ job
67
+ });
68
+ }
69
+ this._accepting = true;
70
+ this._started = true;
71
+ this.wake();
72
+ })();
73
+ try {
74
+ await this._startPromise;
75
+ }
76
+ catch (error) {
77
+ this._reportFrameworkError({ error, stage: "local-background-jobs-start" });
78
+ throw error;
79
+ }
80
+ finally {
81
+ this._startPromise = null;
82
+ }
83
+ }
84
+ /**
85
+ * Coalesces a dispatcher wake onto one tracked microtask.
86
+ * @returns {void} - No return value.
87
+ */
88
+ wake() {
89
+ if (!this._accepting)
90
+ return;
91
+ if (this._drainPromise || this._wakeQueued) {
92
+ this._redrain = true;
93
+ return;
94
+ }
95
+ this._wakeQueued = true;
96
+ const drain = Promise.resolve().then(async () => {
97
+ this._wakeQueued = false;
98
+ await this._drain();
99
+ });
100
+ const drainPromise = drain
101
+ .catch((error) => {
102
+ this._reportFrameworkError({ error, stage: "local-background-jobs-drain" });
103
+ this._armRecoveryTimer();
104
+ })
105
+ .finally(() => {
106
+ if (this._drainPromise === drainPromise)
107
+ this._drainPromise = null;
108
+ if (this._redrain && this._accepting) {
109
+ this._redrain = false;
110
+ this.wake();
111
+ }
112
+ else {
113
+ this._resolveIdleWaiters();
114
+ }
115
+ });
116
+ this._drainPromise = drainPromise;
117
+ }
118
+ /**
119
+ * Fills local capacity with short durable claims.
120
+ * @returns {Promise<void>} - Resolves after one stable drain pass.
121
+ */
122
+ async _drain() {
123
+ await this._retryPendingAcknowledgements();
124
+ while (this._accepting && this._ownedPerformanceCount() < this._maxConcurrentJobs()) {
125
+ const job = await this.store.nextAvailableJob();
126
+ if (!job)
127
+ break;
128
+ const handoff = await this.store.markHandedOff({ jobId: job.id });
129
+ if (!handoff) {
130
+ this._redrain = true;
131
+ break;
132
+ }
133
+ this._startPerformance({ handoff, job });
134
+ }
135
+ await this._armScheduledTimer();
136
+ }
137
+ /**
138
+ * Runs one claimed performance without retaining its claim transaction connection.
139
+ * @param {{handoff: import("./types.js").BackgroundJobHandoff, job: import("./types.js").BackgroundJobRow}} args - Claimed job.
140
+ * @returns {void} - No return value.
141
+ */
142
+ _startPerformance({ handoff, job }) {
143
+ const performance = this._perform({ handoff, job });
144
+ this._inFlight.add(performance);
145
+ void performance
146
+ .catch((error) => this._reportFrameworkError({ error, stage: "local-background-jobs-performance" }))
147
+ .finally(() => {
148
+ this._inFlight.delete(performance);
149
+ if (this._accepting)
150
+ this.wake();
151
+ this._resolveIdleWaiters();
152
+ });
153
+ }
154
+ /**
155
+ * Performs and acknowledges one durable handoff.
156
+ * @param {{handoff: import("./types.js").BackgroundJobHandoff, job: import("./types.js").BackgroundJobRow}} args - Claimed job.
157
+ * @returns {Promise<void>} - Resolves after acknowledgement.
158
+ */
159
+ async _perform({ handoff, job }) {
160
+ /** @type {LocalBackgroundJobAcknowledgement} */
161
+ let acknowledgement = { type: "completed" };
162
+ try {
163
+ const JobClass = this.registry.resolve(job.jobName);
164
+ await performBackgroundJob({
165
+ configuration: this.configuration,
166
+ JobClass,
167
+ jobArgs: job.args,
168
+ name: `Local background job: ${job.jobName}`
169
+ });
170
+ }
171
+ catch (error) {
172
+ if (error instanceof BackgroundJobRescheduleSignal) {
173
+ acknowledgement = { delayMs: error.delayMs, type: "rescheduled" };
174
+ }
175
+ else {
176
+ acknowledgement = { error, type: "failed" };
177
+ }
178
+ }
179
+ try {
180
+ await this._acknowledge({ acknowledgement, handoff, job });
181
+ }
182
+ catch (error) {
183
+ this._pendingAcknowledgements.set(job.id, { acknowledgement, handoff, job });
184
+ this._reportAcknowledgementError({ acknowledgement, error, handoff, job });
185
+ }
186
+ }
187
+ /**
188
+ * Applies one fenced durable acknowledgement.
189
+ * @param {PendingLocalBackgroundJobAcknowledgement} args - Owned acknowledgement.
190
+ * @returns {Promise<void>} - Resolves after the durable transition is settled.
191
+ */
192
+ async _acknowledge({ acknowledgement, handoff, job }) {
193
+ if (acknowledgement.type === "rescheduled") {
194
+ await this.store.markRescheduled({ delayMs: acknowledgement.delayMs, handoffId: handoff.handoffId, jobId: job.id });
195
+ return;
196
+ }
197
+ if (acknowledgement.type === "failed") {
198
+ const updatedJob = await this.store.markFailed({ error: acknowledgement.error, handoffId: handoff.handoffId, jobId: job.id });
199
+ if (updatedJob)
200
+ this._emitBackgroundJobFailed({ error: acknowledgement.error, job: updatedJob });
201
+ return;
202
+ }
203
+ await this.store.markCompleted({ handoffId: handoff.handoffId, jobId: job.id });
204
+ }
205
+ /**
206
+ * Replays each retained acknowledgement once at an event-driven wake boundary.
207
+ * @param {{throwOnError?: boolean}} [args] - Recovery behavior.
208
+ * @returns {Promise<void>} - Resolves after one bounded recovery pass.
209
+ */
210
+ async _retryPendingAcknowledgements({ throwOnError = false } = {}) {
211
+ for (const [jobId, pendingAcknowledgement] of [...this._pendingAcknowledgements]) {
212
+ try {
213
+ await this._acknowledge(pendingAcknowledgement);
214
+ this._pendingAcknowledgements.delete(jobId);
215
+ }
216
+ catch (error) {
217
+ this._reportAcknowledgementError({ ...pendingAcknowledgement, error });
218
+ if (throwOnError)
219
+ throw error;
220
+ this._armRecoveryTimer();
221
+ }
222
+ }
223
+ }
224
+ /**
225
+ * Arms the exact next future job timer, chunking platform-sized delays.
226
+ * @returns {Promise<void>} - Resolves after timer reconciliation.
227
+ */
228
+ async _armScheduledTimer() {
229
+ if (this._scheduledTimer !== undefined) {
230
+ this.clock.clearTimeout(this._scheduledTimer);
231
+ this._scheduledTimer = undefined;
232
+ }
233
+ if (!this._accepting)
234
+ return;
235
+ const nextJob = await this.store.nextScheduledJob();
236
+ if (!nextJob || nextJob.scheduledAtMs === null)
237
+ return;
238
+ const delayMs = Math.max(0, Math.min(nextJob.scheduledAtMs - this.clock.now(), MAX_TIMER_MS));
239
+ this._scheduledTimer = this.clock.setTimeout(() => {
240
+ this._scheduledTimer = undefined;
241
+ this.wake();
242
+ }, delayMs);
243
+ }
244
+ /**
245
+ * Arms one bounded retry after an unexpected drain failure.
246
+ * @returns {void} - No return value.
247
+ */
248
+ _armRecoveryTimer() {
249
+ if (!this._accepting || this._recoveryTimer !== undefined)
250
+ return;
251
+ this._recoveryTimer = this.clock.setTimeout(() => {
252
+ this._recoveryTimer = undefined;
253
+ this.wake();
254
+ }, ERROR_RECOVERY_DELAY_MS);
255
+ }
256
+ /**
257
+ * Waits for admission and every in-flight acknowledgement without polling.
258
+ * @returns {Promise<void>} - Resolves when idle.
259
+ */
260
+ async waitForIdle() {
261
+ if (this._isIdle())
262
+ return;
263
+ await new Promise((resolve) => this._idleWaiters.add(() => resolve(undefined)));
264
+ }
265
+ /**
266
+ * Stops claims and waits for in-flight acknowledgement.
267
+ * @returns {Promise<void>} - Resolves after a graceful stop.
268
+ */
269
+ async stop() {
270
+ this._accepting = false;
271
+ this._redrain = false;
272
+ if (this._scheduledTimer !== undefined) {
273
+ this.clock.clearTimeout(this._scheduledTimer);
274
+ this._scheduledTimer = undefined;
275
+ }
276
+ if (this._recoveryTimer !== undefined) {
277
+ this.clock.clearTimeout(this._recoveryTimer);
278
+ this._recoveryTimer = undefined;
279
+ }
280
+ if (this._drainPromise)
281
+ await this._drainPromise;
282
+ if (this._inFlight.size > 0)
283
+ await Promise.all([...this._inFlight]);
284
+ await this._retryPendingAcknowledgements({ throwOnError: true });
285
+ this._wakeQueued = false;
286
+ this._started = false;
287
+ this._resolveIdleWaiters();
288
+ }
289
+ /**
290
+ * Reports whether dispatcher admission has started.
291
+ * @returns {boolean} - Whether dispatcher admission has started.
292
+ */
293
+ isReady() { return this._started && this._accepting; }
294
+ /**
295
+ * Reads the configuration-owned in-process performance cap.
296
+ * @returns {number} - Configuration-owned in-process performance cap.
297
+ */
298
+ _maxConcurrentJobs() { return this.configuration.getBackgroundJobsConfig().maxConcurrentInlineJobs; }
299
+ /**
300
+ * Counts performances whose durable acknowledgement is still owned locally.
301
+ * @returns {number} - Active or pending-acknowledgement performances.
302
+ */
303
+ _ownedPerformanceCount() { return this._inFlight.size + this._pendingAcknowledgements.size; }
304
+ /**
305
+ * Reports whether no admission or acknowledgement work remains.
306
+ * @returns {boolean} - Whether the dispatcher is idle.
307
+ */
308
+ _isIdle() {
309
+ return !this._wakeQueued && !this._drainPromise && this._inFlight.size === 0 && this._pendingAcknowledgements.size === 0;
310
+ }
311
+ /**
312
+ * Resolves event-based idle waiters at a stable idle boundary.
313
+ * @returns {void} - No return value.
314
+ */
315
+ _resolveIdleWaiters() {
316
+ if (!this._isIdle())
317
+ return;
318
+ const waiters = [...this._idleWaiters];
319
+ this._idleWaiters.clear();
320
+ for (const resolve of waiters)
321
+ resolve();
322
+ }
323
+ /**
324
+ * Emits an expected job failure through the standard job/all-error channels.
325
+ * @param {{error: ReturnType<typeof JSON.parse>, job: import("./types.js").BackgroundJobRow}} args - Failure transition.
326
+ * @returns {void} - No return value.
327
+ */
328
+ _emitBackgroundJobFailed({ error, job }) {
329
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
330
+ const payload = {
331
+ context: {
332
+ attempts: job.attempts,
333
+ jobArgs: job.args,
334
+ jobId: job.id,
335
+ jobName: job.jobName,
336
+ maxRetries: job.maxRetries,
337
+ stage: "background-job-failed",
338
+ status: job.status,
339
+ terminal: job.status === "failed",
340
+ willRetry: job.status === "queued",
341
+ workerId: "local"
342
+ },
343
+ error: normalizedError
344
+ };
345
+ const errorEvents = this.configuration.getErrorEvents();
346
+ errorEvents.emit("background-job-failed", payload);
347
+ errorEvents.emit("all-error", { ...payload, errorType: "background-job-failed" });
348
+ }
349
+ /**
350
+ * Reports one failed durable acknowledgement attempt with its fence context.
351
+ * @param {PendingLocalBackgroundJobAcknowledgement & {error: ReturnType<typeof JSON.parse>}} args - Failed acknowledgement.
352
+ * @returns {void} - No return value.
353
+ */
354
+ _reportAcknowledgementError({ acknowledgement, error, handoff, job }) {
355
+ this._reportFrameworkError({
356
+ context: {
357
+ acknowledgementType: acknowledgement.type,
358
+ handoffId: handoff.handoffId,
359
+ jobId: job.id,
360
+ jobName: job.jobName,
361
+ workerId: "local"
362
+ },
363
+ error,
364
+ stage: "local-background-jobs-acknowledgement"
365
+ });
366
+ }
367
+ /**
368
+ * Reports an unexpected dispatcher failure through framework channels.
369
+ * @param {object} args - Unexpected failure.
370
+ * @param {Record<string, ReturnType<typeof JSON.parse>>} [args.context] - Additional failure context.
371
+ * @param {ReturnType<typeof JSON.parse>} args.error - Unexpected error.
372
+ * @param {string} args.stage - Dispatcher stage.
373
+ * @returns {void} - No return value.
374
+ */
375
+ _reportFrameworkError({ context = {}, error, stage }) {
376
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
377
+ const payload = { context: { ...context, stage }, error: normalizedError };
378
+ const errorEvents = this.configuration.getErrorEvents();
379
+ errorEvents.emit("framework-error", payload);
380
+ errorEvents.emit("all-error", { ...payload, errorType: "framework-error" });
381
+ }
382
+ }
383
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9jYWwtZGlzcGF0Y2hlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9iYWNrZ3JvdW5kLWpvYnMvbG9jYWwtZGlzcGF0Y2hlci5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosT0FBTyw2QkFBNkIsTUFBTSx3QkFBd0IsQ0FBQTtBQUNsRSxPQUFPLG9CQUFvQixNQUFNLGtCQUFrQixDQUFBO0FBRW5ELHlLQUF5SztBQUV6Szs7Ozs7R0FLRztBQUVILE1BQU0sWUFBWSxHQUFHLGFBQWEsQ0FBQTtBQUNsQyxNQUFNLHVCQUF1QixHQUFHLEtBQUssQ0FBQTtBQUVyQyxxRUFBcUU7QUFDckUsTUFBTSxDQUFDLE9BQU8sT0FBTyw2QkFBNkI7SUFDaEQ7Ozs7Ozs7T0FPRztJQUNILFlBQVksRUFBQyxhQUFhLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUM7UUFDakQsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUE7UUFDbEIsSUFBSSxDQUFDLGFBQWEsR0FBRyxhQUFhLENBQUE7UUFDbEMsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUE7UUFDeEIsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUE7UUFDbEIsSUFBSSxDQUFDLFVBQVUsR0FBRyxLQUFLLENBQUE7UUFDdkIsSUFBSSxDQUFDLFFBQVEsR0FBRyxLQUFLLENBQUE7UUFDckIsbUNBQW1DO1FBQ25DLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxDQUFBO1FBQ3pCLG1DQUFtQztRQUNuQyxJQUFJLENBQUMsYUFBYSxHQUFHLElBQUksQ0FBQTtRQUN6QixJQUFJLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQTtRQUNyQixJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQTtRQUN4QixpQ0FBaUM7UUFDakMsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFBO1FBQzFCLG9FQUFvRTtRQUNwRSxJQUFJLENBQUMsd0JBQXdCLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQTtRQUN6Qyw4QkFBOEI7UUFDOUIsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFBO1FBQzdCLGlFQUFpRTtRQUNqRSxJQUFJLENBQUMsZUFBZSxHQUFHLFNBQVMsQ0FBQTtRQUNoQyxpRUFBaUU7UUFDakUsSUFBSSxDQUFDLGNBQWMsR0FBRyxTQUFTLENBQUE7SUFDakMsQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxLQUFLO1FBQ1QsSUFBSSxJQUFJLENBQUMsUUFBUTtZQUFFLE9BQU07UUFDekIsSUFBSSxJQUFJLENBQUMsYUFBYTtZQUFFLE9BQU8sTUFBTSxJQUFJLENBQUMsYUFBYSxDQUFBO1FBRXZELElBQUksQ0FBQyxhQUFhLEdBQUcsQ0FBQyxLQUFLLElBQUksRUFBRTtZQUMvQixJQUFJLENBQUMsYUFBYSxDQUFDLFVBQVUsRUFBRSxDQUFBO1lBQy9CLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxFQUFFLENBQUE7WUFDM0IsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUFDLFVBQVUsQ0FBQyxFQUFDLElBQUksRUFBRSx1QkFBdUIsRUFBQyxDQUFDLENBQUE7WUFDcEUsTUFBTSxJQUFJLENBQUMsS0FBSyxDQUFDLFdBQVcsRUFBRSxDQUFBO1lBQzlCLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyx5QkFBeUIsRUFBRSxDQUFBO1lBRTVDLE1BQU0sYUFBYSxHQUFHLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxvQkFBb0IsRUFBRSxDQUFBO1lBRTdELEtBQUssTUFBTSxHQUFHLElBQUksYUFBYSxFQUFFLENBQUM7Z0JBQ2hDLElBQUksQ0FBQyx3QkFBd0IsQ0FBQztvQkFDNUIsS0FBSyxFQUFFLElBQUksS0FBSyxDQUFDLEdBQUcsQ0FBQyxTQUFTLElBQUksZ0VBQWdFLENBQUM7b0JBQ25HLEdBQUc7aUJBQ0osQ0FBQyxDQUFBO1lBQ0osQ0FBQztZQUVELElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFBO1lBQ3RCLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFBO1lBQ3BCLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQTtRQUNiLENBQUMsQ0FBQyxFQUFFLENBQUE7UUFFSixJQUFJLENBQUM7WUFDSCxNQUFNLElBQUksQ0FBQyxhQUFhLENBQUE7UUFDMUIsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixJQUFJLENBQUMscUJBQXFCLENBQUMsRUFBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLDZCQUE2QixFQUFDLENBQUMsQ0FBQTtZQUN6RSxNQUFNLEtBQUssQ0FBQTtRQUNiLENBQUM7Z0JBQVMsQ0FBQztZQUNULElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxDQUFBO1FBQzNCLENBQUM7SUFDSCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsSUFBSTtRQUNGLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVTtZQUFFLE9BQU07UUFFNUIsSUFBSSxJQUFJLENBQUMsYUFBYSxJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUMzQyxJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQTtZQUNwQixPQUFNO1FBQ1IsQ0FBQztRQUVELElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFBO1FBQ3ZCLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxJQUFJLEVBQUU7WUFDOUMsSUFBSSxDQUFDLFdBQVcsR0FBRyxLQUFLLENBQUE7WUFDeEIsTUFBTSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUE7UUFDckIsQ0FBQyxDQUFDLENBQUE7UUFDRixNQUFNLFlBQVksR0FBRyxLQUFLO2FBQ3ZCLEtBQUssQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFO1lBQ2YsSUFBSSxDQUFDLHFCQUFxQixDQUFDLEVBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSw2QkFBNkIsRUFBQyxDQUFDLENBQUE7WUFDekUsSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUE7UUFDMUIsQ0FBQyxDQUFDO2FBQ0QsT0FBTyxDQUFDLEdBQUcsRUFBRTtZQUNaLElBQUksSUFBSSxDQUFDLGFBQWEsS0FBSyxZQUFZO2dCQUFFLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxDQUFBO1lBRWxFLElBQUksSUFBSSxDQUFDLFFBQVEsSUFBSSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7Z0JBQ3JDLElBQUksQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFBO2dCQUNyQixJQUFJLENBQUMsSUFBSSxFQUFFLENBQUE7WUFDYixDQUFDO2lCQUFNLENBQUM7Z0JBQ04sSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUE7WUFDNUIsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFBO1FBRUosSUFBSSxDQUFDLGFBQWEsR0FBRyxZQUFZLENBQUE7SUFDbkMsQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxNQUFNO1FBQ1YsTUFBTSxJQUFJLENBQUMsNkJBQTZCLEVBQUUsQ0FBQTtRQUUxQyxPQUFPLElBQUksQ0FBQyxVQUFVLElBQUksSUFBSSxDQUFDLHNCQUFzQixFQUFFLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixFQUFFLEVBQUUsQ0FBQztZQUNwRixNQUFNLEdBQUcsR0FBRyxNQUFNLElBQUksQ0FBQyxLQUFLLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQTtZQUUvQyxJQUFJLENBQUMsR0FBRztnQkFBRSxNQUFLO1lBRWYsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBQyxFQUFDLEtBQUssRUFBRSxHQUFHLENBQUMsRUFBRSxFQUFDLENBQUMsQ0FBQTtZQUUvRCxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ2IsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUE7Z0JBQ3BCLE1BQUs7WUFDUCxDQUFDO1lBRUQsSUFBSSxDQUFDLGlCQUFpQixDQUFDLEVBQUMsT0FBTyxFQUFFLEdBQUcsRUFBQyxDQUFDLENBQUE7UUFDeEMsQ0FBQztRQUVELE1BQU0sSUFBSSxDQUFDLGtCQUFrQixFQUFFLENBQUE7SUFDakMsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxpQkFBaUIsQ0FBQyxFQUFDLE9BQU8sRUFBRSxHQUFHLEVBQUM7UUFDOUIsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFDLE9BQU8sRUFBRSxHQUFHLEVBQUMsQ0FBQyxDQUFBO1FBRWpELElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFBO1FBQy9CLEtBQUssV0FBVzthQUNiLEtBQUssQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLEVBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxtQ0FBbUMsRUFBQyxDQUFDLENBQUM7YUFDakcsT0FBTyxDQUFDLEdBQUcsRUFBRTtZQUNaLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFBO1lBQ2xDLElBQUksSUFBSSxDQUFDLFVBQVU7Z0JBQUUsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFBO1lBQ2hDLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFBO1FBQzVCLENBQUMsQ0FBQyxDQUFBO0lBQ04sQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxLQUFLLENBQUMsUUFBUSxDQUFDLEVBQUMsT0FBTyxFQUFFLEdBQUcsRUFBQztRQUMzQixnREFBZ0Q7UUFDaEQsSUFBSSxlQUFlLEdBQUcsRUFBQyxJQUFJLEVBQUUsV0FBVyxFQUFDLENBQUE7UUFFekMsSUFBSSxDQUFDO1lBQ0gsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFBO1lBRW5ELE1BQU0sb0JBQW9CLENBQUM7Z0JBQ3pCLGFBQWEsRUFBRSxJQUFJLENBQUMsYUFBYTtnQkFDakMsUUFBUTtnQkFDUixPQUFPLEVBQUUsR0FBRyxDQUFDLElBQUk7Z0JBQ2pCLElBQUksRUFBRSx5QkFBeUIsR0FBRyxDQUFDLE9BQU8sRUFBRTthQUM3QyxDQUFDLENBQUE7UUFDSixDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLElBQUksS0FBSyxZQUFZLDZCQUE2QixFQUFFLENBQUM7Z0JBQ25ELGVBQWUsR0FBRyxFQUFDLE9BQU8sRUFBRSxLQUFLLENBQUMsT0FBTyxFQUFFLElBQUksRUFBRSxhQUFhLEVBQUMsQ0FBQTtZQUNqRSxDQUFDO2lCQUFNLENBQUM7Z0JBQ04sZUFBZSxHQUFHLEVBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUMsQ0FBQTtZQUMzQyxDQUFDO1FBQ0gsQ0FBQztRQUVELElBQUksQ0FBQztZQUNILE1BQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyxFQUFDLGVBQWUsRUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFDLENBQUMsQ0FBQTtRQUMxRCxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFDLGVBQWUsRUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFDLENBQUMsQ0FBQTtZQUMxRSxJQUFJLENBQUMsMkJBQTJCLENBQUMsRUFBQyxlQUFlLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUMsQ0FBQyxDQUFBO1FBQzFFLENBQUM7SUFDSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILEtBQUssQ0FBQyxZQUFZLENBQUMsRUFBQyxlQUFlLEVBQUUsT0FBTyxFQUFFLEdBQUcsRUFBQztRQUNoRCxJQUFJLGVBQWUsQ0FBQyxJQUFJLEtBQUssYUFBYSxFQUFFLENBQUM7WUFDM0MsTUFBTSxJQUFJLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQyxFQUFDLE9BQU8sRUFBRSxlQUFlLENBQUMsT0FBTyxFQUFFLFNBQVMsRUFBRSxPQUFPLENBQUMsU0FBUyxFQUFFLEtBQUssRUFBRSxHQUFHLENBQUMsRUFBRSxFQUFDLENBQUMsQ0FBQTtZQUNqSCxPQUFNO1FBQ1IsQ0FBQztRQUVELElBQUksZUFBZSxDQUFDLElBQUksS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUN0QyxNQUFNLFVBQVUsR0FBRyxNQUFNLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLEVBQUMsS0FBSyxFQUFFLGVBQWUsQ0FBQyxLQUFLLEVBQUUsU0FBUyxFQUFFLE9BQU8sQ0FBQyxTQUFTLEVBQUUsS0FBSyxFQUFFLEdBQUcsQ0FBQyxFQUFFLEVBQUMsQ0FBQyxDQUFBO1lBRTNILElBQUksVUFBVTtnQkFBRSxJQUFJLENBQUMsd0JBQXdCLENBQUMsRUFBQyxLQUFLLEVBQUUsZUFBZSxDQUFDLEtBQUssRUFBRSxHQUFHLEVBQUUsVUFBVSxFQUFDLENBQUMsQ0FBQTtZQUM5RixPQUFNO1FBQ1IsQ0FBQztRQUVELE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsRUFBQyxTQUFTLEVBQUUsT0FBTyxDQUFDLFNBQVMsRUFBRSxLQUFLLEVBQUUsR0FBRyxDQUFDLEVBQUUsRUFBQyxDQUFDLENBQUE7SUFDL0UsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxLQUFLLENBQUMsNkJBQTZCLENBQUMsRUFBQyxZQUFZLEdBQUcsS0FBSyxFQUFDLEdBQUcsRUFBRTtRQUM3RCxLQUFLLE1BQU0sQ0FBQyxLQUFLLEVBQUUsc0JBQXNCLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLHdCQUF3QixDQUFDLEVBQUUsQ0FBQztZQUNqRixJQUFJLENBQUM7Z0JBQ0gsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLHNCQUFzQixDQUFDLENBQUE7Z0JBQy9DLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUE7WUFDN0MsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YsSUFBSSxDQUFDLDJCQUEyQixDQUFDLEVBQUMsR0FBRyxzQkFBc0IsRUFBRSxLQUFLLEVBQUMsQ0FBQyxDQUFBO2dCQUNwRSxJQUFJLFlBQVk7b0JBQUUsTUFBTSxLQUFLLENBQUE7Z0JBQzdCLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFBO1lBQzFCLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxrQkFBa0I7UUFDdEIsSUFBSSxJQUFJLENBQUMsZUFBZSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3ZDLElBQUksQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQTtZQUM3QyxJQUFJLENBQUMsZUFBZSxHQUFHLFNBQVMsQ0FBQTtRQUNsQyxDQUFDO1FBQ0QsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVO1lBQUUsT0FBTTtRQUU1QixNQUFNLE9BQU8sR0FBRyxNQUFNLElBQUksQ0FBQyxLQUFLLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQTtRQUVuRCxJQUFJLENBQUMsT0FBTyxJQUFJLE9BQU8sQ0FBQyxhQUFhLEtBQUssSUFBSTtZQUFFLE9BQU07UUFFdEQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsYUFBYSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEVBQUUsWUFBWSxDQUFDLENBQUMsQ0FBQTtRQUU3RixJQUFJLENBQUMsZUFBZSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLEdBQUcsRUFBRTtZQUNoRCxJQUFJLENBQUMsZUFBZSxHQUFHLFNBQVMsQ0FBQTtZQUNoQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUE7UUFDYixDQUFDLEVBQUUsT0FBTyxDQUFDLENBQUE7SUFDYixDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsaUJBQWlCO1FBQ2YsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLElBQUksSUFBSSxDQUFDLGNBQWMsS0FBSyxTQUFTO1lBQUUsT0FBTTtRQUVqRSxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLEdBQUcsRUFBRTtZQUMvQyxJQUFJLENBQUMsY0FBYyxHQUFHLFNBQVMsQ0FBQTtZQUMvQixJQUFJLENBQUMsSUFBSSxFQUFFLENBQUE7UUFDYixDQUFDLEVBQUUsdUJBQXVCLENBQUMsQ0FBQTtJQUM3QixDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsS0FBSyxDQUFDLFdBQVc7UUFDZixJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUU7WUFBRSxPQUFNO1FBRTFCLE1BQU0sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUE7SUFDakYsQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxJQUFJO1FBQ1IsSUFBSSxDQUFDLFVBQVUsR0FBRyxLQUFLLENBQUE7UUFDdkIsSUFBSSxDQUFDLFFBQVEsR0FBRyxLQUFLLENBQUE7UUFFckIsSUFBSSxJQUFJLENBQUMsZUFBZSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3ZDLElBQUksQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQTtZQUM3QyxJQUFJLENBQUMsZUFBZSxHQUFHLFNBQVMsQ0FBQTtRQUNsQyxDQUFDO1FBQ0QsSUFBSSxJQUFJLENBQUMsY0FBYyxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3RDLElBQUksQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQTtZQUM1QyxJQUFJLENBQUMsY0FBYyxHQUFHLFNBQVMsQ0FBQTtRQUNqQyxDQUFDO1FBRUQsSUFBSSxJQUFJLENBQUMsYUFBYTtZQUFFLE1BQU0sSUFBSSxDQUFDLGFBQWEsQ0FBQTtRQUNoRCxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxHQUFHLENBQUM7WUFBRSxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFBO1FBQ25FLE1BQU0sSUFBSSxDQUFDLDZCQUE2QixDQUFDLEVBQUMsWUFBWSxFQUFFLElBQUksRUFBQyxDQUFDLENBQUE7UUFFOUQsSUFBSSxDQUFDLFdBQVcsR0FBRyxLQUFLLENBQUE7UUFDeEIsSUFBSSxDQUFDLFFBQVEsR0FBRyxLQUFLLENBQUE7UUFDckIsSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUE7SUFDNUIsQ0FBQztJQUVEOzs7T0FHRztJQUNILE9BQU8sS0FBSyxPQUFPLElBQUksQ0FBQyxRQUFRLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQSxDQUFDLENBQUM7SUFFckQ7OztPQUdHO0lBQ0gsa0JBQWtCLEtBQUssT0FBTyxJQUFJLENBQUMsYUFBYSxDQUFDLHVCQUF1QixFQUFFLENBQUMsdUJBQXVCLENBQUEsQ0FBQyxDQUFDO0lBRXBHOzs7T0FHRztJQUNILHNCQUFzQixLQUFLLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLHdCQUF3QixDQUFDLElBQUksQ0FBQSxDQUFDLENBQUM7SUFFNUY7OztPQUdHO0lBQ0gsT0FBTztRQUNMLE9BQU8sQ0FBQyxJQUFJLENBQUMsV0FBVyxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsSUFBSSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDLHdCQUF3QixDQUFDLElBQUksS0FBSyxDQUFDLENBQUE7SUFDMUgsQ0FBQztJQUVEOzs7T0FHRztJQUNILG1CQUFtQjtRQUNqQixJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRTtZQUFFLE9BQU07UUFFM0IsTUFBTSxPQUFPLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQTtRQUV0QyxJQUFJLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxDQUFBO1FBQ3pCLEtBQUssTUFBTSxPQUFPLElBQUksT0FBTztZQUFFLE9BQU8sRUFBRSxDQUFBO0lBQzFDLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsd0JBQXdCLENBQUMsRUFBQyxLQUFLLEVBQUUsR0FBRyxFQUFDO1FBQ25DLE1BQU0sZUFBZSxHQUFHLEtBQUssWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUE7UUFDakYsTUFBTSxPQUFPLEdBQUc7WUFDZCxPQUFPLEVBQUU7Z0JBQ1AsUUFBUSxFQUFFLEdBQUcsQ0FBQyxRQUFRO2dCQUN0QixPQUFPLEVBQUUsR0FBRyxDQUFDLElBQUk7Z0JBQ2pCLEtBQUssRUFBRSxHQUFHLENBQUMsRUFBRTtnQkFDYixPQUFPLEVBQUUsR0FBRyxDQUFDLE9BQU87Z0JBQ3BCLFVBQVUsRUFBRSxHQUFHLENBQUMsVUFBVTtnQkFDMUIsS0FBSyxFQUFFLHVCQUF1QjtnQkFDOUIsTUFBTSxFQUFFLEdBQUcsQ0FBQyxNQUFNO2dCQUNsQixRQUFRLEVBQUUsR0FBRyxDQUFDLE1BQU0sS0FBSyxRQUFRO2dCQUNqQyxTQUFTLEVBQUUsR0FBRyxDQUFDLE1BQU0sS0FBSyxRQUFRO2dCQUNsQyxRQUFRLEVBQUUsT0FBTzthQUNsQjtZQUNELEtBQUssRUFBRSxlQUFlO1NBQ3ZCLENBQUE7UUFDRCxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLGNBQWMsRUFBRSxDQUFBO1FBRXZELFdBQVcsQ0FBQyxJQUFJLENBQUMsdUJBQXVCLEVBQUUsT0FBTyxDQUFDLENBQUE7UUFDbEQsV0FBVyxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsRUFBQyxHQUFHLE9BQU8sRUFBRSxTQUFTLEVBQUUsdUJBQXVCLEVBQUMsQ0FBQyxDQUFBO0lBQ2pGLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsMkJBQTJCLENBQUMsRUFBQyxlQUFlLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUM7UUFDaEUsSUFBSSxDQUFDLHFCQUFxQixDQUFDO1lBQ3pCLE9BQU8sRUFBRTtnQkFDUCxtQkFBbUIsRUFBRSxlQUFlLENBQUMsSUFBSTtnQkFDekMsU0FBUyxFQUFFLE9BQU8sQ0FBQyxTQUFTO2dCQUM1QixLQUFLLEVBQUUsR0FBRyxDQUFDLEVBQUU7Z0JBQ2IsT0FBTyxFQUFFLEdBQUcsQ0FBQyxPQUFPO2dCQUNwQixRQUFRLEVBQUUsT0FBTzthQUNsQjtZQUNELEtBQUs7WUFDTCxLQUFLLEVBQUUsdUNBQXVDO1NBQy9DLENBQUMsQ0FBQTtJQUNKLENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0gscUJBQXFCLENBQUMsRUFBQyxPQUFPLEdBQUcsRUFBRSxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUM7UUFDaEQsTUFBTSxlQUFlLEdBQUcsS0FBSyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQTtRQUNqRixNQUFNLE9BQU8sR0FBRyxFQUFDLE9BQU8sRUFBRSxFQUFDLEdBQUcsT0FBTyxFQUFFLEtBQUssRUFBQyxFQUFFLEtBQUssRUFBRSxlQUFlLEVBQUMsQ0FBQTtRQUN0RSxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLGNBQWMsRUFBRSxDQUFBO1FBRXZELFdBQVcsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsT0FBTyxDQUFDLENBQUE7UUFDNUMsV0FBVyxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsRUFBQyxHQUFHLE9BQU8sRUFBRSxTQUFTLEVBQUUsaUJBQWlCLEVBQUMsQ0FBQyxDQUFBO0lBQzNFLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5pbXBvcnQgQmFja2dyb3VuZEpvYlJlc2NoZWR1bGVTaWduYWwgZnJvbSBcIi4vcmVzY2hlZHVsZS1zaWduYWwuanNcIlxuaW1wb3J0IHBlcmZvcm1CYWNrZ3JvdW5kSm9iIGZyb20gXCIuL3BlcmZvcm0tam9iLmpzXCJcblxuLyoqIEB0eXBlZGVmIHt7dHlwZTogXCJjb21wbGV0ZWRcIn0gfCB7dHlwZTogXCJmYWlsZWRcIiwgZXJyb3I6IFJldHVyblR5cGU8dHlwZW9mIEpTT04ucGFyc2U+fSB8IHt0eXBlOiBcInJlc2NoZWR1bGVkXCIsIGRlbGF5TXM6IG51bWJlcn19IExvY2FsQmFja2dyb3VuZEpvYkFja25vd2xlZGdlbWVudCAqL1xuXG4vKipcbiAqIEB0eXBlZGVmIHtvYmplY3R9IFBlbmRpbmdMb2NhbEJhY2tncm91bmRKb2JBY2tub3dsZWRnZW1lbnRcbiAqIEBwcm9wZXJ0eSB7TG9jYWxCYWNrZ3JvdW5kSm9iQWNrbm93bGVkZ2VtZW50fSBhY2tub3dsZWRnZW1lbnQgLSBEdXJhYmxlIHRyYW5zaXRpb24gc3RpbGwgb3duZWQgYnkgdGhpcyBkaXNwYXRjaGVyLlxuICogQHByb3BlcnR5IHtpbXBvcnQoXCIuL3R5cGVzLmpzXCIpLkJhY2tncm91bmRKb2JIYW5kb2ZmfSBoYW5kb2ZmIC0gRmVuY2VkIGhhbmRvZmYgYmVpbmcgYWNrbm93bGVkZ2VkLlxuICogQHByb3BlcnR5IHtpbXBvcnQoXCIuL3R5cGVzLmpzXCIpLkJhY2tncm91bmRKb2JSb3d9IGpvYiAtIENsYWltZWQgam9iIHNuYXBzaG90LlxuICovXG5cbmNvbnN0IE1BWF9USU1FUl9NUyA9IDJfMTQ3XzQ4M182NDdcbmNvbnN0IEVSUk9SX1JFQ09WRVJZX0RFTEFZX01TID0gMV8wMDBcblxuLyoqIENvbmZpZ3VyYXRpb24tb3duZWQsIGV2ZW50LWRyaXZlbiBpbi1wcm9jZXNzIGxvY2FsIGRpc3BhdGNoZXIuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBMb2NhbEJhY2tncm91bmRKb2JzRGlzcGF0Y2hlciB7XG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgZGlzcGF0Y2hlciBvd25lZCBieSBvbmUgY29uZmlndXJhdGlvbiBhbmQgbG9jYWwgc3RvcmUuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gRGlzcGF0Y2hlciBvcHRpb25zLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24uanNcIikuZGVmYXVsdH0gYXJncy5jb25maWd1cmF0aW9uIC0gT3duaW5nIGNvbmZpZ3VyYXRpb24uXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi90eXBlcy5qc1wiKS5Mb2NhbEJhY2tncm91bmRKb2JzQ2xvY2t9IGFyZ3MuY2xvY2sgLSBEaXNwYXRjaGVyIGNsb2NrLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vbG9jYWwtam9iLXJlZ2lzdHJ5LmpzXCIpLmRlZmF1bHR9IGFyZ3MucmVnaXN0cnkgLSBTdGF0aWMgam9iIHJlZ2lzdHJ5LlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vbG9jYWwtc3RvcmUuanNcIikuZGVmYXVsdH0gYXJncy5zdG9yZSAtIER1cmFibGUgbG9jYWwgc3RvcmUuXG4gICAqL1xuICBjb25zdHJ1Y3Rvcih7Y29uZmlndXJhdGlvbiwgY2xvY2ssIHJlZ2lzdHJ5LCBzdG9yZX0pIHtcbiAgICB0aGlzLmNsb2NrID0gY2xvY2tcbiAgICB0aGlzLmNvbmZpZ3VyYXRpb24gPSBjb25maWd1cmF0aW9uXG4gICAgdGhpcy5yZWdpc3RyeSA9IHJlZ2lzdHJ5XG4gICAgdGhpcy5zdG9yZSA9IHN0b3JlXG4gICAgdGhpcy5fYWNjZXB0aW5nID0gZmFsc2VcbiAgICB0aGlzLl9zdGFydGVkID0gZmFsc2VcbiAgICAvKiogQHR5cGUge1Byb21pc2U8dm9pZD4gfCBudWxsfSAqL1xuICAgIHRoaXMuX3N0YXJ0UHJvbWlzZSA9IG51bGxcbiAgICAvKiogQHR5cGUge1Byb21pc2U8dm9pZD4gfCBudWxsfSAqL1xuICAgIHRoaXMuX2RyYWluUHJvbWlzZSA9IG51bGxcbiAgICB0aGlzLl9yZWRyYWluID0gZmFsc2VcbiAgICB0aGlzLl93YWtlUXVldWVkID0gZmFsc2VcbiAgICAvKiogQHR5cGUge1NldDxQcm9taXNlPHZvaWQ+Pn0gKi9cbiAgICB0aGlzLl9pbkZsaWdodCA9IG5ldyBTZXQoKVxuICAgIC8qKiBAdHlwZSB7TWFwPHN0cmluZywgUGVuZGluZ0xvY2FsQmFja2dyb3VuZEpvYkFja25vd2xlZGdlbWVudD59ICovXG4gICAgdGhpcy5fcGVuZGluZ0Fja25vd2xlZGdlbWVudHMgPSBuZXcgTWFwKClcbiAgICAvKiogQHR5cGUge1NldDwoKSA9PiB2b2lkPn0gKi9cbiAgICB0aGlzLl9pZGxlV2FpdGVycyA9IG5ldyBTZXQoKVxuICAgIC8qKiBAdHlwZSB7UmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD4gfCBudW1iZXIgfCB1bmRlZmluZWR9ICovXG4gICAgdGhpcy5fc2NoZWR1bGVkVGltZXIgPSB1bmRlZmluZWRcbiAgICAvKiogQHR5cGUge1JldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgbnVtYmVyIHwgdW5kZWZpbmVkfSAqL1xuICAgIHRoaXMuX3JlY292ZXJ5VGltZXIgPSB1bmRlZmluZWRcbiAgfVxuXG4gIC8qKlxuICAgKiBTdGFydHMsIHJlY292ZXJzLCBhbmQgY2F0Y2hlcyB1cCB0aGUgbG9jYWwgZGlzcGF0Y2hlci5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgYWZ0ZXIgYWRtaXNzaW9uIHN0YXJ0cy5cbiAgICovXG4gIGFzeW5jIHN0YXJ0KCkge1xuICAgIGlmICh0aGlzLl9zdGFydGVkKSByZXR1cm5cbiAgICBpZiAodGhpcy5fc3RhcnRQcm9taXNlKSByZXR1cm4gYXdhaXQgdGhpcy5fc3RhcnRQcm9taXNlXG5cbiAgICB0aGlzLl9zdGFydFByb21pc2UgPSAoYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5jb25maWd1cmF0aW9uLnNldEN1cnJlbnQoKVxuICAgICAgdGhpcy5yZWdpc3RyeS5lbnN1cmVSZWFkeSgpXG4gICAgICBhd2FpdCB0aGlzLmNvbmZpZ3VyYXRpb24uaW5pdGlhbGl6ZSh7dHlwZTogXCJsb2NhbC1iYWNrZ3JvdW5kLWpvYnNcIn0pXG4gICAgICBhd2FpdCB0aGlzLnN0b3JlLmVuc3VyZVJlYWR5KClcbiAgICAgIGF3YWl0IHRoaXMuc3RvcmUucmVjb25jaWxlUXVldWVDb25jdXJyZW5jeSgpXG5cbiAgICAgIGNvbnN0IHJlY292ZXJlZEpvYnMgPSBhd2FpdCB0aGlzLnN0b3JlLnJlY292ZXJIYW5kZWRPZmZKb2JzKClcblxuICAgICAgZm9yIChjb25zdCBqb2Igb2YgcmVjb3ZlcmVkSm9icykge1xuICAgICAgICB0aGlzLl9lbWl0QmFja2dyb3VuZEpvYkZhaWxlZCh7XG4gICAgICAgICAgZXJyb3I6IG5ldyBFcnJvcihqb2IubGFzdEVycm9yIHx8IFwiTG9jYWwgYmFja2dyb3VuZCBqb2IgcmVjb3ZlcmVkIGFmdGVyIGFuIGludGVycnVwdGVkIGRpc3BhdGNoZXJcIiksXG4gICAgICAgICAgam9iXG4gICAgICAgIH0pXG4gICAgICB9XG5cbiAgICAgIHRoaXMuX2FjY2VwdGluZyA9IHRydWVcbiAgICAgIHRoaXMuX3N0YXJ0ZWQgPSB0cnVlXG4gICAgICB0aGlzLndha2UoKVxuICAgIH0pKClcblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLl9zdGFydFByb21pc2VcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhpcy5fcmVwb3J0RnJhbWV3b3JrRXJyb3Ioe2Vycm9yLCBzdGFnZTogXCJsb2NhbC1iYWNrZ3JvdW5kLWpvYnMtc3RhcnRcIn0pXG4gICAgICB0aHJvdyBlcnJvclxuICAgIH0gZmluYWxseSB7XG4gICAgICB0aGlzLl9zdGFydFByb21pc2UgPSBudWxsXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENvYWxlc2NlcyBhIGRpc3BhdGNoZXIgd2FrZSBvbnRvIG9uZSB0cmFja2VkIG1pY3JvdGFzay5cbiAgICogQHJldHVybnMge3ZvaWR9IC0gTm8gcmV0dXJuIHZhbHVlLlxuICAgKi9cbiAgd2FrZSgpIHtcbiAgICBpZiAoIXRoaXMuX2FjY2VwdGluZykgcmV0dXJuXG5cbiAgICBpZiAodGhpcy5fZHJhaW5Qcm9taXNlIHx8IHRoaXMuX3dha2VRdWV1ZWQpIHtcbiAgICAgIHRoaXMuX3JlZHJhaW4gPSB0cnVlXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICB0aGlzLl93YWtlUXVldWVkID0gdHJ1ZVxuICAgIGNvbnN0IGRyYWluID0gUHJvbWlzZS5yZXNvbHZlKCkudGhlbihhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLl93YWtlUXVldWVkID0gZmFsc2VcbiAgICAgIGF3YWl0IHRoaXMuX2RyYWluKClcbiAgICB9KVxuICAgIGNvbnN0IGRyYWluUHJvbWlzZSA9IGRyYWluXG4gICAgICAuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgICAgIHRoaXMuX3JlcG9ydEZyYW1ld29ya0Vycm9yKHtlcnJvciwgc3RhZ2U6IFwibG9jYWwtYmFja2dyb3VuZC1qb2JzLWRyYWluXCJ9KVxuICAgICAgICB0aGlzLl9hcm1SZWNvdmVyeVRpbWVyKClcbiAgICAgIH0pXG4gICAgICAuZmluYWxseSgoKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLl9kcmFpblByb21pc2UgPT09IGRyYWluUHJvbWlzZSkgdGhpcy5fZHJhaW5Qcm9taXNlID0gbnVsbFxuXG4gICAgICAgIGlmICh0aGlzLl9yZWRyYWluICYmIHRoaXMuX2FjY2VwdGluZykge1xuICAgICAgICAgIHRoaXMuX3JlZHJhaW4gPSBmYWxzZVxuICAgICAgICAgIHRoaXMud2FrZSgpXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5fcmVzb2x2ZUlkbGVXYWl0ZXJzKClcbiAgICAgICAgfVxuICAgICAgfSlcblxuICAgIHRoaXMuX2RyYWluUHJvbWlzZSA9IGRyYWluUHJvbWlzZVxuICB9XG5cbiAgLyoqXG4gICAqIEZpbGxzIGxvY2FsIGNhcGFjaXR5IHdpdGggc2hvcnQgZHVyYWJsZSBjbGFpbXMuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIGFmdGVyIG9uZSBzdGFibGUgZHJhaW4gcGFzcy5cbiAgICovXG4gIGFzeW5jIF9kcmFpbigpIHtcbiAgICBhd2FpdCB0aGlzLl9yZXRyeVBlbmRpbmdBY2tub3dsZWRnZW1lbnRzKClcblxuICAgIHdoaWxlICh0aGlzLl9hY2NlcHRpbmcgJiYgdGhpcy5fb3duZWRQZXJmb3JtYW5jZUNvdW50KCkgPCB0aGlzLl9tYXhDb25jdXJyZW50Sm9icygpKSB7XG4gICAgICBjb25zdCBqb2IgPSBhd2FpdCB0aGlzLnN0b3JlLm5leHRBdmFpbGFibGVKb2IoKVxuXG4gICAgICBpZiAoIWpvYikgYnJlYWtcblxuICAgICAgY29uc3QgaGFuZG9mZiA9IGF3YWl0IHRoaXMuc3RvcmUubWFya0hhbmRlZE9mZih7am9iSWQ6IGpvYi5pZH0pXG5cbiAgICAgIGlmICghaGFuZG9mZikge1xuICAgICAgICB0aGlzLl9yZWRyYWluID0gdHJ1ZVxuICAgICAgICBicmVha1xuICAgICAgfVxuXG4gICAgICB0aGlzLl9zdGFydFBlcmZvcm1hbmNlKHtoYW5kb2ZmLCBqb2J9KVxuICAgIH1cblxuICAgIGF3YWl0IHRoaXMuX2FybVNjaGVkdWxlZFRpbWVyKClcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIG9uZSBjbGFpbWVkIHBlcmZvcm1hbmNlIHdpdGhvdXQgcmV0YWluaW5nIGl0cyBjbGFpbSB0cmFuc2FjdGlvbiBjb25uZWN0aW9uLlxuICAgKiBAcGFyYW0ge3toYW5kb2ZmOiBpbXBvcnQoXCIuL3R5cGVzLmpzXCIpLkJhY2tncm91bmRKb2JIYW5kb2ZmLCBqb2I6IGltcG9ydChcIi4vdHlwZXMuanNcIikuQmFja2dyb3VuZEpvYlJvd319IGFyZ3MgLSBDbGFpbWVkIGpvYi5cbiAgICogQHJldHVybnMge3ZvaWR9IC0gTm8gcmV0dXJuIHZhbHVlLlxuICAgKi9cbiAgX3N0YXJ0UGVyZm9ybWFuY2Uoe2hhbmRvZmYsIGpvYn0pIHtcbiAgICBjb25zdCBwZXJmb3JtYW5jZSA9IHRoaXMuX3BlcmZvcm0oe2hhbmRvZmYsIGpvYn0pXG5cbiAgICB0aGlzLl9pbkZsaWdodC5hZGQocGVyZm9ybWFuY2UpXG4gICAgdm9pZCBwZXJmb3JtYW5jZVxuICAgICAgLmNhdGNoKChlcnJvcikgPT4gdGhpcy5fcmVwb3J0RnJhbWV3b3JrRXJyb3Ioe2Vycm9yLCBzdGFnZTogXCJsb2NhbC1iYWNrZ3JvdW5kLWpvYnMtcGVyZm9ybWFuY2VcIn0pKVxuICAgICAgLmZpbmFsbHkoKCkgPT4ge1xuICAgICAgICB0aGlzLl9pbkZsaWdodC5kZWxldGUocGVyZm9ybWFuY2UpXG4gICAgICAgIGlmICh0aGlzLl9hY2NlcHRpbmcpIHRoaXMud2FrZSgpXG4gICAgICAgIHRoaXMuX3Jlc29sdmVJZGxlV2FpdGVycygpXG4gICAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIFBlcmZvcm1zIGFuZCBhY2tub3dsZWRnZXMgb25lIGR1cmFibGUgaGFuZG9mZi5cbiAgICogQHBhcmFtIHt7aGFuZG9mZjogaW1wb3J0KFwiLi90eXBlcy5qc1wiKS5CYWNrZ3JvdW5kSm9iSGFuZG9mZiwgam9iOiBpbXBvcnQoXCIuL3R5cGVzLmpzXCIpLkJhY2tncm91bmRKb2JSb3d9fSBhcmdzIC0gQ2xhaW1lZCBqb2IuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIGFmdGVyIGFja25vd2xlZGdlbWVudC5cbiAgICovXG4gIGFzeW5jIF9wZXJmb3JtKHtoYW5kb2ZmLCBqb2J9KSB7XG4gICAgLyoqIEB0eXBlIHtMb2NhbEJhY2tncm91bmRKb2JBY2tub3dsZWRnZW1lbnR9ICovXG4gICAgbGV0IGFja25vd2xlZGdlbWVudCA9IHt0eXBlOiBcImNvbXBsZXRlZFwifVxuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IEpvYkNsYXNzID0gdGhpcy5yZWdpc3RyeS5yZXNvbHZlKGpvYi5qb2JOYW1lKVxuXG4gICAgICBhd2FpdCBwZXJmb3JtQmFja2dyb3VuZEpvYih7XG4gICAgICAgIGNvbmZpZ3VyYXRpb246IHRoaXMuY29uZmlndXJhdGlvbixcbiAgICAgICAgSm9iQ2xhc3MsXG4gICAgICAgIGpvYkFyZ3M6IGpvYi5hcmdzLFxuICAgICAgICBuYW1lOiBgTG9jYWwgYmFja2dyb3VuZCBqb2I6ICR7am9iLmpvYk5hbWV9YFxuICAgICAgfSlcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgQmFja2dyb3VuZEpvYlJlc2NoZWR1bGVTaWduYWwpIHtcbiAgICAgICAgYWNrbm93bGVkZ2VtZW50ID0ge2RlbGF5TXM6IGVycm9yLmRlbGF5TXMsIHR5cGU6IFwicmVzY2hlZHVsZWRcIn1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGFja25vd2xlZGdlbWVudCA9IHtlcnJvciwgdHlwZTogXCJmYWlsZWRcIn1cbiAgICAgIH1cbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5fYWNrbm93bGVkZ2Uoe2Fja25vd2xlZGdlbWVudCwgaGFuZG9mZiwgam9ifSlcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhpcy5fcGVuZGluZ0Fja25vd2xlZGdlbWVudHMuc2V0KGpvYi5pZCwge2Fja25vd2xlZGdlbWVudCwgaGFuZG9mZiwgam9ifSlcbiAgICAgIHRoaXMuX3JlcG9ydEFja25vd2xlZGdlbWVudEVycm9yKHthY2tub3dsZWRnZW1lbnQsIGVycm9yLCBoYW5kb2ZmLCBqb2J9KVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBBcHBsaWVzIG9uZSBmZW5jZWQgZHVyYWJsZSBhY2tub3dsZWRnZW1lbnQuXG4gICAqIEBwYXJhbSB7UGVuZGluZ0xvY2FsQmFja2dyb3VuZEpvYkFja25vd2xlZGdlbWVudH0gYXJncyAtIE93bmVkIGFja25vd2xlZGdlbWVudC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgYWZ0ZXIgdGhlIGR1cmFibGUgdHJhbnNpdGlvbiBpcyBzZXR0bGVkLlxuICAgKi9cbiAgYXN5bmMgX2Fja25vd2xlZGdlKHthY2tub3dsZWRnZW1lbnQsIGhhbmRvZmYsIGpvYn0pIHtcbiAgICBpZiAoYWNrbm93bGVkZ2VtZW50LnR5cGUgPT09IFwicmVzY2hlZHVsZWRcIikge1xuICAgICAgYXdhaXQgdGhpcy5zdG9yZS5tYXJrUmVzY2hlZHVsZWQoe2RlbGF5TXM6IGFja25vd2xlZGdlbWVudC5kZWxheU1zLCBoYW5kb2ZmSWQ6IGhhbmRvZmYuaGFuZG9mZklkLCBqb2JJZDogam9iLmlkfSlcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIGlmIChhY2tub3dsZWRnZW1lbnQudHlwZSA9PT0gXCJmYWlsZWRcIikge1xuICAgICAgY29uc3QgdXBkYXRlZEpvYiA9IGF3YWl0IHRoaXMuc3RvcmUubWFya0ZhaWxlZCh7ZXJyb3I6IGFja25vd2xlZGdlbWVudC5lcnJvciwgaGFuZG9mZklkOiBoYW5kb2ZmLmhhbmRvZmZJZCwgam9iSWQ6IGpvYi5pZH0pXG5cbiAgICAgIGlmICh1cGRhdGVkSm9iKSB0aGlzLl9lbWl0QmFja2dyb3VuZEpvYkZhaWxlZCh7ZXJyb3I6IGFja25vd2xlZGdlbWVudC5lcnJvciwgam9iOiB1cGRhdGVkSm9ifSlcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIGF3YWl0IHRoaXMuc3RvcmUubWFya0NvbXBsZXRlZCh7aGFuZG9mZklkOiBoYW5kb2ZmLmhhbmRvZmZJZCwgam9iSWQ6IGpvYi5pZH0pXG4gIH1cblxuICAvKipcbiAgICogUmVwbGF5cyBlYWNoIHJldGFpbmVkIGFja25vd2xlZGdlbWVudCBvbmNlIGF0IGFuIGV2ZW50LWRyaXZlbiB3YWtlIGJvdW5kYXJ5LlxuICAgKiBAcGFyYW0ge3t0aHJvd09uRXJyb3I/OiBib29sZWFufX0gW2FyZ3NdIC0gUmVjb3ZlcnkgYmVoYXZpb3IuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIGFmdGVyIG9uZSBib3VuZGVkIHJlY292ZXJ5IHBhc3MuXG4gICAqL1xuICBhc3luYyBfcmV0cnlQZW5kaW5nQWNrbm93bGVkZ2VtZW50cyh7dGhyb3dPbkVycm9yID0gZmFsc2V9ID0ge30pIHtcbiAgICBmb3IgKGNvbnN0IFtqb2JJZCwgcGVuZGluZ0Fja25vd2xlZGdlbWVudF0gb2YgWy4uLnRoaXMuX3BlbmRpbmdBY2tub3dsZWRnZW1lbnRzXSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgdGhpcy5fYWNrbm93bGVkZ2UocGVuZGluZ0Fja25vd2xlZGdlbWVudClcbiAgICAgICAgdGhpcy5fcGVuZGluZ0Fja25vd2xlZGdlbWVudHMuZGVsZXRlKGpvYklkKVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgdGhpcy5fcmVwb3J0QWNrbm93bGVkZ2VtZW50RXJyb3Ioey4uLnBlbmRpbmdBY2tub3dsZWRnZW1lbnQsIGVycm9yfSlcbiAgICAgICAgaWYgKHRocm93T25FcnJvcikgdGhyb3cgZXJyb3JcbiAgICAgICAgdGhpcy5fYXJtUmVjb3ZlcnlUaW1lcigpXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEFybXMgdGhlIGV4YWN0IG5leHQgZnV0dXJlIGpvYiB0aW1lciwgY2h1bmtpbmcgcGxhdGZvcm0tc2l6ZWQgZGVsYXlzLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyBhZnRlciB0aW1lciByZWNvbmNpbGlhdGlvbi5cbiAgICovXG4gIGFzeW5jIF9hcm1TY2hlZHVsZWRUaW1lcigpIHtcbiAgICBpZiAodGhpcy5fc2NoZWR1bGVkVGltZXIgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhpcy5jbG9jay5jbGVhclRpbWVvdXQodGhpcy5fc2NoZWR1bGVkVGltZXIpXG4gICAgICB0aGlzLl9zY2hlZHVsZWRUaW1lciA9IHVuZGVmaW5lZFxuICAgIH1cbiAgICBpZiAoIXRoaXMuX2FjY2VwdGluZykgcmV0dXJuXG5cbiAgICBjb25zdCBuZXh0Sm9iID0gYXdhaXQgdGhpcy5zdG9yZS5uZXh0U2NoZWR1bGVkSm9iKClcblxuICAgIGlmICghbmV4dEpvYiB8fCBuZXh0Sm9iLnNjaGVkdWxlZEF0TXMgPT09IG51bGwpIHJldHVyblxuXG4gICAgY29uc3QgZGVsYXlNcyA9IE1hdGgubWF4KDAsIE1hdGgubWluKG5leHRKb2Iuc2NoZWR1bGVkQXRNcyAtIHRoaXMuY2xvY2subm93KCksIE1BWF9USU1FUl9NUykpXG5cbiAgICB0aGlzLl9zY2hlZHVsZWRUaW1lciA9IHRoaXMuY2xvY2suc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLl9zY2hlZHVsZWRUaW1lciA9IHVuZGVmaW5lZFxuICAgICAgdGhpcy53YWtlKClcbiAgICB9LCBkZWxheU1zKVxuICB9XG5cbiAgLyoqXG4gICAqIEFybXMgb25lIGJvdW5kZWQgcmV0cnkgYWZ0ZXIgYW4gdW5leHBlY3RlZCBkcmFpbiBmYWlsdXJlLlxuICAgKiBAcmV0dXJucyB7dm9pZH0gLSBObyByZXR1cm4gdmFsdWUuXG4gICAqL1xuICBfYXJtUmVjb3ZlcnlUaW1lcigpIHtcbiAgICBpZiAoIXRoaXMuX2FjY2VwdGluZyB8fCB0aGlzLl9yZWNvdmVyeVRpbWVyICE9PSB1bmRlZmluZWQpIHJldHVyblxuXG4gICAgdGhpcy5fcmVjb3ZlcnlUaW1lciA9IHRoaXMuY2xvY2suc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLl9yZWNvdmVyeVRpbWVyID0gdW5kZWZpbmVkXG4gICAgICB0aGlzLndha2UoKVxuICAgIH0sIEVSUk9SX1JFQ09WRVJZX0RFTEFZX01TKVxuICB9XG5cbiAgLyoqXG4gICAqIFdhaXRzIGZvciBhZG1pc3Npb24gYW5kIGV2ZXJ5IGluLWZsaWdodCBhY2tub3dsZWRnZW1lbnQgd2l0aG91dCBwb2xsaW5nLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIGlkbGUuXG4gICAqL1xuICBhc3luYyB3YWl0Rm9ySWRsZSgpIHtcbiAgICBpZiAodGhpcy5faXNJZGxlKCkpIHJldHVyblxuXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHRoaXMuX2lkbGVXYWl0ZXJzLmFkZCgoKSA9PiByZXNvbHZlKHVuZGVmaW5lZCkpKVxuICB9XG5cbiAgLyoqXG4gICAqIFN0b3BzIGNsYWltcyBhbmQgd2FpdHMgZm9yIGluLWZsaWdodCBhY2tub3dsZWRnZW1lbnQuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIGFmdGVyIGEgZ3JhY2VmdWwgc3RvcC5cbiAgICovXG4gIGFzeW5jIHN0b3AoKSB7XG4gICAgdGhpcy5fYWNjZXB0aW5nID0gZmFsc2VcbiAgICB0aGlzLl9yZWRyYWluID0gZmFsc2VcblxuICAgIGlmICh0aGlzLl9zY2hlZHVsZWRUaW1lciAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLmNsb2NrLmNsZWFyVGltZW91dCh0aGlzLl9zY2hlZHVsZWRUaW1lcilcbiAgICAgIHRoaXMuX3NjaGVkdWxlZFRpbWVyID0gdW5kZWZpbmVkXG4gICAgfVxuICAgIGlmICh0aGlzLl9yZWNvdmVyeVRpbWVyICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHRoaXMuY2xvY2suY2xlYXJUaW1lb3V0KHRoaXMuX3JlY292ZXJ5VGltZXIpXG4gICAgICB0aGlzLl9yZWNvdmVyeVRpbWVyID0gdW5kZWZpbmVkXG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX2RyYWluUHJvbWlzZSkgYXdhaXQgdGhpcy5fZHJhaW5Qcm9taXNlXG4gICAgaWYgKHRoaXMuX2luRmxpZ2h0LnNpemUgPiAwKSBhd2FpdCBQcm9taXNlLmFsbChbLi4udGhpcy5faW5GbGlnaHRdKVxuICAgIGF3YWl0IHRoaXMuX3JldHJ5UGVuZGluZ0Fja25vd2xlZGdlbWVudHMoe3Rocm93T25FcnJvcjogdHJ1ZX0pXG5cbiAgICB0aGlzLl93YWtlUXVldWVkID0gZmFsc2VcbiAgICB0aGlzLl9zdGFydGVkID0gZmFsc2VcbiAgICB0aGlzLl9yZXNvbHZlSWRsZVdhaXRlcnMoKVxuICB9XG5cbiAgLyoqXG4gICAqIFJlcG9ydHMgd2hldGhlciBkaXNwYXRjaGVyIGFkbWlzc2lvbiBoYXMgc3RhcnRlZC5cbiAgICogQHJldHVybnMge2Jvb2xlYW59IC0gV2hldGhlciBkaXNwYXRjaGVyIGFkbWlzc2lvbiBoYXMgc3RhcnRlZC5cbiAgICovXG4gIGlzUmVhZHkoKSB7IHJldHVybiB0aGlzLl9zdGFydGVkICYmIHRoaXMuX2FjY2VwdGluZyB9XG5cbiAgLyoqXG4gICAqIFJlYWRzIHRoZSBjb25maWd1cmF0aW9uLW93bmVkIGluLXByb2Nlc3MgcGVyZm9ybWFuY2UgY2FwLlxuICAgKiBAcmV0dXJucyB7bnVtYmVyfSAtIENvbmZpZ3VyYXRpb24tb3duZWQgaW4tcHJvY2VzcyBwZXJmb3JtYW5jZSBjYXAuXG4gICAqL1xuICBfbWF4Q29uY3VycmVudEpvYnMoKSB7IHJldHVybiB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0QmFja2dyb3VuZEpvYnNDb25maWcoKS5tYXhDb25jdXJyZW50SW5saW5lSm9icyB9XG5cbiAgLyoqXG4gICAqIENvdW50cyBwZXJmb3JtYW5jZXMgd2hvc2UgZHVyYWJsZSBhY2tub3dsZWRnZW1lbnQgaXMgc3RpbGwgb3duZWQgbG9jYWxseS5cbiAgICogQHJldHVybnMge251bWJlcn0gLSBBY3RpdmUgb3IgcGVuZGluZy1hY2tub3dsZWRnZW1lbnQgcGVyZm9ybWFuY2VzLlxuICAgKi9cbiAgX293bmVkUGVyZm9ybWFuY2VDb3VudCgpIHsgcmV0dXJuIHRoaXMuX2luRmxpZ2h0LnNpemUgKyB0aGlzLl9wZW5kaW5nQWNrbm93bGVkZ2VtZW50cy5zaXplIH1cblxuICAvKipcbiAgICogUmVwb3J0cyB3aGV0aGVyIG5vIGFkbWlzc2lvbiBvciBhY2tub3dsZWRnZW1lbnQgd29yayByZW1haW5zLlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBXaGV0aGVyIHRoZSBkaXNwYXRjaGVyIGlzIGlkbGUuXG4gICAqL1xuICBfaXNJZGxlKCkge1xuICAgIHJldHVybiAhdGhpcy5fd2FrZVF1ZXVlZCAmJiAhdGhpcy5fZHJhaW5Qcm9taXNlICYmIHRoaXMuX2luRmxpZ2h0LnNpemUgPT09IDAgJiYgdGhpcy5fcGVuZGluZ0Fja25vd2xlZGdlbWVudHMuc2l6ZSA9PT0gMFxuICB9XG5cbiAgLyoqXG4gICAqIFJlc29sdmVzIGV2ZW50LWJhc2VkIGlkbGUgd2FpdGVycyBhdCBhIHN0YWJsZSBpZGxlIGJvdW5kYXJ5LlxuICAgKiBAcmV0dXJucyB7dm9pZH0gLSBObyByZXR1cm4gdmFsdWUuXG4gICAqL1xuICBfcmVzb2x2ZUlkbGVXYWl0ZXJzKCkge1xuICAgIGlmICghdGhpcy5faXNJZGxlKCkpIHJldHVyblxuXG4gICAgY29uc3Qgd2FpdGVycyA9IFsuLi50aGlzLl9pZGxlV2FpdGVyc11cblxuICAgIHRoaXMuX2lkbGVXYWl0ZXJzLmNsZWFyKClcbiAgICBmb3IgKGNvbnN0IHJlc29sdmUgb2Ygd2FpdGVycykgcmVzb2x2ZSgpXG4gIH1cblxuICAvKipcbiAgICogRW1pdHMgYW4gZXhwZWN0ZWQgam9iIGZhaWx1cmUgdGhyb3VnaCB0aGUgc3RhbmRhcmQgam9iL2FsbC1lcnJvciBjaGFubmVscy5cbiAgICogQHBhcmFtIHt7ZXJyb3I6IFJldHVyblR5cGU8dHlwZW9mIEpTT04ucGFyc2U+LCBqb2I6IGltcG9ydChcIi4vdHlwZXMuanNcIikuQmFja2dyb3VuZEpvYlJvd319IGFyZ3MgLSBGYWlsdXJlIHRyYW5zaXRpb24uXG4gICAqIEByZXR1cm5zIHt2b2lkfSAtIE5vIHJldHVybiB2YWx1ZS5cbiAgICovXG4gIF9lbWl0QmFja2dyb3VuZEpvYkZhaWxlZCh7ZXJyb3IsIGpvYn0pIHtcbiAgICBjb25zdCBub3JtYWxpemVkRXJyb3IgPSBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IgOiBuZXcgRXJyb3IoU3RyaW5nKGVycm9yKSlcbiAgICBjb25zdCBwYXlsb2FkID0ge1xuICAgICAgY29udGV4dDoge1xuICAgICAgICBhdHRlbXB0czogam9iLmF0dGVtcHRzLFxuICAgICAgICBqb2JBcmdzOiBqb2IuYXJncyxcbiAgICAgICAgam9iSWQ6IGpvYi5pZCxcbiAgICAgICAgam9iTmFtZTogam9iLmpvYk5hbWUsXG4gICAgICAgIG1heFJldHJpZXM6IGpvYi5tYXhSZXRyaWVzLFxuICAgICAgICBzdGFnZTogXCJiYWNrZ3JvdW5kLWpvYi1mYWlsZWRcIixcbiAgICAgICAgc3RhdHVzOiBqb2Iuc3RhdHVzLFxuICAgICAgICB0ZXJtaW5hbDogam9iLnN0YXR1cyA9PT0gXCJmYWlsZWRcIixcbiAgICAgICAgd2lsbFJldHJ5OiBqb2Iuc3RhdHVzID09PSBcInF1ZXVlZFwiLFxuICAgICAgICB3b3JrZXJJZDogXCJsb2NhbFwiXG4gICAgICB9LFxuICAgICAgZXJyb3I6IG5vcm1hbGl6ZWRFcnJvclxuICAgIH1cbiAgICBjb25zdCBlcnJvckV2ZW50cyA9IHRoaXMuY29uZmlndXJhdGlvbi5nZXRFcnJvckV2ZW50cygpXG5cbiAgICBlcnJvckV2ZW50cy5lbWl0KFwiYmFja2dyb3VuZC1qb2ItZmFpbGVkXCIsIHBheWxvYWQpXG4gICAgZXJyb3JFdmVudHMuZW1pdChcImFsbC1lcnJvclwiLCB7Li4ucGF5bG9hZCwgZXJyb3JUeXBlOiBcImJhY2tncm91bmQtam9iLWZhaWxlZFwifSlcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXBvcnRzIG9uZSBmYWlsZWQgZHVyYWJsZSBhY2tub3dsZWRnZW1lbnQgYXR0ZW1wdCB3aXRoIGl0cyBmZW5jZSBjb250ZXh0LlxuICAgKiBAcGFyYW0ge1BlbmRpbmdMb2NhbEJhY2tncm91bmRKb2JBY2tub3dsZWRnZW1lbnQgJiB7ZXJyb3I6IFJldHVyblR5cGU8dHlwZW9mIEpTT04ucGFyc2U+fX0gYXJncyAtIEZhaWxlZCBhY2tub3dsZWRnZW1lbnQuXG4gICAqIEByZXR1cm5zIHt2b2lkfSAtIE5vIHJldHVybiB2YWx1ZS5cbiAgICovXG4gIF9yZXBvcnRBY2tub3dsZWRnZW1lbnRFcnJvcih7YWNrbm93bGVkZ2VtZW50LCBlcnJvciwgaGFuZG9mZiwgam9ifSkge1xuICAgIHRoaXMuX3JlcG9ydEZyYW1ld29ya0Vycm9yKHtcbiAgICAgIGNvbnRleHQ6IHtcbiAgICAgICAgYWNrbm93bGVkZ2VtZW50VHlwZTogYWNrbm93bGVkZ2VtZW50LnR5cGUsXG4gICAgICAgIGhhbmRvZmZJZDogaGFuZG9mZi5oYW5kb2ZmSWQsXG4gICAgICAgIGpvYklkOiBqb2IuaWQsXG4gICAgICAgIGpvYk5hbWU6IGpvYi5qb2JOYW1lLFxuICAgICAgICB3b3JrZXJJZDogXCJsb2NhbFwiXG4gICAgICB9LFxuICAgICAgZXJyb3IsXG4gICAgICBzdGFnZTogXCJsb2NhbC1iYWNrZ3JvdW5kLWpvYnMtYWNrbm93bGVkZ2VtZW50XCJcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIFJlcG9ydHMgYW4gdW5leHBlY3RlZCBkaXNwYXRjaGVyIGZhaWx1cmUgdGhyb3VnaCBmcmFtZXdvcmsgY2hhbm5lbHMuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gVW5leHBlY3RlZCBmYWlsdXJlLlxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIFJldHVyblR5cGU8dHlwZW9mIEpTT04ucGFyc2U+Pn0gW2FyZ3MuY29udGV4dF0gLSBBZGRpdGlvbmFsIGZhaWx1cmUgY29udGV4dC5cbiAgICogQHBhcmFtIHtSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPn0gYXJncy5lcnJvciAtIFVuZXhwZWN0ZWQgZXJyb3IuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzLnN0YWdlIC0gRGlzcGF0Y2hlciBzdGFnZS5cbiAgICogQHJldHVybnMge3ZvaWR9IC0gTm8gcmV0dXJuIHZhbHVlLlxuICAgKi9cbiAgX3JlcG9ydEZyYW1ld29ya0Vycm9yKHtjb250ZXh0ID0ge30sIGVycm9yLCBzdGFnZX0pIHtcbiAgICBjb25zdCBub3JtYWxpemVkRXJyb3IgPSBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IgOiBuZXcgRXJyb3IoU3RyaW5nKGVycm9yKSlcbiAgICBjb25zdCBwYXlsb2FkID0ge2NvbnRleHQ6IHsuLi5jb250ZXh0LCBzdGFnZX0sIGVycm9yOiBub3JtYWxpemVkRXJyb3J9XG4gICAgY29uc3QgZXJyb3JFdmVudHMgPSB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0RXJyb3JFdmVudHMoKVxuXG4gICAgZXJyb3JFdmVudHMuZW1pdChcImZyYW1ld29yay1lcnJvclwiLCBwYXlsb2FkKVxuICAgIGVycm9yRXZlbnRzLmVtaXQoXCJhbGwtZXJyb3JcIiwgey4uLnBheWxvYWQsIGVycm9yVHlwZTogXCJmcmFtZXdvcmstZXJyb3JcIn0pXG4gIH1cbn1cbiJdfQ==