velocious 1.0.682 → 1.0.683
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/background-jobs/pooled-runner-child.js +102 -0
- package/build/background-jobs/types.js +21 -0
- package/build/background-jobs/worker.js +111 -1
- package/build/src/background-jobs/pooled-runner-child.js +95 -1
- package/build/src/background-jobs/types.d.ts +71 -0
- package/build/src/background-jobs/types.d.ts.map +1 -1
- package/build/src/background-jobs/types.js +22 -1
- package/build/src/background-jobs/worker.d.ts +40 -1
- package/build/src/background-jobs/worker.d.ts.map +1 -1
- package/build/src/background-jobs/worker.js +109 -2
- package/package.json +1 -1
- package/src/background-jobs/pooled-runner-child.js +102 -0
- package/src/background-jobs/types.js +21 -0
- package/src/background-jobs/worker.js +111 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
3
|
import { randomUUID } from "node:crypto"
|
|
4
|
+
import v8 from "node:v8"
|
|
4
5
|
import timeout from "awaitery/build/timeout.js"
|
|
5
6
|
import runJobPayload, { BackgroundJobPerformedFailure } from "./job-runner.js"
|
|
6
7
|
import { boundedPooledRunnerInflightJobIds, isPooledChildShutdownReason, isPooledChildShutdownSignal } from "./pooled-runner-shutdown.js"
|
|
@@ -14,6 +15,10 @@ const BASE_PROCESS_TITLE = "velocious background-jobs-runner"
|
|
|
14
15
|
const SHUTDOWN_OBSERVATION_SEND_TIMEOUT_MS = 100
|
|
15
16
|
/** Stable identity of this pooled child process for the life of the process. */
|
|
16
17
|
const childInstanceId = randomUUID()
|
|
18
|
+
/** Sampling cadence for the memory observation sampler. */
|
|
19
|
+
const MEMORY_OBSERVATION_INTERVAL_MS = 10000
|
|
20
|
+
/** Bound on in-flight job ids carried in a memory observation. */
|
|
21
|
+
const MEMORY_OBSERVATION_JOB_ID_LIMIT = 32
|
|
17
22
|
|
|
18
23
|
setRunnerProcessTitle()
|
|
19
24
|
|
|
@@ -148,6 +153,93 @@ function sendChildAcceptance(type, payload, observedAtMs) {
|
|
|
148
153
|
}
|
|
149
154
|
}
|
|
150
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Collects a bounded diagnostic snapshot of this child's memory state. The
|
|
158
|
+
* pooled child's stdio is ignored by the worker fork, so IPC is the only channel
|
|
159
|
+
* to the worker's log surface — this snapshot (sent periodically and on demand)
|
|
160
|
+
* is how a memory problem names itself in production. The V8 heap-stat
|
|
161
|
+
* breakdown (not a full heap snapshot, which would be far too expensive while a
|
|
162
|
+
* child runs 25 concurrent jobs) distinguishes a V8 heap-growth leak from
|
|
163
|
+
* external/array-buffer (native resource) growth, and the in-flight job ids
|
|
164
|
+
* tie the observation to the work that was running.
|
|
165
|
+
* @returns {{activeJobIds: string[], activeJobIdsTruncatedCount: number, childInstanceId: string, childPid: number, childUptimeMs: number, heapStatistics: ReturnType<typeof v8.getHeapStatistics>, jobCount: number, memoryUsage: ReturnType<typeof process.memoryUsage>, observedAtMs: number, rssBytes: number, type: "pooled-child-memory", uptimeMs: number}} - Bounded memory observation for this child.
|
|
166
|
+
*/
|
|
167
|
+
function collectMemoryObservation() {
|
|
168
|
+
const jobIds = [...runningJobIds]
|
|
169
|
+
const activeJobIds = jobIds.slice(0, MEMORY_OBSERVATION_JOB_ID_LIMIT)
|
|
170
|
+
const memoryUsage = process.memoryUsage()
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
activeJobIds,
|
|
174
|
+
activeJobIdsTruncatedCount: Math.max(0, jobIds.length - activeJobIds.length),
|
|
175
|
+
childInstanceId,
|
|
176
|
+
childPid: process.pid,
|
|
177
|
+
childUptimeMs: Math.floor(process.uptime() * 1000),
|
|
178
|
+
heapStatistics: v8.getHeapStatistics(),
|
|
179
|
+
jobCount: jobIds.length,
|
|
180
|
+
memoryUsage,
|
|
181
|
+
observedAtMs: Date.now(),
|
|
182
|
+
rssBytes: memoryUsage.rss,
|
|
183
|
+
type: "pooled-child-memory",
|
|
184
|
+
uptimeMs: Math.floor(process.uptime() * 1000)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Sends a memory observation to the worker. Sampling is cheap (process + V8
|
|
190
|
+
* heap stats) and only runs while jobs are in flight; a closed IPC channel is
|
|
191
|
+
* terminal for this child (the disconnect handler owns shutdown), so a failed
|
|
192
|
+
* send is swallowed.
|
|
193
|
+
* @returns {void}
|
|
194
|
+
*/
|
|
195
|
+
function sendMemoryObservation() {
|
|
196
|
+
if (!process.send || runningJobIds.size === 0) return
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
process.send(collectMemoryObservation())
|
|
200
|
+
} catch {
|
|
201
|
+
// The IPC channel is already gone; the disconnect handler owns shutdown.
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** @type {ReturnType<typeof setInterval> | undefined} */
|
|
206
|
+
let memoryObservationTimer
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Checks whether an IPC value requests this child to send a memory observation.
|
|
210
|
+
* @param {ReturnType<typeof JSON.parse>} message - IPC message.
|
|
211
|
+
* @returns {message is {type: "memory-observation-request"}} - Whether the message requests one.
|
|
212
|
+
*/
|
|
213
|
+
function isMemoryObservationRequestMessage(message) {
|
|
214
|
+
return message !== null
|
|
215
|
+
&& typeof message === "object"
|
|
216
|
+
&& message.type === "memory-observation-request"
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Starts the periodic memory observation sampler if it is not already running.
|
|
221
|
+
* @returns {void}
|
|
222
|
+
*/
|
|
223
|
+
function startMemoryObservationSampling() {
|
|
224
|
+
if (memoryObservationTimer || !process.send) return
|
|
225
|
+
|
|
226
|
+
memoryObservationTimer = setInterval(() => {
|
|
227
|
+
sendMemoryObservation()
|
|
228
|
+
}, MEMORY_OBSERVATION_INTERVAL_MS)
|
|
229
|
+
memoryObservationTimer.unref()
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Stops the periodic memory observation sampler.
|
|
234
|
+
* @returns {void}
|
|
235
|
+
*/
|
|
236
|
+
function stopMemoryObservationSampling() {
|
|
237
|
+
if (!memoryObservationTimer) return
|
|
238
|
+
|
|
239
|
+
clearInterval(memoryObservationTimer)
|
|
240
|
+
memoryObservationTimer = undefined
|
|
241
|
+
}
|
|
242
|
+
|
|
151
243
|
/**
|
|
152
244
|
* Checks whether an IPC value is a runnable pooled job message.
|
|
153
245
|
* @param {ReturnType<typeof JSON.parse>} message - IPC message.
|
|
@@ -238,6 +330,10 @@ async function runJob(payload, sharedTransactionBroker) {
|
|
|
238
330
|
} finally {
|
|
239
331
|
runningJobIds.delete(payload.id)
|
|
240
332
|
updateProcessTitle()
|
|
333
|
+
|
|
334
|
+
if (runningJobIds.size === 0) {
|
|
335
|
+
stopMemoryObservationSampling()
|
|
336
|
+
}
|
|
241
337
|
}
|
|
242
338
|
}
|
|
243
339
|
|
|
@@ -257,11 +353,17 @@ function handleMessage(message) {
|
|
|
257
353
|
return
|
|
258
354
|
}
|
|
259
355
|
|
|
356
|
+
if (isMemoryObservationRequestMessage(message)) {
|
|
357
|
+
sendMemoryObservation()
|
|
358
|
+
return
|
|
359
|
+
}
|
|
360
|
+
|
|
260
361
|
if (!isJobMessage(message) || runningJobIds.has(message.payload.id)) return
|
|
261
362
|
|
|
262
363
|
runningJobIds.add(message.payload.id)
|
|
263
364
|
updateProcessTitle()
|
|
264
365
|
sendChildAcceptance("job-received", message.payload, Date.now())
|
|
366
|
+
startMemoryObservationSampling()
|
|
265
367
|
void runJob(message.payload, message.sharedTransactionBroker || {expected: false})
|
|
266
368
|
}
|
|
267
369
|
|
|
@@ -73,6 +73,27 @@
|
|
|
73
73
|
* @property {number | null} shutdownRequestedAtMs - Parent request timestamp when supplied over IPC.
|
|
74
74
|
* @property {import("node:child_process").ChildProcess["signalCode"]} signal - Requested or observed signal when available.
|
|
75
75
|
*/
|
|
76
|
+
/**
|
|
77
|
+
* Bounded pooled-child memory observation sent over the child IPC channel.
|
|
78
|
+
* The pooled child's stdio is ignored by the worker fork, so this observation
|
|
79
|
+
* (sent periodically while jobs run, plus on demand) is how a memory problem
|
|
80
|
+
* in a running child names itself. `heapStatistics` and `memoryUsage`
|
|
81
|
+
* distinguish V8-heap growth from external/array-buffer (native resource)
|
|
82
|
+
* growth; `activeJobIds` ties the sample to the work that was in flight.
|
|
83
|
+
* @typedef {object} PooledChildMemoryObservation
|
|
84
|
+
* @property {string[]} activeJobIds - In-flight job ids, bounded.
|
|
85
|
+
* @property {number} activeJobIdsTruncatedCount - In-flight job ids omitted by the bound.
|
|
86
|
+
* @property {string} childInstanceId - Stable identity reported by the child.
|
|
87
|
+
* @property {number} childPid - Child process id.
|
|
88
|
+
* @property {number} childUptimeMs - Child process uptime in ms.
|
|
89
|
+
* @property {ReturnType<typeof import("node:v8").getHeapStatistics>} heapStatistics - V8 heap-stat breakdown at the sample.
|
|
90
|
+
* @property {number} jobCount - In-flight job count.
|
|
91
|
+
* @property {ReturnType<typeof import("node:process").memoryUsage>} memoryUsage - Process memory breakdown at the sample.
|
|
92
|
+
* @property {number} observedAtMs - Epoch ms the child sampled.
|
|
93
|
+
* @property {number} rssBytes - Resident set size in bytes at the sample.
|
|
94
|
+
* @property {"pooled-child-memory"} type - Discriminator.
|
|
95
|
+
* @property {number} uptimeMs - Process uptime in ms.
|
|
96
|
+
*/
|
|
76
97
|
/**
|
|
77
98
|
* @typedef {object} LocalBackgroundJobsClock
|
|
78
99
|
* @property {() => number} now - Current epoch milliseconds.
|
|
@@ -41,6 +41,7 @@ import { POOLED_RUNNER_INFLIGHT_JOB_ID_LIMIT, boundedPooledRunnerInflightJobIds,
|
|
|
41
41
|
* @property {boolean} retiring - Whether this child is draining before retirement.
|
|
42
42
|
* @property {boolean} [started] - Whether the child completed its startup handshake.
|
|
43
43
|
* @property {boolean} [settling] - Whether failure handling already owns this child.
|
|
44
|
+
* @property {import("./types.js").PooledChildMemoryObservation} [lastMemoryObservation] - Latest memory observation received from this child.
|
|
44
45
|
* @property {number} [ipcDisconnectedAtMs] - Parent observation of IPC disconnect.
|
|
45
46
|
* @property {import("./types.js").PooledChildShutdownObservation} [shutdownObservation] - Child observation sent before teardown.
|
|
46
47
|
* @property {import("./types.js").PooledChildShutdownReason} [shutdownReason] - Exact parent-requested shutdown reason.
|
|
@@ -132,6 +133,38 @@ function isChildShutdownObservationMessage(message) {
|
|
|
132
133
|
&& isPooledChildShutdownSignal(record.signal)
|
|
133
134
|
}
|
|
134
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Checks whether an IPC value is a pooled child's bounded memory observation.
|
|
138
|
+
* The pooled child's stdio is ignored by the worker fork, so this observation
|
|
139
|
+
* (periodic while jobs run, plus on demand) is how a memory problem in a
|
|
140
|
+
* running child names itself. The worker logs it (its stderr reaches the prod
|
|
141
|
+
* log) and forwards it to the optional `onPooledRunnerMemoryObservation` hook.
|
|
142
|
+
* @param {ReturnType<typeof JSON.parse>} message - IPC message.
|
|
143
|
+
* @returns {message is import("./types.js").PooledChildMemoryObservation} - Whether this is a valid memory observation.
|
|
144
|
+
*/
|
|
145
|
+
function isPooledChildMemoryObservationMessage(message) {
|
|
146
|
+
if (!message || typeof message !== "object") return false
|
|
147
|
+
const record = /** @type {Record<string, ReturnType<typeof JSON.parse>>} */ (message)
|
|
148
|
+
const heapStatistics = /** @type {Record<string, ReturnType<typeof JSON.parse>> | undefined} */ (record.heapStatistics)
|
|
149
|
+
const memoryUsage = /** @type {Record<string, ReturnType<typeof JSON.parse>> | undefined} */ (record.memoryUsage)
|
|
150
|
+
|
|
151
|
+
return record.type === "pooled-child-memory"
|
|
152
|
+
&& typeof record.childInstanceId === "string"
|
|
153
|
+
&& Number.isInteger(record.childPid)
|
|
154
|
+
&& typeof record.rssBytes === "number"
|
|
155
|
+
&& Number.isFinite(record.rssBytes)
|
|
156
|
+
&& Number.isInteger(record.jobCount)
|
|
157
|
+
&& record.jobCount >= 0
|
|
158
|
+
&& Array.isArray(record.activeJobIds)
|
|
159
|
+
&& record.activeJobIds.every((jobId) => typeof jobId === "string")
|
|
160
|
+
&& Number.isInteger(record.activeJobIdsTruncatedCount)
|
|
161
|
+
&& record.activeJobIdsTruncatedCount >= 0
|
|
162
|
+
&& typeof record.observedAtMs === "number"
|
|
163
|
+
&& Number.isFinite(record.observedAtMs)
|
|
164
|
+
&& heapStatistics !== undefined && typeof heapStatistics === "object"
|
|
165
|
+
&& memoryUsage !== undefined && typeof memoryUsage === "object"
|
|
166
|
+
}
|
|
167
|
+
|
|
135
168
|
/**
|
|
136
169
|
* Normalizes a candidate pooled-runner resource limit.
|
|
137
170
|
* @param {number | undefined} value - Candidate positive number.
|
|
@@ -166,8 +199,9 @@ export default class BackgroundJobsWorker {
|
|
|
166
199
|
* @param {() => void | Promise<void>} [args.onStopped] - Lifecycle hook invoked after the worker finishes stopping.
|
|
167
200
|
* @param {() => void} [args.onGenerationAccepted] - Explicit generation-acceptance observation hook.
|
|
168
201
|
* @param {() => void} [args.onRetireMessage] - Explicit retire-message observation hook.
|
|
202
|
+
* @param {(observation: import("./types.js").PooledChildMemoryObservation) => void | Promise<void>} [args.onPooledRunnerMemoryObservation] - Explicit pooled-child memory observation hook. Every validated observation (periodic while a child has in-flight jobs, plus on demand) is forwarded here, in addition to the worker's compact stderr log line, so an application can route memory diagnostics (e.g. to a bug reporter) without parsing logs.
|
|
169
203
|
*/
|
|
170
|
-
constructor({configuration, host, port, generationId, workerInstanceId, maxConcurrentForkedJobs, maxConcurrentInlineJobs, pooledRunnerCount, pooledRunnerConcurrency, pooledRunnerMaxJobs, pooledRunnerMaxRssBytes, pooledRunnerMaxLifetimeMs, forkedChildSigkillGraceMs, heartbeatIntervalMs, generationHandshakeTimeoutMs = DEFAULT_GENERATION_HANDSHAKE_TIMEOUT_MS, reconnectDelayMs = 1000, jobTimeoutMs, closeDatabaseConnectionsOnStop = true, onStopped, onGenerationAccepted, onRetireMessage} = {}) {
|
|
204
|
+
constructor({configuration, host, port, generationId, workerInstanceId, maxConcurrentForkedJobs, maxConcurrentInlineJobs, pooledRunnerCount, pooledRunnerConcurrency, pooledRunnerMaxJobs, pooledRunnerMaxRssBytes, pooledRunnerMaxLifetimeMs, forkedChildSigkillGraceMs, heartbeatIntervalMs, generationHandshakeTimeoutMs = DEFAULT_GENERATION_HANDSHAKE_TIMEOUT_MS, reconnectDelayMs = 1000, jobTimeoutMs, closeDatabaseConnectionsOnStop = true, onStopped, onGenerationAccepted, onRetireMessage, onPooledRunnerMemoryObservation} = {}) {
|
|
171
205
|
/**
|
|
172
206
|
* Narrows the runtime value to the documented type.
|
|
173
207
|
* @type {Promise<import("../configuration.js").default>} */
|
|
@@ -186,6 +220,7 @@ export default class BackgroundJobsWorker {
|
|
|
186
220
|
this.onStopped = onStopped
|
|
187
221
|
this.onGenerationAccepted = onGenerationAccepted
|
|
188
222
|
this.onRetireMessage = onRetireMessage
|
|
223
|
+
this.onPooledRunnerMemoryObservation = onPooledRunnerMemoryObservation
|
|
189
224
|
/**
|
|
190
225
|
* Constructor override for the inline-job concurrency cap. When unset
|
|
191
226
|
* the cap is read from `configuration.getBackgroundJobsConfig()` in
|
|
@@ -1393,6 +1428,10 @@ export default class BackgroundJobsWorker {
|
|
|
1393
1428
|
this._reportChildAccepted(message)
|
|
1394
1429
|
return
|
|
1395
1430
|
}
|
|
1431
|
+
if (isPooledChildMemoryObservationMessage(message)) {
|
|
1432
|
+
this._handlePooledChildMemoryObservation({child, message})
|
|
1433
|
+
return
|
|
1434
|
+
}
|
|
1396
1435
|
if (record.type !== "job-outcome" || !state || state.settling || typeof record.jobId !== "string") return
|
|
1397
1436
|
state.started = true
|
|
1398
1437
|
const entry = state.inflight.get(record.jobId)
|
|
@@ -1456,6 +1495,77 @@ export default class BackgroundJobsWorker {
|
|
|
1456
1495
|
})
|
|
1457
1496
|
}
|
|
1458
1497
|
|
|
1498
|
+
/**
|
|
1499
|
+
* Handles a pooled child's bounded memory observation. The pooled child's
|
|
1500
|
+
* stdio is ignored by the worker fork, so this IPC observation is how a
|
|
1501
|
+
* memory problem in a running child names itself. The worker (a) records the
|
|
1502
|
+
* latest observation on the child's state for later correlation, (b) logs one
|
|
1503
|
+
* compact line to its own stderr (which reaches the prod log, unlike the
|
|
1504
|
+
* child's ignored stdio), and (c) forwards the full observation to the
|
|
1505
|
+
* optional `onPooledRunnerMemoryObservation` hook so an application can route
|
|
1506
|
+
* it (e.g. to a bug reporter) without parsing logs. The heap-stat breakdown
|
|
1507
|
+
* distinguishes V8-heap growth from external/array-buffer (native) growth. A
|
|
1508
|
+
* hook failure is swallowed — diagnostics must never take down the worker or
|
|
1509
|
+
* fail the jobs running on that child.
|
|
1510
|
+
* @param {object} args - Message details.
|
|
1511
|
+
* @param {import("node:child_process").ChildProcess} args.child - Pooled child.
|
|
1512
|
+
* @param {import("./types.js").PooledChildMemoryObservation} args.message - Validated memory observation.
|
|
1513
|
+
* @returns {void}
|
|
1514
|
+
*/
|
|
1515
|
+
_handlePooledChildMemoryObservation({child, message}) {
|
|
1516
|
+
const state = this.pooledChildStates.get(child)
|
|
1517
|
+
if (state) state.lastMemoryObservation = message
|
|
1518
|
+
|
|
1519
|
+
const heap = message.heapStatistics
|
|
1520
|
+
console.error(
|
|
1521
|
+
JSON.stringify({
|
|
1522
|
+
event: "pooled-child-memory",
|
|
1523
|
+
childInstanceId: state?.childInstanceId ?? message.childInstanceId,
|
|
1524
|
+
childPid: message.childPid,
|
|
1525
|
+
childUptimeS: Math.round(message.childUptimeMs / 1000),
|
|
1526
|
+
rssMb: Math.round(message.rssBytes / (1024 * 1024)),
|
|
1527
|
+
heapUsedMb: Math.round(heap.used_heap_size / (1024 * 1024)),
|
|
1528
|
+
heapTotalMb: Math.round(heap.total_heap_size / (1024 * 1024)),
|
|
1529
|
+
heapLimitMb: Math.round(heap.heap_size_limit / (1024 * 1024)),
|
|
1530
|
+
externalMb: Math.round(message.memoryUsage.external / (1024 * 1024)),
|
|
1531
|
+
arrayBuffersMb: Math.round(message.memoryUsage.arrayBuffers / (1024 * 1024)),
|
|
1532
|
+
jobs: message.jobCount,
|
|
1533
|
+
activeJobIds: message.activeJobIds
|
|
1534
|
+
})
|
|
1535
|
+
)
|
|
1536
|
+
|
|
1537
|
+
if (this.onPooledRunnerMemoryObservation) {
|
|
1538
|
+
try {
|
|
1539
|
+
const result = this.onPooledRunnerMemoryObservation(message)
|
|
1540
|
+
if (result && typeof result.catch === "function") result.catch((error) => {
|
|
1541
|
+
console.error("Pooled runner memory observation hook failed:", error)
|
|
1542
|
+
})
|
|
1543
|
+
} catch (error) {
|
|
1544
|
+
console.error("Pooled runner memory observation hook failed:", error)
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
/**
|
|
1550
|
+
* Requests an immediate memory observation from one pooled child. The child
|
|
1551
|
+
* replies over IPC with its current snapshot (the same shape as the periodic
|
|
1552
|
+
* sampler), which the worker records, logs, and forwards to the
|
|
1553
|
+
* `onPooledRunnerMemoryObservation` hook. Use this to pull a snapshot on
|
|
1554
|
+
* suspicion (e.g. after an OOM report) without waiting for the next periodic
|
|
1555
|
+
* sample. A no-op when the child is gone or its IPC channel is closed.
|
|
1556
|
+
* @param {import("node:child_process").ChildProcess} child - Pooled child to sample.
|
|
1557
|
+
* @returns {void}
|
|
1558
|
+
*/
|
|
1559
|
+
requestPooledChildMemoryObservation(child) {
|
|
1560
|
+
if (!child.connected) return
|
|
1561
|
+
|
|
1562
|
+
try {
|
|
1563
|
+
child.send({type: "memory-observation-request"})
|
|
1564
|
+
} catch {
|
|
1565
|
+
// The IPC channel is already gone; the disconnect/exit handler owns teardown.
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1459
1569
|
/**
|
|
1460
1570
|
* Marks a pooled child for retirement and — when the pool is below its hard
|
|
1461
1571
|
* cap — eagerly spawns a single replacement (1-for-1) so its capacity is
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
|
+
import v8 from "node:v8";
|
|
3
4
|
import timeout from "awaitery/build/timeout.js";
|
|
4
5
|
import runJobPayload, { BackgroundJobPerformedFailure } from "./job-runner.js";
|
|
5
6
|
import { boundedPooledRunnerInflightJobIds, isPooledChildShutdownReason, isPooledChildShutdownSignal } from "./pooled-runner-shutdown.js";
|
|
@@ -12,6 +13,10 @@ const BASE_PROCESS_TITLE = "velocious background-jobs-runner";
|
|
|
12
13
|
const SHUTDOWN_OBSERVATION_SEND_TIMEOUT_MS = 100;
|
|
13
14
|
/** Stable identity of this pooled child process for the life of the process. */
|
|
14
15
|
const childInstanceId = randomUUID();
|
|
16
|
+
/** Sampling cadence for the memory observation sampler. */
|
|
17
|
+
const MEMORY_OBSERVATION_INTERVAL_MS = 10000;
|
|
18
|
+
/** Bound on in-flight job ids carried in a memory observation. */
|
|
19
|
+
const MEMORY_OBSERVATION_JOB_ID_LIMIT = 32;
|
|
15
20
|
setRunnerProcessTitle();
|
|
16
21
|
/** @type {Promise<void> | undefined} */
|
|
17
22
|
let shutdownPromise;
|
|
@@ -138,6 +143,87 @@ function sendChildAcceptance(type, payload, observedAtMs) {
|
|
|
138
143
|
// The IPC channel is already gone; the disconnect handler owns shutdown.
|
|
139
144
|
}
|
|
140
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Collects a bounded diagnostic snapshot of this child's memory state. The
|
|
148
|
+
* pooled child's stdio is ignored by the worker fork, so IPC is the only channel
|
|
149
|
+
* to the worker's log surface — this snapshot (sent periodically and on demand)
|
|
150
|
+
* is how a memory problem names itself in production. The V8 heap-stat
|
|
151
|
+
* breakdown (not a full heap snapshot, which would be far too expensive while a
|
|
152
|
+
* child runs 25 concurrent jobs) distinguishes a V8 heap-growth leak from
|
|
153
|
+
* external/array-buffer (native resource) growth, and the in-flight job ids
|
|
154
|
+
* tie the observation to the work that was running.
|
|
155
|
+
* @returns {{activeJobIds: string[], activeJobIdsTruncatedCount: number, childInstanceId: string, childPid: number, childUptimeMs: number, heapStatistics: ReturnType<typeof v8.getHeapStatistics>, jobCount: number, memoryUsage: ReturnType<typeof process.memoryUsage>, observedAtMs: number, rssBytes: number, type: "pooled-child-memory", uptimeMs: number}} - Bounded memory observation for this child.
|
|
156
|
+
*/
|
|
157
|
+
function collectMemoryObservation() {
|
|
158
|
+
const jobIds = [...runningJobIds];
|
|
159
|
+
const activeJobIds = jobIds.slice(0, MEMORY_OBSERVATION_JOB_ID_LIMIT);
|
|
160
|
+
const memoryUsage = process.memoryUsage();
|
|
161
|
+
return {
|
|
162
|
+
activeJobIds,
|
|
163
|
+
activeJobIdsTruncatedCount: Math.max(0, jobIds.length - activeJobIds.length),
|
|
164
|
+
childInstanceId,
|
|
165
|
+
childPid: process.pid,
|
|
166
|
+
childUptimeMs: Math.floor(process.uptime() * 1000),
|
|
167
|
+
heapStatistics: v8.getHeapStatistics(),
|
|
168
|
+
jobCount: jobIds.length,
|
|
169
|
+
memoryUsage,
|
|
170
|
+
observedAtMs: Date.now(),
|
|
171
|
+
rssBytes: memoryUsage.rss,
|
|
172
|
+
type: "pooled-child-memory",
|
|
173
|
+
uptimeMs: Math.floor(process.uptime() * 1000)
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Sends a memory observation to the worker. Sampling is cheap (process + V8
|
|
178
|
+
* heap stats) and only runs while jobs are in flight; a closed IPC channel is
|
|
179
|
+
* terminal for this child (the disconnect handler owns shutdown), so a failed
|
|
180
|
+
* send is swallowed.
|
|
181
|
+
* @returns {void}
|
|
182
|
+
*/
|
|
183
|
+
function sendMemoryObservation() {
|
|
184
|
+
if (!process.send || runningJobIds.size === 0)
|
|
185
|
+
return;
|
|
186
|
+
try {
|
|
187
|
+
process.send(collectMemoryObservation());
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
// The IPC channel is already gone; the disconnect handler owns shutdown.
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/** @type {ReturnType<typeof setInterval> | undefined} */
|
|
194
|
+
let memoryObservationTimer;
|
|
195
|
+
/**
|
|
196
|
+
* Checks whether an IPC value requests this child to send a memory observation.
|
|
197
|
+
* @param {ReturnType<typeof JSON.parse>} message - IPC message.
|
|
198
|
+
* @returns {message is {type: "memory-observation-request"}} - Whether the message requests one.
|
|
199
|
+
*/
|
|
200
|
+
function isMemoryObservationRequestMessage(message) {
|
|
201
|
+
return message !== null
|
|
202
|
+
&& typeof message === "object"
|
|
203
|
+
&& message.type === "memory-observation-request";
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Starts the periodic memory observation sampler if it is not already running.
|
|
207
|
+
* @returns {void}
|
|
208
|
+
*/
|
|
209
|
+
function startMemoryObservationSampling() {
|
|
210
|
+
if (memoryObservationTimer || !process.send)
|
|
211
|
+
return;
|
|
212
|
+
memoryObservationTimer = setInterval(() => {
|
|
213
|
+
sendMemoryObservation();
|
|
214
|
+
}, MEMORY_OBSERVATION_INTERVAL_MS);
|
|
215
|
+
memoryObservationTimer.unref();
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Stops the periodic memory observation sampler.
|
|
219
|
+
* @returns {void}
|
|
220
|
+
*/
|
|
221
|
+
function stopMemoryObservationSampling() {
|
|
222
|
+
if (!memoryObservationTimer)
|
|
223
|
+
return;
|
|
224
|
+
clearInterval(memoryObservationTimer);
|
|
225
|
+
memoryObservationTimer = undefined;
|
|
226
|
+
}
|
|
141
227
|
/**
|
|
142
228
|
* Checks whether an IPC value is a runnable pooled job message.
|
|
143
229
|
* @param {ReturnType<typeof JSON.parse>} message - IPC message.
|
|
@@ -227,6 +313,9 @@ async function runJob(payload, sharedTransactionBroker) {
|
|
|
227
313
|
finally {
|
|
228
314
|
runningJobIds.delete(payload.id);
|
|
229
315
|
updateProcessTitle();
|
|
316
|
+
if (runningJobIds.size === 0) {
|
|
317
|
+
stopMemoryObservationSampling();
|
|
318
|
+
}
|
|
230
319
|
}
|
|
231
320
|
}
|
|
232
321
|
/**
|
|
@@ -244,11 +333,16 @@ function handleMessage(message) {
|
|
|
244
333
|
});
|
|
245
334
|
return;
|
|
246
335
|
}
|
|
336
|
+
if (isMemoryObservationRequestMessage(message)) {
|
|
337
|
+
sendMemoryObservation();
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
247
340
|
if (!isJobMessage(message) || runningJobIds.has(message.payload.id))
|
|
248
341
|
return;
|
|
249
342
|
runningJobIds.add(message.payload.id);
|
|
250
343
|
updateProcessTitle();
|
|
251
344
|
sendChildAcceptance("job-received", message.payload, Date.now());
|
|
345
|
+
startMemoryObservationSampling();
|
|
252
346
|
void runJob(message.payload, message.sharedTransactionBroker || { expected: false });
|
|
253
347
|
}
|
|
254
348
|
process.on("message", (message) => handleMessage(message));
|
|
@@ -257,4 +351,4 @@ process.once("SIGTERM", () => void shutdownRunner({ exitCode: 1, reason: "signal
|
|
|
257
351
|
process.once("SIGINT", () => void shutdownRunner({ exitCode: 1, reason: "signal_sigint", signal: "SIGINT" }));
|
|
258
352
|
if (process.send)
|
|
259
353
|
process.send({ childInstanceId, childPid: process.pid, type: "ready" });
|
|
260
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicG9vbGVkLXJ1bm5lci1jaGlsZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9iYWNrZ3JvdW5kLWpvYnMvcG9vbGVkLXJ1bm5lci1jaGlsZC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGFBQWEsQ0FBQTtBQUN4QyxPQUFPLE9BQU8sTUFBTSwyQkFBMkIsQ0FBQTtBQUMvQyxPQUFPLGFBQWEsRUFBRSxFQUFFLDZCQUE2QixFQUFFLE1BQU0saUJBQWlCLENBQUE7QUFDOUUsT0FBTyxFQUFFLGlDQUFpQyxFQUFFLDJCQUEyQixFQUFFLDJCQUEyQixFQUFFLE1BQU0sNkJBQTZCLENBQUE7QUFDekksT0FBTyxFQUFFLHNCQUFzQixFQUFFLCtCQUErQixFQUFFLDBCQUEwQixFQUFFLE1BQU0sK0JBQStCLENBQUE7QUFDbkksT0FBTyxxQkFBcUIsTUFBTSwyQkFBMkIsQ0FBQTtBQUM3RCxPQUFPLDBCQUEwQixNQUFNLG9DQUFvQyxDQUFBO0FBQzNFLE9BQU8sRUFBRSxvQ0FBb0MsRUFBRSxNQUFNLCtDQUErQyxDQUFBO0FBRXBHLE1BQU0sa0JBQWtCLEdBQUcsa0NBQWtDLENBQUE7QUFDN0QseUZBQXlGO0FBQ3pGLE1BQU0sb0NBQW9DLEdBQUcsR0FBRyxDQUFBO0FBQ2hELGdGQUFnRjtBQUNoRixNQUFNLGVBQWUsR0FBRyxVQUFVLEVBQUUsQ0FBQTtBQUVwQyxxQkFBcUIsRUFBRSxDQUFBO0FBRXZCLHdDQUF3QztBQUN4QyxJQUFJLGVBQWUsQ0FBQTtBQUVuQjs7Ozs7Ozs7OztHQVVHO0FBQ0gsU0FBUyxjQUFjLENBQUMsRUFBQyxRQUFRLEVBQUUsTUFBTSxFQUFFLHFCQUFxQixHQUFHLElBQUksRUFBRSxNQUFNLEdBQUcsSUFBSSxFQUFDO0lBQ3JGLElBQUksZUFBZTtRQUFFLE9BQU8sZUFBZSxDQUFBO0lBRTNDLGVBQWUsR0FBRyxDQUFDLEtBQUssSUFB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RyxFQUFFLENBQUMsS0FBSyxjQUFjLENBQUMsRUFBQyxRQUFRLEVBQUUsQ0FBQyxFQUFFLE1BQU0sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFDLENBQUMsQ0FBQyxDQUFBO0FBQzlHLE9BQU8sQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLEdBQUcsRUFBRSxDQUFDLEtBQUssY0FBYyxDQUFDLEVBQUMsUUFBUSxFQUFFLENBQUMsRUFBRSxNQUFNLEVBQUUsZUFBZSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUMsQ0FBQyxDQUFDLENBQUE7QUFDM0csSUFBSSxPQUFPLENBQUMsSUFBSTtJQUFFLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBQyxlQUFlLEVBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQyxHQUFHLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBQyxDQUFDLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAdHMtY2hlY2tcblxuaW1wb3J0IHsgcmFuZG9tVVVJRCB9IGZyb20gXCJub2RlOmNyeXB0b1wiXG5pbXBvcnQgdGltZW91dCBmcm9tIFwiYXdhaXRlcnkvYnVpbGQvdGltZW91dC5qc1wiXG5pbXBvcnQgcnVuSm9iUGF5bG9hZCwgeyBCYWNrZ3JvdW5kSm9iUGVyZm9ybWVkRmFpbHVyZSB9IGZyb20gXCIuL2pvYi1ydW5uZXIuanNcIlxuaW1wb3J0IHsgYm91bmRlZFBvb2xlZFJ1bm5lckluZmxpZ2h0Sm9iSWRzLCBpc1Bvb2xlZENoaWxkU2h1dGRvd25SZWFzb24sIGlzUG9vbGVkQ2hpbGRTaHV0ZG93blNpZ25hbCB9IGZyb20gXCIuL3Bvb2xlZC1ydW5uZXItc2h1dGRvd24uanNcIlxuaW1wb3J0IHsgY2xvc2VSdW5uZXJDb25uZWN0aW9ucywgY2xvc2VSdW5uZXJGcmFtZXdvcmtDb25uZWN0aW9ucywgY3VycmVudENvbmZpZ3VyYXRpb25Pck51bGwgfSBmcm9tIFwiLi9ydW5uZXItZ3JhY2VmdWwtc2h1dGRvd24uanNcIlxuaW1wb3J0IHNldFJ1bm5lclByb2Nlc3NUaXRsZSBmcm9tIFwiLi9ydW5uZXItcHJvY2Vzcy10aXRsZS5qc1wiXG5pbXBvcnQgUG9vbGVkUnVubmVyQnJva2VySWRlbnRpdHkgZnJvbSBcIi4vcG9vbGVkLXJ1bm5lci1icm9rZXItaWRlbnRpdHkuanNcIlxuaW1wb3J0IHsgcnVuV2l0aFNoYXJlZFRyYW5zYWN0aW9uQnJva2VyQ29uZmlnIH0gZnJvbSBcIi4uL3Rlc3Rpbmcvc2hhcmVkLXRyYW5zYWN0aW9uLXByb3h5LWRyaXZlci5qc1wiXG5cbmNvbnN0IEJBU0VfUFJPQ0VTU19USVRMRSA9IFwidmVsb2Npb3VzIGJhY2tncm91bmQtam9icy1ydW5uZXJcIlxuLyoqIEEgc2h1dGRvd24gb2JzZXJ2YXRpb24gbWF5IGRlbGF5IHJlc291cmNlIHRlYXJkb3duIG9ubHkgZm9yIHRoaXMgYm91bmRlZCBJUEMgc2VuZC4gKi9cbmNvbnN0IFNIVVRET1dOX09CU0VSVkFUSU9OX1NFTkRfVElNRU9VVF9NUyA9IDEwMFxuLyoqIFN0YWJsZSBpZGVudGl0eSBvZiB0aGlzIHBvb2xlZCBjaGlsZCBwcm9jZXNzIGZvciB0aGUgbGlmZSBvZiB0aGUgcHJvY2Vzcy4gKi9cbmNvbnN0IGNoaWxkSW5zdGFuY2VJZCA9IHJhbmRvbVVVSUQoKVxuXG5zZXRSdW5uZXJQcm9jZXNzVGl0bGUoKVxuXG4vKiogQHR5cGUge1Byb21pc2U8dm9pZD4gfCB1bmRlZmluZWR9ICovXG5sZXQgc2h1dGRvd25Qcm9taXNlXG5cbi8qKlxuICogQ2xvc2VzIHRoZSBydW5uZXIncyBjb25uZWN0aW9ucyDigJQgcmVsZWFzaW5nIGFueSBhZHZpc29yeSBsb2NrIGEga2lsbGVkLW1pZC1wYXNzXG4gKiBqb2Igc3RpbGwgaG9sZHMg4oCUIGJlZm9yZSBleGl0aW5nLCBpbnN0ZWFkIG9mIGxlYXZpbmcgYSBoYWxmLW9wZW4gc2Vzc2lvbiB0aGF0XG4gKiBrZWVwcyB0aGUgbG9jayB1bnRpbCB0aGUgREIgc2VydmVyJ3MgYHdhaXRfdGltZW91dGAuXG4gKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIFNodXRkb3duIG9ic2VydmF0aW9uLlxuICogQHBhcmFtIHtudW1iZXJ9IGFyZ3MuZXhpdENvZGUgLSBQcm9jZXNzIGV4aXQgY29kZS5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi90eXBlcy5qc1wiKS5Qb29sZWRDaGlsZFNodXRkb3duUmVhc29ufSBhcmdzLnJlYXNvbiAtIEV4YWN0IHNodXRkb3duIHJlYXNvbiBvYnNlcnZlZCBieSB0aGUgY2hpbGQuXG4gKiBAcGFyYW0ge251bWJlciB8IG51bGx9IFthcmdzLnNodXRkb3duUmVxdWVzdGVkQXRNc10gLSBQYXJlbnQgcmVxdWVzdCB0aW1lc3RhbXAgd2hlbiBzdXBwbGllZCBvdmVyIElQQy5cbiAqIEBwYXJhbSB7aW1wb3J0KFwibm9kZTpjaGlsZF9wcm9jZXNzXCIpLkNoaWxkUHJvY2Vzc1tcInNpZ25hbENvZGVcIl19IFthcmdzLnNpZ25hbF0gLSBSZXF1ZXN0ZWQgb3Igb2JzZXJ2ZWQgc2lnbmFsLlxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59XG4gKi9cbmZ1bmN0aW9uIHNodXRkb3duUnVubmVyKHtleGl0Q29kZSwgcmVhc29uLCBzaHV0ZG93blJlcXVlc3RlZEF0TXMgPSBudWxsLCBzaWduYWwgPSBudWxsfSkge1xuICBpZiAoc2h1dGRvd25Qcm9taXNlKSByZXR1cm4gc2h1dGRvd25Qcm9taXNlXG5cbiAgc2h1dGRvd25Qcm9taXNlID0gKGFzeW5jICgpID0+IHtcbiAgICBhd2FpdCBzZW5kU2h1dGRvd25PYnNlcnZhdGlvbih7cmVhc29uLCBzaHV0ZG93blJlcXVlc3RlZEF0TXMsIHNpZ25hbH0pXG4gICAgYXdhaXQgY2xvc2VSdW5uZXJDb25uZWN0aW9ucyhjdXJyZW50Q29uZmlndXJhdGlvbk9yTnVsbCgpKVxuICAgIHByb2Nlc3MuZXhpdChleGl0Q29kZSlcbiAgfSkoKVxuXG4gIHJldHVybiBzaHV0ZG93blByb21pc2Vcbn1cblxuLyoqXG4gKiBJZHMgb2Ygam9icyBjdXJyZW50bHkgcnVubmluZyBpbiB0aGlzIGNoaWxkLiBBIHBvb2xlZCBjaGlsZCBydW5zIHVwIHRvXG4gKiBgcG9vbGVkUnVubmVyQ29uY3VycmVuY3lgIGpvYnMgYXQgb25jZSAodGhlIHdvcmtlciBvbmx5IGRpc3BhdGNoZXMgd2l0aGluIHRoYXRcbiAqIGJvdW5kKTsgdGhlIHNldCBkZWR1cGVzIGEgcmVkZWxpdmVyZWQgam9iIGlkIGFuZCBsZXRzIGVhY2ggam9iIHNldHRsZVxuICogaW5kZXBlbmRlbnRseS5cbiAqIEB0eXBlIHtTZXQ8c3RyaW5nPn1cbiAqL1xuY29uc3QgcnVubmluZ0pvYklkcyA9IG5ldyBTZXQoKVxuY29uc3QgYnJva2VySWRlbnRpdHkgPSBuZXcgUG9vbGVkUnVubmVyQnJva2VySWRlbnRpdHkoe1xuICBjbG9zZUNvbm5lY3Rpb25zOiBhc3luYyAoKSA9PiBhd2FpdCBjbG9zZVJ1bm5lckZyYW1ld29ya0Nvbm5lY3Rpb25zKGN1cnJlbnRDb25maWd1cmF0aW9uT3JOdWxsKCkpXG59KVxuXG4vKipcbiAqIFNldHMgYW4gYWdncmVnYXRlIHByb2Nlc3MgdGl0bGUgZnJvbSB0aGUgY3VycmVudCBpbi1mbGlnaHQgY291bnQuIEEgY2hpbGQgcnVuc1xuICogam9icyBjb25jdXJyZW50bHksIHNvIGEgcGVyLWpvYiB0aXRsZSAod2hpY2ggYHJ1bkpvYlBheWxvYWRgIHdvdWxkIHNuYXBzaG90IGFuZFxuICogcmVzdG9yZSBhcm91bmQgYSBzaW5nbGUgam9iKSBjYW5ub3QgcmVwcmVzZW50IHRoZSBwcm9jZXNzIOKAlCBpbnRlcmxlYXZlZFxuICogY29tcGxldGlvbnMgd291bGQgbGVhdmUgYSBzdGFsZSBsYWJlbC4gUmVjb21wdXRpbmcgZnJvbSBgcnVubmluZ0pvYklkcy5zaXplYCBpc1xuICogY29uY3VycmVuY3ktc2FmZSBhbmQgaG9uZXN0OiBgcHNgL2B0b3BgIHNob3cgaG93IG1hbnkgam9icyB0aGUgY2hpbGQgaXMgcnVubmluZy5cbiAqIEByZXR1cm5zIHt2b2lkfVxuICovXG5mdW5jdGlvbiB1cGRhdGVQcm9jZXNzVGl0bGUoKSB7XG4gIGNvbnN0IGNvdW50ID0gcnVubmluZ0pvYklkcy5zaXplXG5cbiAgcHJvY2Vzcy50aXRsZSA9IGNvdW50ID4gMCA/IGAke0JBU0VfUFJPQ0VTU19USVRMRX06ICR7Y291bnR9ICR7Y291bnQgPT09IDEgPyBcImpvYlwiIDogXCJqb2JzXCJ9YCA6IEJBU0VfUFJPQ0VTU19USVRMRVxufVxuXG4vKipcbiAqIFNlbmRzIG9uZSBib3VuZGVkIGxpZmVjeWNsZSBvYnNlcnZhdGlvbiBiZWZvcmUgYXBwbGljYXRpb24vZnJhbWV3b3JrIHRlYXJkb3duLlxuICogQSBjbG9zZWQgSVBDIGNoYW5uZWwgaXMgZXhwZWN0ZWQgZm9yIGBpcGNfZGlzY29ubmVjdGA7IG90aGVyIHNlbmQgZmFpbHVyZXMgYXJlXG4gKiBzdXJmYWNlZCBvbiBzdGRlcnIgYnV0IG5ldmVyIGhvbGQgY29ubmVjdGlvbiBjbGVhbnVwIHBhc3QgdGhlIGZpeGVkIGJvdW5kLlxuICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBTaHV0ZG93biBvYnNlcnZhdGlvbi5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi90eXBlcy5qc1wiKS5Qb29sZWRDaGlsZFNodXRkb3duUmVhc29ufSBhcmdzLnJlYXNvbiAtIFNodXRkb3duIHJlYXNvbi5cbiAqIEBwYXJhbSB7bnVtYmVyIHwgbnVsbH0gYXJncy5zaHV0ZG93blJlcXVlc3RlZEF0TXMgLSBQYXJlbnQgcmVxdWVzdCB0aW1lc3RhbXAuXG4gKiBAcGFyYW0ge2ltcG9ydChcIm5vZGU6Y2hpbGRfcHJvY2Vzc1wiKS5DaGlsZFByb2Nlc3NbXCJzaWduYWxDb2RlXCJdfSBhcmdzLnNpZ25hbCAtIFJlcXVlc3RlZCBvciBvYnNlcnZlZCBzaWduYWwuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyBhZnRlciBJUEMgYWNjZXB0cyB0aGUgb2JzZXJ2YXRpb24gb3IgdGhlIGJvdW5kIGV4cGlyZXMuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHNlbmRTaHV0ZG93bk9ic2VydmF0aW9uKHtyZWFzb24sIHNodXRkb3duUmVxdWVzdGVkQXRNcywgc2lnbmFsfSkge1xuICBpZiAoIXByb2Nlc3Muc2VuZCB8fCAhcHJvY2Vzcy5jb25uZWN0ZWQpIHJldHVyblxuXG4gIGNvbnN0IGJvdW5kZWRJbmZsaWdodCA9IGJvdW5kZWRQb29sZWRSdW5uZXJJbmZsaWdodEpvYklkcyhydW5uaW5nSm9iSWRzKVxuICAvKiogQHR5cGUge2ltcG9ydChcIi4vdHlwZXMuanNcIikuUG9vbGVkQ2hpbGRTaHV0ZG93bk9ic2VydmF0aW9uICYge3R5cGU6IFwic2h1dGRvd24tb2JzZXJ2YXRpb25cIn19ICovXG4gIGNvbnN0IG1lc3NhZ2UgPSB7XG4gICAgY2hpbGRJbnN0YW5jZUlkLFxuICAgIC4uLmJvdW5kZWRJbmZsaWdodCxcbiAgICByZWFzb24sXG4gICAgc2h1dGRvd25PYnNlcnZlZEF0TXM6IERhdGUubm93KCksXG4gICAgc2h1dGRvd25SZXF1ZXN0ZWRBdE1zLFxuICAgIHNpZ25hbCxcbiAgICB0eXBlOiBcInNodXRkb3duLW9ic2VydmF0aW9uXCJcbiAgfVxuXG4gIHRyeSB7XG4gICAgYXdhaXQgdGltZW91dCh7dGltZW91dDogU0hVVERPV05fT0JTRVJWQVRJT05fU0VORF9USU1FT1VUX01TfSwgYXN5bmMgKCkgPT4ge1xuICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIHByb2Nlc3Muc2VuZD8uKG1lc3NhZ2UsIChlcnJvcikgPT4ge1xuICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgIHJlamVjdChlcnJvcilcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHJlc29sdmUodW5kZWZpbmVkKVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgcmVqZWN0KGVycm9yKVxuICAgICAgICB9XG4gICAgICB9KVxuICAgIH0pXG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgY29uc29sZS5lcnJvcihcIlBvb2xlZCBiYWNrZ3JvdW5kIGpvYiBydW5uZXIgY291bGQgbm90IHNlbmQgaXRzIHNodXRkb3duIG9ic2VydmF0aW9uOlwiLCBlcnJvcilcbiAgfVxufVxuXG4vKipcbiAqIFJlcG9ydHMgb25lIGFjY2VwdGFuY2Ugb2JzZXJ2YXRpb24gKGpvYiByZWNlaXZlZCAvIHBlcmZvcm0gc3RhcnRlZCkgdG8gdGhlXG4gKiB3b3JrZXIgb3ZlciBJUEMuIFRoZSBtZXNzYWdlIGNhcnJpZXMgdGhlIGpvYidzIGV4YWN0IGhhbmRvZmYgbGVhc2Ugc28gdGhlXG4gKiB3b3JrZXIgY2FuIHBlcnNpc3QgaXQgZmVuY2VkIHdpdGhvdXQgYW55IG90aGVyIGxvb2t1cC4gU2VuZCBmYWlsdXJlcyBhcmVcbiAqIHN3YWxsb3dlZDogYSBkZWFkIElQQyBjaGFubmVsIGlzIHRlcm1pbmFsIGZvciB0aGlzIGNoaWxkICh0aGUgZGlzY29ubmVjdFxuICogaGFuZGxlciBvd25zIHNodXRkb3duKSwgYW5kIGxvc2luZyBhY2NlcHRhbmNlIGV2aWRlbmNlIG11c3QgbmV2ZXIgZmFpbCB0aGVcbiAqIGpvYiBpdHNlbGYuXG4gKiBAcGFyYW0ge1wiam9iLXJlY2VpdmVkXCIgfCBcImpvYi1zdGFydGVkXCJ9IHR5cGUgLSBPYnNlcnZhdGlvbiBraW5kLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuL3R5cGVzLmpzXCIpLkJhY2tncm91bmRKb2JQYXlsb2FkICYge2lkOiBzdHJpbmd9fSBwYXlsb2FkIC0gSm9iIHBheWxvYWQgY2FycnlpbmcgdGhlIGhhbmRvZmYgbGVhc2UuXG4gKiBAcGFyYW0ge251bWJlcn0gb2JzZXJ2ZWRBdE1zIC0gRXBvY2ggbXMgb2YgdGhlIG9ic2VydmF0aW9uLlxuICogQHJldHVybnMge3ZvaWR9XG4gKi9cbmZ1bmN0aW9uIHNlbmRDaGlsZEFjY2VwdGFuY2UodHlwZSwgcGF5bG9hZCwgb2JzZXJ2ZWRBdE1zKSB7XG4gIGlmICghcHJvY2Vzcy5zZW5kKSByZXR1cm5cblxuICBjb25zdCBtZXNzYWdlID0ge1xuICAgIGNoaWxkSW5zdGFuY2VJZCxcbiAgICBjaGlsZFBpZDogcHJvY2Vzcy5waWQsXG4gICAgaGFuZGVkT2ZmQXRNczogcGF5bG9hZC5oYW5kZWRPZmZBdE1zLFxuICAgIGhhbmRvZmZJZDogcGF5bG9hZC5oYW5kb2ZmSWQsXG4gICAgam9iSWQ6IHBheWxvYWQuaWQsXG4gICAgdHlwZSxcbiAgICB3b3JrZXJJZDogcGF5bG9hZC53b3JrZXJJZCxcbiAgICAuLi4odHlwZSA9PT0gXCJqb2ItcmVjZWl2ZWRcIiA/IHtyZWNlaXZlZEF0TXM6IG9ic2VydmVkQXRNc30gOiB7c3RhcnRlZEF0TXM6IG9ic2VydmVkQXRNc30pXG4gIH1cblxuICB0cnkge1xuICAgIHByb2Nlc3Muc2VuZChtZXNzYWdlKVxuICB9IGNhdGNoIHtcbiAgICAvLyBUaGUgSVBDIGNoYW5uZWwgaXMgYWxyZWFkeSBnb25lOyB0aGUgZGlzY29ubmVjdCBoYW5kbGVyIG93bnMgc2h1dGRvd24uXG4gIH1cbn1cblxuLyoqXG4gKiBDaGVja3Mgd2hldGhlciBhbiBJUEMgdmFsdWUgaXMgYSBydW5uYWJsZSBwb29sZWQgam9iIG1lc3NhZ2UuXG4gKiBAcGFyYW0ge1JldHVyblR5cGU8dHlwZW9mIEpTT04ucGFyc2U+fSBtZXNzYWdlIC0gSVBDIG1lc3NhZ2UuXG4gKiBAcmV0dXJucyB7bWVzc2FnZSBpcyB7dHlwZTogXCJqb2JcIiwgcGF5bG9hZDogaW1wb3J0KFwiLi90eXBlcy5qc1wiKS5CYWNrZ3JvdW5kSm9iUGF5bG9hZCAmIHtpZDogc3RyaW5nfSwgc2hhcmVkVHJhbnNhY3Rpb25Ccm9rZXI/OiBpbXBvcnQoXCIuLi90ZXN0aW5nL3NoYXJlZC10cmFuc2FjdGlvbi1wcm94eS1kcml2ZXIuanNcIikuU2hhcmVkVHJhbnNhY3Rpb25Ccm9rZXJKb2JDb25maWd9fSAtIFdoZXRoZXIgdGhpcyBpcyBhIHZhbGlkIGpvYiBtZXNzYWdlLlxuICovXG5mdW5jdGlvbiBpc0pvYk1lc3NhZ2UobWVzc2FnZSkge1xuICBpZiAoIW1lc3NhZ2UgfHwgdHlwZW9mIG1lc3NhZ2UgIT09IFwib2JqZWN0XCIpIHJldHVybiBmYWxzZVxuICBjb25zdCByZWNvcmQgPSAvKiogQHR5cGUge3t0eXBlPzogUmV0dXJuVHlwZTx0eXBlb2YgSlNPTi5wYXJzZT4sIHBheWxvYWQ/OiBSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPiwgc2hhcmVkVHJhbnNhY3Rpb25Ccm9rZXI/OiBSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPn19ICovIChtZXNzYWdlKVxuXG4gIHJldHVybiByZWNvcmQudHlwZSA9PT0gXCJqb2JcIiAmJiAhIXJlY29yZC5wYXlsb2FkICYmIHR5cGVvZiByZWNvcmQucGF5bG9hZCA9PT0gXCJvYmplY3RcIiAmJiB0eXBlb2YgcmVjb3JkLnBheWxvYWQuaWQgPT09IFwic3RyaW5nXCJcbn1cblxuLyoqXG4gKiBDaGVja3Mgd2hldGhlciBhbiBJUEMgdmFsdWUgcmVxdWVzdHMgYSB0eXBlZCBwb29sZWQtY2hpbGQgc2h1dGRvd24uXG4gKiBAcGFyYW0ge1JldHVyblR5cGU8dHlwZW9mIEpTT04ucGFyc2U+fSBtZXNzYWdlIC0gSVBDIG1lc3NhZ2UuXG4gKiBAcmV0dXJucyB7bWVzc2FnZSBpcyB7dHlwZTogXCJzaHV0ZG93bi1yZXF1ZXN0XCIsIHJlYXNvbjogaW1wb3J0KFwiLi90eXBlcy5qc1wiKS5Qb29sZWRDaGlsZFNodXRkb3duUmVhc29uLCBzaHV0ZG93blJlcXVlc3RlZEF0TXM6IG51bWJlciwgc2lnbmFsOiBpbXBvcnQoXCJub2RlOmNoaWxkX3Byb2Nlc3NcIikuQ2hpbGRQcm9jZXNzW1wic2lnbmFsQ29kZVwiXX19IC0gV2hldGhlciB0aGlzIGlzIGEgdmFsaWQgcGFyZW50IHNodXRkb3duIHJlcXVlc3QuXG4gKi9cbmZ1bmN0aW9uIGlzU2h1dGRvd25SZXF1ZXN0TWVzc2FnZShtZXNzYWdlKSB7XG4gIGlmICghbWVzc2FnZSB8fCB0eXBlb2YgbWVzc2FnZSAhPT0gXCJvYmplY3RcIikgcmV0dXJuIGZhbHNlXG4gIGNvbnN0IHJlY29yZCA9IC8qKiBAdHlwZSB7e3R5cGU/OiBSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPiwgcmVhc29uPzogUmV0dXJuVHlwZTx0eXBlb2YgSlNPTi5wYXJzZT4sIHNodXRkb3duUmVxdWVzdGVkQXRNcz86IFJldHVyblR5cGU8dHlwZW9mIEpTT04ucGFyc2U+LCBzaWduYWw/OiBSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPn19ICovIChtZXNzYWdlKVxuXG4gIHJldHVybiByZWNvcmQudHlwZSA9PT0gXCJzaHV0ZG93bi1yZXF1ZXN0XCJcbiAgICAmJiBpc1Bvb2xlZENoaWxkU2h1dGRvd25SZWFzb24ocmVjb3JkLnJlYXNvbilcbiAgICAmJiB0eXBlb2YgcmVjb3JkLnNodXRkb3duUmVxdWVzdGVkQXRNcyA9PT0gXCJudW1iZXJcIlxuICAgICYmIE51bWJlci5pc0Zpbml0ZShyZWNvcmQuc2h1dGRvd25SZXF1ZXN0ZWRBdE1zKVxuICAgICYmIGlzUG9vbGVkQ2hpbGRTaHV0ZG93blNpZ25hbChyZWNvcmQuc2lnbmFsKVxufVxuXG4vKipcbiAqIFNlbmRzIHRoZSB0ZXJtaW5hbCBvdXRjb21lIGFmdGVyIHRoZSBtYWluL0RCIHJlcG9ydCBoYXMgYmVlbiBhY2tub3dsZWRnZWQgb3IgcmVqZWN0ZWQuXG4gKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIE91dGNvbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gYXJncy5qb2JJZCAtIEpvYiBpZC5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYXJncy5hY2tub3dsZWRnZWQgLSBXaGV0aGVyIHRoZSB0ZXJtaW5hbCByZXBvcnQgd2FzIGFja25vd2xlZGdlZC5cbiAqIEBwYXJhbSB7XCJjb21wbGV0ZWRcIiB8IFwiZmFpbGVkXCIgfCBcInJlc2NoZWR1bGVkXCJ9IFthcmdzLnN0YXR1c10gLSBBY2tub3dsZWRnZWQgb3V0Y29tZS5cbiAqIEBwYXJhbSB7RXJyb3J9IFthcmdzLmVycm9yXSAtIFJlcG9ydGluZyBlcnJvciB3aGVuIGFja25vd2xlZGdlbWVudCB3YXMgbm90IG9idGFpbmVkLlxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgYWZ0ZXIgSVBDIGFjY2VwdHMgdGhlIG1lc3NhZ2UuXG4gKi9cbmZ1bmN0aW9uIHNlbmRPdXRjb21lKHtqb2JJZCwgYWNrbm93bGVkZ2VkLCBzdGF0dXMsIGVycm9yfSkge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICBpZiAoIXByb2Nlc3Muc2VuZCkge1xuICAgICAgcmVzb2x2ZSh1bmRlZmluZWQpXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICBwcm9jZXNzLnNlbmQoe1xuICAgICAgdHlwZTogXCJqb2Itb3V0Y29tZVwiLFxuICAgICAgam9iSWQsXG4gICAgICBhY2tub3dsZWRnZWQsXG4gICAgICBzdGF0dXMsXG4gICAgICByc3NCeXRlczogcHJvY2Vzcy5tZW1vcnlVc2FnZSgpLnJzcyxcbiAgICAgIGVycm9yOiBlcnJvcj8ubWVzc2FnZVxuICAgIH0sICgpID0+IHJlc29sdmUodW5kZWZpbmVkKSlcbiAgfSlcbn1cblxuLyoqXG4gKiBSdW5zIG9uZSBqb2IgY29uY3VycmVudGx5IHdpdGggYW55IHNpYmxpbmdzIGFuZCByZXBvcnRzIGl0cyBvd24gdGVybWluYWxcbiAqIG91dGNvbWUuIEEgc2luZ2xlIGpvYidzIHVuZXhwZWN0ZWQgZmFpbHVyZSByZXBvcnRzIHRoYXQgam9iIGZvciByZWNsYW1hdGlvblxuICogKGBhY2tub3dsZWRnZWQ6IGZhbHNlYCkgYnV0IGRvZXMgTk9UIHRha2UgZG93biB0aGUgY2hpbGQg4oCUIGl0cyBjb25jdXJyZW50XG4gKiBzaWJsaW5ncyBrZWVwIHJ1bm5pbmcuIE9ubHkgYSBwcm9jZXNzLWxldmVsIGZhdWx0ICh3aGljaCBlc2NhcGVzIGV2ZXJ5XG4gKiBwZXItam9iIHRyeS9jYXRjaCkgZW5kcyB0aGUgY2hpbGQsIHdoaWNoIHRoZSB3b3JrZXIgc2VlcyBhcyBhbiBleGl0IGFuZFxuICogcmVjbGFpbXMgZm9yIHRoZSB3aG9sZSBpbi1mbGlnaHQgc2V0LlxuICogQHBhcmFtIHtpbXBvcnQoXCIuL3R5cGVzLmpzXCIpLkJhY2tncm91bmRKb2JQYXlsb2FkICYge2lkOiBzdHJpbmd9fSBwYXlsb2FkIC0gSm9iIHBheWxvYWQuXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4uL3Rlc3Rpbmcvc2hhcmVkLXRyYW5zYWN0aW9uLXByb3h5LWRyaXZlci5qc1wiKS5TaGFyZWRUcmFuc2FjdGlvbkJyb2tlckpvYkNvbmZpZ30gc2hhcmVkVHJhbnNhY3Rpb25Ccm9rZXIgLSBQZXItam9iIGJyb2tlciBjb25maWd1cmF0aW9uLlxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgYWZ0ZXIgcmVwb3J0aW5nLlxuICovXG5hc3luYyBmdW5jdGlvbiBydW5Kb2IocGF5bG9hZCwgc2hhcmVkVHJhbnNhY3Rpb25Ccm9rZXIpIHtcbiAgdHJ5IHtcbiAgICBjb25zdCBzdGF0dXMgPSBhd2FpdCBydW5XaXRoU2hhcmVkVHJhbnNhY3Rpb25Ccm9rZXJDb25maWcoc2hhcmVkVHJhbnNhY3Rpb25Ccm9rZXIsIGFzeW5jICgpID0+IHtcbiAgICAgIHJldHVybiBhd2FpdCBicm9rZXJJZGVudGl0eS5ydW4oc2hhcmVkVHJhbnNhY3Rpb25Ccm9rZXIsIGFzeW5jICgpID0+IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHJ1bkpvYlBheWxvYWQocGF5bG9hZCwge1xuICAgICAgICAgIGNsb3NlQ29ubmVjdGlvbnM6IGZhbHNlLFxuICAgICAgICAgIG1hbmFnZVByb2Nlc3NUaXRsZTogZmFsc2UsXG4gICAgICAgICAgb25QZXJmb3JtU3RhcnQ6ICgpID0+IHNlbmRDaGlsZEFjY2VwdGFuY2UoXCJqb2Itc3RhcnRlZFwiLCBwYXlsb2FkLCBEYXRlLm5vdygpKSxcbiAgICAgICAgICBwcm9jZXNzVHlwZTogXCJiYWNrZ3JvdW5kLWpvYnMtcG9vbGVkLXJ1bm5lclwiXG4gICAgICAgIH0pXG4gICAgICB9KVxuICAgIH0pXG4gICAgYXdhaXQgc2VuZE91dGNvbWUoe2pvYklkOiBwYXlsb2FkLmlkLCBhY2tub3dsZWRnZWQ6IHRydWUsIHN0YXR1c30pXG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgaWYgKGVycm9yIGluc3RhbmNlb2YgQmFja2dyb3VuZEpvYlBlcmZvcm1lZEZhaWx1cmUpIHtcbiAgICAgIGF3YWl0IHNlbmRPdXRjb21lKHtqb2JJZDogcGF5bG9hZC5pZCwgYWNrbm93bGVkZ2VkOiB0cnVlLCBzdGF0dXM6IFwiZmFpbGVkXCJ9KVxuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCByZXBvcnRFcnJvciA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvciA6IG5ldyBFcnJvcihTdHJpbmcoZXJyb3IpKVxuICAgICAgY29uc29sZS5lcnJvcihcIlBvb2xlZCBiYWNrZ3JvdW5kIGpvYiBydW5uZXIgZmFpbGVkIGJlZm9yZSB0ZXJtaW5hbCBhY2tub3dsZWRnZW1lbnQ6XCIsIHJlcG9ydEVycm9yKVxuICAgICAgYXdhaXQgc2VuZE91dGNvbWUoe2pvYklkOiBwYXlsb2FkLmlkLCBhY2tub3dsZWRnZWQ6IGZhbHNlLCBlcnJvcjogcmVwb3J0RXJyb3J9KVxuICAgIH1cbiAgfSBmaW5hbGx5IHtcbiAgICBydW5uaW5nSm9iSWRzLmRlbGV0ZShwYXlsb2FkLmlkKVxuICAgIHVwZGF0ZVByb2Nlc3NUaXRsZSgpXG4gIH1cbn1cblxuLyoqXG4gKiBIYW5kbGVzIGEgam9iIG1lc3NhZ2UsIHN0YXJ0aW5nIGl0IGFsb25nc2lkZSBhbnkgY29uY3VycmVudCBzaWJsaW5ncy5cbiAqIEBwYXJhbSB7UmV0dXJuVHlwZTx0eXBlb2YgSlNPTi5wYXJzZT59IG1lc3NhZ2UgLSBJUEMgbWVzc2FnZS5cbiAqIEByZXR1cm5zIHt2b2lkfVxuICovXG5mdW5jdGlvbiBoYW5kbGVNZXNzYWdlKG1lc3NhZ2UpIHtcbiAgaWYgKGlzU2h1dGRvd25SZXF1ZXN0TWVzc2FnZShtZXNzYWdlKSkge1xuICAgIHZvaWQgc2h1dGRvd25SdW5uZXIoe1xuICAgICAgZXhpdENvZGU6IG1lc3NhZ2UucmVhc29uID09PSBcInBhcmVudF9yZXRpcmVfZHJhaW5lZFwiID8gMCA6IDEsXG4gICAgICByZWFzb246IG1lc3NhZ2UucmVhc29uLFxuICAgICAgc2h1dGRvd25SZXF1ZXN0ZWRBdE1zOiBtZXNzYWdlLnNodXRkb3duUmVxdWVzdGVkQXRNcyxcbiAgICAgIHNpZ25hbDogbWVzc2FnZS5zaWduYWxcbiAgICB9KVxuICAgIHJldHVyblxuICB9XG5cbiAgaWYgKCFpc0pvYk1lc3NhZ2UobWVzc2FnZSkgfHwgcnVubmluZ0pvYklkcy5oYXMobWVzc2FnZS5wYXlsb2FkLmlkKSkgcmV0dXJuXG5cbiAgcnVubmluZ0pvYklkcy5hZGQobWVzc2FnZS5wYXlsb2FkLmlkKVxuICB1cGRhdGVQcm9jZXNzVGl0bGUoKVxuICBzZW5kQ2hpbGRBY2NlcHRhbmNlKFwiam9iLXJlY2VpdmVkXCIsIG1lc3NhZ2UucGF5bG9hZCwgRGF0ZS5ub3coKSlcbiAgdm9pZCBydW5Kb2IobWVzc2FnZS5wYXlsb2FkLCBtZXNzYWdlLnNoYXJlZFRyYW5zYWN0aW9uQnJva2VyIHx8IHtleHBlY3RlZDogZmFsc2V9KVxufVxuXG5wcm9jZXNzLm9uKFwibWVzc2FnZVwiLCAobWVzc2FnZSkgPT4gaGFuZGxlTWVzc2FnZShtZXNzYWdlKSlcbnByb2Nlc3Mub25jZShcImRpc2Nvbm5lY3RcIiwgKCkgPT4gdm9pZCBzaHV0ZG93blJ1bm5lcih7ZXhpdENvZGU6IDAsIHJlYXNvbjogXCJpcGNfZGlzY29ubmVjdFwifSkpXG5wcm9jZXNzLm9uY2UoXCJTSUdURVJNXCIsICgpID0+IHZvaWQgc2h1dGRvd25SdW5uZXIoe2V4aXRDb2RlOiAxLCByZWFzb246IFwic2lnbmFsX3NpZ3Rlcm1cIiwgc2lnbmFsOiBcIlNJR1RFUk1cIn0pKVxucHJvY2Vzcy5vbmNlKFwiU0lHSU5UXCIsICgpID0+IHZvaWQgc2h1dGRvd25SdW5uZXIoe2V4aXRDb2RlOiAxLCByZWFzb246IFwic2lnbmFsX3NpZ2ludFwiLCBzaWduYWw6IFwiU0lHSU5UXCJ9KSlcbmlmIChwcm9jZXNzLnNlbmQpIHByb2Nlc3Muc2VuZCh7Y2hpbGRJbnN0YW5jZUlkLCBjaGlsZFBpZDogcHJvY2Vzcy5waWQsIHR5cGU6IFwicmVhZHlcIn0pXG4iXX0=
|
|
354
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicG9vbGVkLXJ1bm5lci1jaGlsZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9iYWNrZ3JvdW5kLWpvYnMvcG9vbGVkLXJ1bm5lci1jaGlsZC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGFBQWEsQ0FBQTtBQUN4QyxPQUFPLEVBQUUsTUFBTSxTQUFTLENBQUE7QUFDeEIsT0FBTyxPQUFPLE1BQU0sMkJBQTJCLENBQUE7QUFDL0MsT0FBTyxhQUFhLEVBQUUsRUFBRSw2QkFBNkIsRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBQzlFLE9BQU8sRUFBRSxpQ0FBaUMsRUFBRSwyQkFBMkIsRUFBRSwyQkFBMkIsRUFBRSxNQUFNLDZCQUE2QixDQUFBO0FBQ3pJLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSwrQkFBK0IsRUFBRSwwQkFBMEIsRUFBRSxNQUFNLCtCQUErQixDQUFBO0FBQ25JLE9BQU8scUJBQXFCLE1BQU0sMkJBQTJCLENBQUE7QUFDN0QsT0FBTywwQkFBMEIsTUFBTSxvQ0FBb0MsQ0FBQTtBQUMzRSxPQUFPLEVBQUUsb0NBQW9DLEVBQUUsTUFBTSwrQ0FBK0MsQ0FBQTtBQUVwRyxNQUFNLGtCQUFrQixHQUFHLGtDQUFrQyxDQUFBO0FBQzdELHlGQUF5RjtBQUN6RixNQUFNLG9DQUFvQyxHQUFHLEdBQUcsQ0FBQTtBQUNoRCxnRkFBZ0Y7QUFDaEYsTUFBTSxlQUFlLEdBQUcsVUFBVSxFQUFFLENBQUE7QUFDcEMsMkRBQTJEO0FBQzNELE1BQU0sOEJBQThCLEdBQUcsS0FBSyxDQUFBO0FBQzVDLGtFQUFrRTtBQUNsRSxNQUFNLCtCQUErQixHQUFHLEVBQUUsQ0FBQTtBQUUxQyxxQkFBcUIsRUFBRSxDQUFBO0FBRXZCLHdDQUF3QztBQUN4QyxJQUFJLGVBQWUsQ0FBQTtBQUVuQjs7Ozs7Ozs7OztHQVVHO0FBQ0gsU0FBUyxjQUFjLENBQUMsRUFBQyxRQUFR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LEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBQyxDQUFDLENBQUMsQ0FBQTtBQUM5RyxPQUFPLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxLQUFLLGNBQWMsQ0FBQyxFQUFDLFFBQVEsRUFBRSxDQUFDLEVBQUUsTUFBTSxFQUFFLGVBQWUsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFDLENBQUMsQ0FBQyxDQUFBO0FBQzNHLElBQUksT0FBTyxDQUFDLElBQUk7SUFBRSxPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUMsZUFBZSxFQUFFLFFBQVEsRUFBRSxPQUFPLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUMsQ0FBQyxDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCB7IHJhbmRvbVVVSUQgfSBmcm9tIFwibm9kZTpjcnlwdG9cIlxuaW1wb3J0IHY4IGZyb20gXCJub2RlOnY4XCJcbmltcG9ydCB0aW1lb3V0IGZyb20gXCJhd2FpdGVyeS9idWlsZC90aW1lb3V0LmpzXCJcbmltcG9ydCBydW5Kb2JQYXlsb2FkLCB7IEJhY2tncm91bmRKb2JQZXJmb3JtZWRGYWlsdXJlIH0gZnJvbSBcIi4vam9iLXJ1bm5lci5qc1wiXG5pbXBvcnQgeyBib3VuZGVkUG9vbGVkUnVubmVySW5mbGlnaHRKb2JJZHMsIGlzUG9vbGVkQ2hpbGRTaHV0ZG93blJlYXNvbiwgaXNQb29sZWRDaGlsZFNodXRkb3duU2lnbmFsIH0gZnJvbSBcIi4vcG9vbGVkLXJ1bm5lci1zaHV0ZG93bi5qc1wiXG5pbXBvcnQgeyBjbG9zZVJ1bm5lckNvbm5lY3Rpb25zLCBjbG9zZVJ1bm5lckZyYW1ld29ya0Nvbm5lY3Rpb25zLCBjdXJyZW50Q29uZmlndXJhdGlvbk9yTnVsbCB9IGZyb20gXCIuL3J1bm5lci1ncmFjZWZ1bC1zaHV0ZG93bi5qc1wiXG5pbXBvcnQgc2V0UnVubmVyUHJvY2Vzc1RpdGxlIGZyb20gXCIuL3J1bm5lci1wcm9jZXNzLXRpdGxlLmpzXCJcbmltcG9ydCBQb29sZWRSdW5uZXJCcm9rZXJJZGVudGl0eSBmcm9tIFwiLi9wb29sZWQtcnVubmVyLWJyb2tlci1pZGVudGl0eS5qc1wiXG5pbXBvcnQgeyBydW5XaXRoU2hhcmVkVHJhbnNhY3Rpb25Ccm9rZXJDb25maWcgfSBmcm9tIFwiLi4vdGVzdGluZy9zaGFyZWQtdHJhbnNhY3Rpb24tcHJveHktZHJpdmVyLmpzXCJcblxuY29uc3QgQkFTRV9QUk9DRVNTX1RJVExFID0gXCJ2ZWxvY2lvdXMgYmFja2dyb3VuZC1qb2JzLXJ1bm5lclwiXG4vKiogQSBzaHV0ZG93biBvYnNlcnZhdGlvbiBtYXkgZGVsYXkgcmVzb3VyY2UgdGVhcmRvd24gb25seSBmb3IgdGhpcyBib3VuZGVkIElQQyBzZW5kLiAqL1xuY29uc3QgU0hVVERPV05fT0JTRVJWQVRJT05fU0VORF9USU1FT1VUX01TID0gMTAwXG4vKiogU3RhYmxlIGlkZW50aXR5IG9mIHRoaXMgcG9vbGVkIGNoaWxkIHByb2Nlc3MgZm9yIHRoZSBsaWZlIG9mIHRoZSBwcm9jZXNzLiAqL1xuY29uc3QgY2hpbGRJbnN0YW5jZUlkID0gcmFuZG9tVVVJRCgpXG4vKiogU2FtcGxpbmcgY2FkZW5jZSBmb3IgdGhlIG1lbW9yeSBvYnNlcnZhdGlvbiBzYW1wbGVyLiAqL1xuY29uc3QgTUVNT1JZX09CU0VSVkFUSU9OX0lOVEVSVkFMX01TID0gMTAwMDBcbi8qKiBCb3VuZCBvbiBpbi1mbGlnaHQgam9iIGlkcyBjYXJyaWVkIGluIGEgbWVtb3J5IG9ic2VydmF0aW9uLiAqL1xuY29uc3QgTUVNT1JZX09CU0VSVkFUSU9OX0pPQl9JRF9MSU1JVCA9IDMyXG5cbnNldFJ1bm5lclByb2Nlc3NUaXRsZSgpXG5cbi8qKiBAdHlwZSB7UHJvbWlzZTx2b2lkPiB8IHVuZGVmaW5lZH0gKi9cbmxldCBzaHV0ZG93blByb21pc2VcblxuLyoqXG4gKiBDbG9zZXMgdGhlIHJ1bm5lcidzIGNvbm5lY3Rpb25zIOKAlCByZWxlYXNpbmcgYW55IGFkdmlzb3J5IGxvY2sgYSBraWxsZWQtbWlkLXBhc3NcbiAqIGpvYiBzdGlsbCBob2xkcyDigJQgYmVmb3JlIGV4aXRpbmcsIGluc3RlYWQgb2YgbGVhdmluZyBhIGhhbGYtb3BlbiBzZXNzaW9uIHRoYXRcbiAqIGtlZXBzIHRoZSBsb2NrIHVudGlsIHRoZSBEQiBzZXJ2ZXIncyBgd2FpdF90aW1lb3V0YC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gU2h1dGRvd24gb2JzZXJ2YXRpb24uXG4gKiBAcGFyYW0ge251bWJlcn0gYXJncy5leGl0Q29kZSAtIFByb2Nlc3MgZXhpdCBjb2RlLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuL3R5cGVzLmpzXCIpLlBvb2xlZENoaWxkU2h1dGRvd25SZWFzb259IGFyZ3MucmVhc29uIC0gRXhhY3Qgc2h1dGRvd24gcmVhc29uIG9ic2VydmVkIGJ5IHRoZSBjaGlsZC5cbiAqIEBwYXJhbSB7bnVtYmVyIHwgbnVsbH0gW2FyZ3Muc2h1dGRvd25SZXF1ZXN0ZWRBdE1zXSAtIFBhcmVudCByZXF1ZXN0IHRpbWVzdGFtcCB3aGVuIHN1cHBsaWVkIG92ZXIgSVBDLlxuICogQHBhcmFtIHtpbXBvcnQoXCJub2RlOmNoaWxkX3Byb2Nlc3NcIikuQ2hpbGRQcm9jZXNzW1wic2lnbmFsQ29kZVwiXX0gW2FyZ3Muc2lnbmFsXSAtIFJlcXVlc3RlZCBvciBvYnNlcnZlZCBzaWduYWwuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn1cbiAqL1xuZnVuY3Rpb24gc2h1dGRvd25SdW5uZXIoe2V4aXRDb2RlLCByZWFzb24sIHNodXRkb3duUmVxdWVzdGVkQXRNcyA9IG51bGwsIHNpZ25hbCA9IG51bGx9KSB7XG4gIGlmIChzaHV0ZG93blByb21pc2UpIHJldHVybiBzaHV0ZG93blByb21pc2VcblxuICBzaHV0ZG93blByb21pc2UgPSAoYXN5bmMgKCkgPT4ge1xuICAgIGF3YWl0IHNlbmRTaHV0ZG93bk9ic2VydmF0aW9uKHtyZWFzb24sIHNodXRkb3duUmVxdWVzdGVkQXRNcywgc2lnbmFsfSlcbiAgICBhd2FpdCBjbG9zZVJ1bm5lckNvbm5lY3Rpb25zKGN1cnJlbnRDb25maWd1cmF0aW9uT3JOdWxsKCkpXG4gICAgcHJvY2Vzcy5leGl0KGV4aXRDb2RlKVxuICB9KSgpXG5cbiAgcmV0dXJuIHNodXRkb3duUHJvbWlzZVxufVxuXG4vKipcbiAqIElkcyBvZiBqb2JzIGN1cnJlbnRseSBydW5uaW5nIGluIHRoaXMgY2hpbGQuIEEgcG9vbGVkIGNoaWxkIHJ1bnMgdXAgdG9cbiAqIGBwb29sZWRSdW5uZXJDb25jdXJyZW5jeWAgam9icyBhdCBvbmNlICh0aGUgd29ya2VyIG9ubHkgZGlzcGF0Y2hlcyB3aXRoaW4gdGhhdFxuICogYm91bmQpOyB0aGUgc2V0IGRlZHVwZXMgYSByZWRlbGl2ZXJlZCBqb2IgaWQgYW5kIGxldHMgZWFjaCBqb2Igc2V0dGxlXG4gKiBpbmRlcGVuZGVudGx5LlxuICogQHR5cGUge1NldDxzdHJpbmc+fVxuICovXG5jb25zdCBydW5uaW5nSm9iSWRzID0gbmV3IFNldCgpXG5jb25zdCBicm9rZXJJZGVudGl0eSA9IG5ldyBQb29sZWRSdW5uZXJCcm9rZXJJZGVudGl0eSh7XG4gIGNsb3NlQ29ubmVjdGlvbnM6IGFzeW5jICgpID0+IGF3YWl0IGNsb3NlUnVubmVyRnJhbWV3b3JrQ29ubmVjdGlvbnMoY3VycmVudENvbmZpZ3VyYXRpb25Pck51bGwoKSlcbn0pXG5cbi8qKlxuICogU2V0cyBhbiBhZ2dyZWdhdGUgcHJvY2VzcyB0aXRsZSBmcm9tIHRoZSBjdXJyZW50IGluLWZsaWdodCBjb3VudC4gQSBjaGlsZCBydW5zXG4gKiBqb2JzIGNvbmN1cnJlbnRseSwgc28gYSBwZXItam9iIHRpdGxlICh3aGljaCBgcnVuSm9iUGF5bG9hZGAgd291bGQgc25hcHNob3QgYW5kXG4gKiByZXN0b3JlIGFyb3VuZCBhIHNpbmdsZSBqb2IpIGNhbm5vdCByZXByZXNlbnQgdGhlIHByb2Nlc3Mg4oCUIGludGVybGVhdmVkXG4gKiBjb21wbGV0aW9ucyB3b3VsZCBsZWF2ZSBhIHN0YWxlIGxhYmVsLiBSZWNvbXB1dGluZyBmcm9tIGBydW5uaW5nSm9iSWRzLnNpemVgIGlzXG4gKiBjb25jdXJyZW5jeS1zYWZlIGFuZCBob25lc3Q6IGBwc2AvYHRvcGAgc2hvdyBob3cgbWFueSBqb2JzIHRoZSBjaGlsZCBpcyBydW5uaW5nLlxuICogQHJldHVybnMge3ZvaWR9XG4gKi9cbmZ1bmN0aW9uIHVwZGF0ZVByb2Nlc3NUaXRsZSgpIHtcbiAgY29uc3QgY291bnQgPSBydW5uaW5nSm9iSWRzLnNpemVcblxuICBwcm9jZXNzLnRpdGxlID0gY291bnQgPiAwID8gYCR7QkFTRV9QUk9DRVNTX1RJVExFfTogJHtjb3VudH0gJHtjb3VudCA9PT0gMSA/IFwiam9iXCIgOiBcImpvYnNcIn1gIDogQkFTRV9QUk9DRVNTX1RJVExFXG59XG5cbi8qKlxuICogU2VuZHMgb25lIGJvdW5kZWQgbGlmZWN5Y2xlIG9ic2VydmF0aW9uIGJlZm9yZSBhcHBsaWNhdGlvbi9mcmFtZXdvcmsgdGVhcmRvd24uXG4gKiBBIGNsb3NlZCBJUEMgY2hhbm5lbCBpcyBleHBlY3RlZCBmb3IgYGlwY19kaXNjb25uZWN0YDsgb3RoZXIgc2VuZCBmYWlsdXJlcyBhcmVcbiAqIHN1cmZhY2VkIG9uIHN0ZGVyciBidXQgbmV2ZXIgaG9sZCBjb25uZWN0aW9uIGNsZWFudXAgcGFzdCB0aGUgZml4ZWQgYm91bmQuXG4gKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIFNodXRkb3duIG9ic2VydmF0aW9uLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuL3R5cGVzLmpzXCIpLlBvb2xlZENoaWxkU2h1dGRvd25SZWFzb259IGFyZ3MucmVhc29uIC0gU2h1dGRvd24gcmVhc29uLlxuICogQHBhcmFtIHtudW1iZXIgfCBudWxsfSBhcmdzLnNodXRkb3duUmVxdWVzdGVkQXRNcyAtIFBhcmVudCByZXF1ZXN0IHRpbWVzdGFtcC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwibm9kZTpjaGlsZF9wcm9jZXNzXCIpLkNoaWxkUHJvY2Vzc1tcInNpZ25hbENvZGVcIl19IGFyZ3Muc2lnbmFsIC0gUmVxdWVzdGVkIG9yIG9ic2VydmVkIHNpZ25hbC5cbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIGFmdGVyIElQQyBhY2NlcHRzIHRoZSBvYnNlcnZhdGlvbiBvciB0aGUgYm91bmQgZXhwaXJlcy5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gc2VuZFNodXRkb3duT2JzZXJ2YXRpb24oe3JlYXNvbiwgc2h1dGRvd25SZXF1ZXN0ZWRBdE1zLCBzaWduYWx9KSB7XG4gIGlmICghcHJvY2Vzcy5zZW5kIHx8ICFwcm9jZXNzLmNvbm5lY3RlZCkgcmV0dXJuXG5cbiAgY29uc3QgYm91bmRlZEluZmxpZ2h0ID0gYm91bmRlZFBvb2xlZFJ1bm5lckluZmxpZ2h0Sm9iSWRzKHJ1bm5pbmdKb2JJZHMpXG4gIC8qKiBAdHlwZSB7aW1wb3J0KFwiLi90eXBlcy5qc1wiKS5Qb29sZWRDaGlsZFNodXRkb3duT2JzZXJ2YXRpb24gJiB7dHlwZTogXCJzaHV0ZG93bi1vYnNlcnZhdGlvblwifX0gKi9cbiAgY29uc3QgbWVzc2FnZSA9IHtcbiAgICBjaGlsZEluc3RhbmNlSWQsXG4gICAgLi4uYm91bmRlZEluZmxpZ2h0LFxuICAgIHJlYXNvbixcbiAgICBzaHV0ZG93bk9ic2VydmVkQXRNczogRGF0ZS5ub3coKSxcbiAgICBzaHV0ZG93blJlcXVlc3RlZEF0TXMsXG4gICAgc2lnbmFsLFxuICAgIHR5cGU6IFwic2h1dGRvd24tb2JzZXJ2YXRpb25cIlxuICB9XG5cbiAgdHJ5IHtcbiAgICBhd2FpdCB0aW1lb3V0KHt0aW1lb3V0OiBTSFVURE9XTl9PQlNFUlZBVElPTl9TRU5EX1RJTUVPVVRfTVN9LCBhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgcHJvY2Vzcy5zZW5kPy4obWVzc2FnZSwgKGVycm9yKSA9PiB7XG4gICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgcmVqZWN0KGVycm9yKVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgcmVzb2x2ZSh1bmRlZmluZWQpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSlcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICByZWplY3QoZXJyb3IpXG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgfSlcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBjb25zb2xlLmVycm9yKFwiUG9vbGVkIGJhY2tncm91bmQgam9iIHJ1bm5lciBjb3VsZCBub3Qgc2VuZCBpdHMgc2h1dGRvd24gb2JzZXJ2YXRpb246XCIsIGVycm9yKVxuICB9XG59XG5cbi8qKlxuICogUmVwb3J0cyBvbmUgYWNjZXB0YW5jZSBvYnNlcnZhdGlvbiAoam9iIHJlY2VpdmVkIC8gcGVyZm9ybSBzdGFydGVkKSB0byB0aGVcbiAqIHdvcmtlciBvdmVyIElQQy4gVGhlIG1lc3NhZ2UgY2FycmllcyB0aGUgam9iJ3MgZXhhY3QgaGFuZG9mZiBsZWFzZSBzbyB0aGVcbiAqIHdvcmtlciBjYW4gcGVyc2lzdCBpdCBmZW5jZWQgd2l0aG91dCBhbnkgb3RoZXIgbG9va3VwLiBTZW5kIGZhaWx1cmVzIGFyZVxuICogc3dhbGxvd2VkOiBhIGRlYWQgSVBDIGNoYW5uZWwgaXMgdGVybWluYWwgZm9yIHRoaXMgY2hpbGQgKHRoZSBkaXNjb25uZWN0XG4gKiBoYW5kbGVyIG93bnMgc2h1dGRvd24pLCBhbmQgbG9zaW5nIGFjY2VwdGFuY2UgZXZpZGVuY2UgbXVzdCBuZXZlciBmYWlsIHRoZVxuICogam9iIGl0c2VsZi5cbiAqIEBwYXJhbSB7XCJqb2ItcmVjZWl2ZWRcIiB8IFwiam9iLXN0YXJ0ZWRcIn0gdHlwZSAtIE9ic2VydmF0aW9uIGtpbmQuXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4vdHlwZXMuanNcIikuQmFja2dyb3VuZEpvYlBheWxvYWQgJiB7aWQ6IHN0cmluZ319IHBheWxvYWQgLSBKb2IgcGF5bG9hZCBjYXJyeWluZyB0aGUgaGFuZG9mZiBsZWFzZS5cbiAqIEBwYXJhbSB7bnVtYmVyfSBvYnNlcnZlZEF0TXMgLSBFcG9jaCBtcyBvZiB0aGUgb2JzZXJ2YXRpb24uXG4gKiBAcmV0dXJucyB7dm9pZH1cbiAqL1xuZnVuY3Rpb24gc2VuZENoaWxkQWNjZXB0YW5jZSh0eXBlLCBwYXlsb2FkLCBvYnNlcnZlZEF0TXMpIHtcbiAgaWYgKCFwcm9jZXNzLnNlbmQpIHJldHVyblxuXG4gIGNvbnN0IG1lc3NhZ2UgPSB7XG4gICAgY2hpbGRJbnN0YW5jZUlkLFxuICAgIGNoaWxkUGlkOiBwcm9jZXNzLnBpZCxcbiAgICBoYW5kZWRPZmZBdE1zOiBwYXlsb2FkLmhhbmRlZE9mZkF0TXMsXG4gICAgaGFuZG9mZklkOiBwYXlsb2FkLmhhbmRvZmZJZCxcbiAgICBqb2JJZDogcGF5bG9hZC5pZCxcbiAgICB0eXBlLFxuICAgIHdvcmtlcklkOiBwYXlsb2FkLndvcmtlcklkLFxuICAgIC4uLih0eXBlID09PSBcImpvYi1yZWNlaXZlZFwiID8ge3JlY2VpdmVkQXRNczogb2JzZXJ2ZWRBdE1zfSA6IHtzdGFydGVkQXRNczogb2JzZXJ2ZWRBdE1zfSlcbiAgfVxuXG4gIHRyeSB7XG4gICAgcHJvY2Vzcy5zZW5kKG1lc3NhZ2UpXG4gIH0gY2F0Y2gge1xuICAgIC8vIFRoZSBJUEMgY2hhbm5lbCBpcyBhbHJlYWR5IGdvbmU7IHRoZSBkaXNjb25uZWN0IGhhbmRsZXIgb3ducyBzaHV0ZG93bi5cbiAgfVxufVxuXG4vKipcbiAqIENvbGxlY3RzIGEgYm91bmRlZCBkaWFnbm9zdGljIHNuYXBzaG90IG9mIHRoaXMgY2hpbGQncyBtZW1vcnkgc3RhdGUuIFRoZVxuICogcG9vbGVkIGNoaWxkJ3Mgc3RkaW8gaXMgaWdub3JlZCBieSB0aGUgd29ya2VyIGZvcmssIHNvIElQQyBpcyB0aGUgb25seSBjaGFubmVsXG4gKiB0byB0aGUgd29ya2VyJ3MgbG9nIHN1cmZhY2Ug4oCUIHRoaXMgc25hcHNob3QgKHNlbnQgcGVyaW9kaWNhbGx5IGFuZCBvbiBkZW1hbmQpXG4gKiBpcyBob3cgYSBtZW1vcnkgcHJvYmxlbSBuYW1lcyBpdHNlbGYgaW4gcHJvZHVjdGlvbi4gVGhlIFY4IGhlYXAtc3RhdFxuICogYnJlYWtkb3duIChub3QgYSBmdWxsIGhlYXAgc25hcHNob3QsIHdoaWNoIHdvdWxkIGJlIGZhciB0b28gZXhwZW5zaXZlIHdoaWxlIGFcbiAqIGNoaWxkIHJ1bnMgMjUgY29uY3VycmVudCBqb2JzKSBkaXN0aW5ndWlzaGVzIGEgVjggaGVhcC1ncm93dGggbGVhayBmcm9tXG4gKiBleHRlcm5hbC9hcnJheS1idWZmZXIgKG5hdGl2ZSByZXNvdXJjZSkgZ3Jvd3RoLCBhbmQgdGhlIGluLWZsaWdodCBqb2IgaWRzXG4gKiB0aWUgdGhlIG9ic2VydmF0aW9uIHRvIHRoZSB3b3JrIHRoYXQgd2FzIHJ1bm5pbmcuXG4gKiBAcmV0dXJucyB7e2FjdGl2ZUpvYklkczogc3RyaW5nW10sIGFjdGl2ZUpvYklkc1RydW5jYXRlZENvdW50OiBudW1iZXIsIGNoaWxkSW5zdGFuY2VJZDogc3RyaW5nLCBjaGlsZFBpZDogbnVtYmVyLCBjaGlsZFVwdGltZU1zOiBudW1iZXIsIGhlYXBTdGF0aXN0aWNzOiBSZXR1cm5UeXBlPHR5cGVvZiB2OC5nZXRIZWFwU3RhdGlzdGljcz4sIGpvYkNvdW50OiBudW1iZXIsIG1lbW9yeVVzYWdlOiBSZXR1cm5UeXBlPHR5cGVvZiBwcm9jZXNzLm1lbW9yeVVzYWdlPiwgb2JzZXJ2ZWRBdE1zOiBudW1iZXIsIHJzc0J5dGVzOiBudW1iZXIsIHR5cGU6IFwicG9vbGVkLWNoaWxkLW1lbW9yeVwiLCB1cHRpbWVNczogbnVtYmVyfX0gLSBCb3VuZGVkIG1lbW9yeSBvYnNlcnZhdGlvbiBmb3IgdGhpcyBjaGlsZC5cbiAqL1xuZnVuY3Rpb24gY29sbGVjdE1lbW9yeU9ic2VydmF0aW9uKCkge1xuICBjb25zdCBqb2JJZHMgPSBbLi4ucnVubmluZ0pvYklkc11cbiAgY29uc3QgYWN0aXZlSm9iSWRzID0gam9iSWRzLnNsaWNlKDAsIE1FTU9SWV9PQlNFUlZBVElPTl9KT0JfSURfTElNSVQpXG4gIGNvbnN0IG1lbW9yeVVzYWdlID0gcHJvY2Vzcy5tZW1vcnlVc2FnZSgpXG5cbiAgcmV0dXJuIHtcbiAgICBhY3RpdmVKb2JJZHMsXG4gICAgYWN0aXZlSm9iSWRzVHJ1bmNhdGVkQ291bnQ6IE1hdGgubWF4KDAsIGpvYklkcy5sZW5ndGggLSBhY3RpdmVKb2JJZHMubGVuZ3RoKSxcbiAgICBjaGlsZEluc3RhbmNlSWQsXG4gICAgY2hpbGRQaWQ6IHByb2Nlc3MucGlkLFxuICAgIGNoaWxkVXB0aW1lTXM6IE1hdGguZmxvb3IocHJvY2Vzcy51cHRpbWUoKSAqIDEwMDApLFxuICAgIGhlYXBTdGF0aXN0aWNzOiB2OC5nZXRIZWFwU3RhdGlzdGljcygpLFxuICAgIGpvYkNvdW50OiBqb2JJZHMubGVuZ3RoLFxuICAgIG1lbW9yeVVzYWdlLFxuICAgIG9ic2VydmVkQXRNczogRGF0ZS5ub3coKSxcbiAgICByc3NCeXRlczogbWVtb3J5VXNhZ2UucnNzLFxuICAgIHR5cGU6IFwicG9vbGVkLWNoaWxkLW1lbW9yeVwiLFxuICAgIHVwdGltZU1zOiBNYXRoLmZsb29yKHByb2Nlc3MudXB0aW1lKCkgKiAxMDAwKVxuICB9XG59XG5cbi8qKlxuICogU2VuZHMgYSBtZW1vcnkgb2JzZXJ2YXRpb24gdG8gdGhlIHdvcmtlci4gU2FtcGxpbmcgaXMgY2hlYXAgKHByb2Nlc3MgKyBWOFxuICogaGVhcCBzdGF0cykgYW5kIG9ubHkgcnVucyB3aGlsZSBqb2JzIGFyZSBpbiBmbGlnaHQ7IGEgY2xvc2VkIElQQyBjaGFubmVsIGlzXG4gKiB0ZXJtaW5hbCBmb3IgdGhpcyBjaGlsZCAodGhlIGRpc2Nvbm5lY3QgaGFuZGxlciBvd25zIHNodXRkb3duKSwgc28gYSBmYWlsZWRcbiAqIHNlbmQgaXMgc3dhbGxvd2VkLlxuICogQHJldHVybnMge3ZvaWR9XG4gKi9cbmZ1bmN0aW9uIHNlbmRNZW1vcnlPYnNlcnZhdGlvbigpIHtcbiAgaWYgKCFwcm9jZXNzLnNlbmQgfHwgcnVubmluZ0pvYklkcy5zaXplID09PSAwKSByZXR1cm5cblxuICB0cnkge1xuICAgIHByb2Nlc3Muc2VuZChjb2xsZWN0TWVtb3J5T2JzZXJ2YXRpb24oKSlcbiAgfSBjYXRjaCB7XG4gICAgLy8gVGhlIElQQyBjaGFubmVsIGlzIGFscmVhZHkgZ29uZTsgdGhlIGRpc2Nvbm5lY3QgaGFuZGxlciBvd25zIHNodXRkb3duLlxuICB9XG59XG5cbi8qKiBAdHlwZSB7UmV0dXJuVHlwZTx0eXBlb2Ygc2V0SW50ZXJ2YWw+IHwgdW5kZWZpbmVkfSAqL1xubGV0IG1lbW9yeU9ic2VydmF0aW9uVGltZXJcblxuLyoqXG4gKiBDaGVja3Mgd2hldGhlciBhbiBJUEMgdmFsdWUgcmVxdWVzdHMgdGhpcyBjaGlsZCB0byBzZW5kIGEgbWVtb3J5IG9ic2VydmF0aW9uLlxuICogQHBhcmFtIHtSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPn0gbWVzc2FnZSAtIElQQyBtZXNzYWdlLlxuICogQHJldHVybnMge21lc3NhZ2UgaXMge3R5cGU6IFwibWVtb3J5LW9ic2VydmF0aW9uLXJlcXVlc3RcIn19IC0gV2hldGhlciB0aGUgbWVzc2FnZSByZXF1ZXN0cyBvbmUuXG4gKi9cbmZ1bmN0aW9uIGlzTWVtb3J5T2JzZXJ2YXRpb25SZXF1ZXN0TWVzc2FnZShtZXNzYWdlKSB7XG4gIHJldHVybiBtZXNzYWdlICE9PSBudWxsXG4gICAgJiYgdHlwZW9mIG1lc3NhZ2UgPT09IFwib2JqZWN0XCJcbiAgICAmJiBtZXNzYWdlLnR5cGUgPT09IFwibWVtb3J5LW9ic2VydmF0aW9uLXJlcXVlc3RcIlxufVxuXG4vKipcbiAqIFN0YXJ0cyB0aGUgcGVyaW9kaWMgbWVtb3J5IG9ic2VydmF0aW9uIHNhbXBsZXIgaWYgaXQgaXMgbm90IGFscmVhZHkgcnVubmluZy5cbiAqIEByZXR1cm5zIHt2b2lkfVxuICovXG5mdW5jdGlvbiBzdGFydE1lbW9yeU9ic2VydmF0aW9uU2FtcGxpbmcoKSB7XG4gIGlmIChtZW1vcnlPYnNlcnZhdGlvblRpbWVyIHx8ICFwcm9jZXNzLnNlbmQpIHJldHVyblxuXG4gIG1lbW9yeU9ic2VydmF0aW9uVGltZXIgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgc2VuZE1lbW9yeU9ic2VydmF0aW9uKClcbiAgfSwgTUVNT1JZX09CU0VSVkFUSU9OX0lOVEVSVkFMX01TKVxuICBtZW1vcnlPYnNlcnZhdGlvblRpbWVyLnVucmVmKClcbn1cblxuLyoqXG4gKiBTdG9wcyB0aGUgcGVyaW9kaWMgbWVtb3J5IG9ic2VydmF0aW9uIHNhbXBsZXIuXG4gKiBAcmV0dXJucyB7dm9pZH1cbiAqL1xuZnVuY3Rpb24gc3RvcE1lbW9yeU9ic2VydmF0aW9uU2FtcGxpbmcoKSB7XG4gIGlmICghbWVtb3J5T2JzZXJ2YXRpb25UaW1lcikgcmV0dXJuXG5cbiAgY2xlYXJJbnRlcnZhbChtZW1vcnlPYnNlcnZhdGlvblRpbWVyKVxuICBtZW1vcnlPYnNlcnZhdGlvblRpbWVyID0gdW5kZWZpbmVkXG59XG5cbi8qKlxuICogQ2hlY2tzIHdoZXRoZXIgYW4gSVBDIHZhbHVlIGlzIGEgcnVubmFibGUgcG9vbGVkIGpvYiBtZXNzYWdlLlxuICogQHBhcmFtIHtSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPn0gbWVzc2FnZSAtIElQQyBtZXNzYWdlLlxuICogQHJldHVybnMge21lc3NhZ2UgaXMge3R5cGU6IFwiam9iXCIsIHBheWxvYWQ6IGltcG9ydChcIi4vdHlwZXMuanNcIikuQmFja2dyb3VuZEpvYlBheWxvYWQgJiB7aWQ6IHN0cmluZ30sIHNoYXJlZFRyYW5zYWN0aW9uQnJva2VyPzogaW1wb3J0KFwiLi4vdGVzdGluZy9zaGFyZWQtdHJhbnNhY3Rpb24tcHJveHktZHJpdmVyLmpzXCIpLlNoYXJlZFRyYW5zYWN0aW9uQnJva2VySm9iQ29uZmlnfX0gLSBXaGV0aGVyIHRoaXMgaXMgYSB2YWxpZCBqb2IgbWVzc2FnZS5cbiAqL1xuZnVuY3Rpb24gaXNKb2JNZXNzYWdlKG1lc3NhZ2UpIHtcbiAgaWYgKCFtZXNzYWdlIHx8IHR5cGVvZiBtZXNzYWdlICE9PSBcIm9iamVjdFwiKSByZXR1cm4gZmFsc2VcbiAgY29uc3QgcmVjb3JkID0gLyoqIEB0eXBlIHt7dHlwZT86IFJldHVyblR5cGU8dHlwZW9mIEpTT04ucGFyc2U+LCBwYXlsb2FkPzogUmV0dXJuVHlwZTx0eXBlb2YgSlNPTi5wYXJzZT4sIHNoYXJlZFRyYW5zYWN0aW9uQnJva2VyPzogUmV0dXJuVHlwZTx0eXBlb2YgSlNPTi5wYXJzZT59fSAqLyAobWVzc2FnZSlcblxuICByZXR1cm4gcmVjb3JkLnR5cGUgPT09IFwiam9iXCIgJiYgISFyZWNvcmQucGF5bG9hZCAmJiB0eXBlb2YgcmVjb3JkLnBheWxvYWQgPT09IFwib2JqZWN0XCIgJiYgdHlwZW9mIHJlY29yZC5wYXlsb2FkLmlkID09PSBcInN0cmluZ1wiXG59XG5cbi8qKlxuICogQ2hlY2tzIHdoZXRoZXIgYW4gSVBDIHZhbHVlIHJlcXVlc3RzIGEgdHlwZWQgcG9vbGVkLWNoaWxkIHNodXRkb3duLlxuICogQHBhcmFtIHtSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPn0gbWVzc2FnZSAtIElQQyBtZXNzYWdlLlxuICogQHJldHVybnMge21lc3NhZ2UgaXMge3R5cGU6IFwic2h1dGRvd24tcmVxdWVzdFwiLCByZWFzb246IGltcG9ydChcIi4vdHlwZXMuanNcIikuUG9vbGVkQ2hpbGRTaHV0ZG93blJlYXNvbiwgc2h1dGRvd25SZXF1ZXN0ZWRBdE1zOiBudW1iZXIsIHNpZ25hbDogaW1wb3J0KFwibm9kZTpjaGlsZF9wcm9jZXNzXCIpLkNoaWxkUHJvY2Vzc1tcInNpZ25hbENvZGVcIl19fSAtIFdoZXRoZXIgdGhpcyBpcyBhIHZhbGlkIHBhcmVudCBzaHV0ZG93biByZXF1ZXN0LlxuICovXG5mdW5jdGlvbiBpc1NodXRkb3duUmVxdWVzdE1lc3NhZ2UobWVzc2FnZSkge1xuICBpZiAoIW1lc3NhZ2UgfHwgdHlwZW9mIG1lc3NhZ2UgIT09IFwib2JqZWN0XCIpIHJldHVybiBmYWxzZVxuICBjb25zdCByZWNvcmQgPSAvKiogQHR5cGUge3t0eXBlPzogUmV0dXJuVHlwZTx0eXBlb2YgSlNPTi5wYXJzZT4sIHJlYXNvbj86IFJldHVyblR5cGU8dHlwZW9mIEpTT04ucGFyc2U+LCBzaHV0ZG93blJlcXVlc3RlZEF0TXM/OiBSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPiwgc2lnbmFsPzogUmV0dXJuVHlwZTx0eXBlb2YgSlNPTi5wYXJzZT59fSAqLyAobWVzc2FnZSlcblxuICByZXR1cm4gcmVjb3JkLnR5cGUgPT09IFwic2h1dGRvd24tcmVxdWVzdFwiXG4gICAgJiYgaXNQb29sZWRDaGlsZFNodXRkb3duUmVhc29uKHJlY29yZC5yZWFzb24pXG4gICAgJiYgdHlwZW9mIHJlY29yZC5zaHV0ZG93blJlcXVlc3RlZEF0TXMgPT09IFwibnVtYmVyXCJcbiAgICAmJiBOdW1iZXIuaXNGaW5pdGUocmVjb3JkLnNodXRkb3duUmVxdWVzdGVkQXRNcylcbiAgICAmJiBpc1Bvb2xlZENoaWxkU2h1dGRvd25TaWduYWwocmVjb3JkLnNpZ25hbClcbn1cblxuLyoqXG4gKiBTZW5kcyB0aGUgdGVybWluYWwgb3V0Y29tZSBhZnRlciB0aGUgbWFpbi9EQiByZXBvcnQgaGFzIGJlZW4gYWNrbm93bGVkZ2VkIG9yIHJlamVjdGVkLlxuICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBPdXRjb21lLlxuICogQHBhcmFtIHtzdHJpbmd9IGFyZ3Muam9iSWQgLSBKb2IgaWQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFyZ3MuYWNrbm93bGVkZ2VkIC0gV2hldGhlciB0aGUgdGVybWluYWwgcmVwb3J0IHdhcyBhY2tub3dsZWRnZWQuXG4gKiBAcGFyYW0ge1wiY29tcGxldGVkXCIgfCBcImZhaWxlZFwiIHwgXCJyZXNjaGVkdWxlZFwifSBbYXJncy5zdGF0dXNdIC0gQWNrbm93bGVkZ2VkIG91dGNvbWUuXG4gKiBAcGFyYW0ge0Vycm9yfSBbYXJncy5lcnJvcl0gLSBSZXBvcnRpbmcgZXJyb3Igd2hlbiBhY2tub3dsZWRnZW1lbnQgd2FzIG5vdCBvYnRhaW5lZC5cbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIGFmdGVyIElQQyBhY2NlcHRzIHRoZSBtZXNzYWdlLlxuICovXG5mdW5jdGlvbiBzZW5kT3V0Y29tZSh7am9iSWQsIGFja25vd2xlZGdlZCwgc3RhdHVzLCBlcnJvcn0pIHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgaWYgKCFwcm9jZXNzLnNlbmQpIHtcbiAgICAgIHJlc29sdmUodW5kZWZpbmVkKVxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgcHJvY2Vzcy5zZW5kKHtcbiAgICAgIHR5cGU6IFwiam9iLW91dGNvbWVcIixcbiAgICAgIGpvYklkLFxuICAgICAgYWNrbm93bGVkZ2VkLFxuICAgICAgc3RhdHVzLFxuICAgICAgcnNzQnl0ZXM6IHByb2Nlc3MubWVtb3J5VXNhZ2UoKS5yc3MsXG4gICAgICBlcnJvcjogZXJyb3I/Lm1lc3NhZ2VcbiAgICB9LCAoKSA9PiByZXNvbHZlKHVuZGVmaW5lZCkpXG4gIH0pXG59XG5cbi8qKlxuICogUnVucyBvbmUgam9iIGNvbmN1cnJlbnRseSB3aXRoIGFueSBzaWJsaW5ncyBhbmQgcmVwb3J0cyBpdHMgb3duIHRlcm1pbmFsXG4gKiBvdXRjb21lLiBBIHNpbmdsZSBqb2IncyB1bmV4cGVjdGVkIGZhaWx1cmUgcmVwb3J0cyB0aGF0IGpvYiBmb3IgcmVjbGFtYXRpb25cbiAqIChgYWNrbm93bGVkZ2VkOiBmYWxzZWApIGJ1dCBkb2VzIE5PVCB0YWtlIGRvd24gdGhlIGNoaWxkIOKAlCBpdHMgY29uY3VycmVudFxuICogc2libGluZ3Mga2VlcCBydW5uaW5nLiBPbmx5IGEgcHJvY2Vzcy1sZXZlbCBmYXVsdCAod2hpY2ggZXNjYXBlcyBldmVyeVxuICogcGVyLWpvYiB0cnkvY2F0Y2gpIGVuZHMgdGhlIGNoaWxkLCB3aGljaCB0aGUgd29ya2VyIHNlZXMgYXMgYW4gZXhpdCBhbmRcbiAqIHJlY2xhaW1zIGZvciB0aGUgd2hvbGUgaW4tZmxpZ2h0IHNldC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi90eXBlcy5qc1wiKS5CYWNrZ3JvdW5kSm9iUGF5bG9hZCAmIHtpZDogc3RyaW5nfX0gcGF5bG9hZCAtIEpvYiBwYXlsb2FkLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi90ZXN0aW5nL3NoYXJlZC10cmFuc2FjdGlvbi1wcm94eS1kcml2ZXIuanNcIikuU2hhcmVkVHJhbnNhY3Rpb25Ccm9rZXJKb2JDb25maWd9IHNoYXJlZFRyYW5zYWN0aW9uQnJva2VyIC0gUGVyLWpvYiBicm9rZXIgY29uZmlndXJhdGlvbi5cbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIGFmdGVyIHJlcG9ydGluZy5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcnVuSm9iKHBheWxvYWQsIHNoYXJlZFRyYW5zYWN0aW9uQnJva2VyKSB7XG4gIHRyeSB7XG4gICAgY29uc3Qgc3RhdHVzID0gYXdhaXQgcnVuV2l0aFNoYXJlZFRyYW5zYWN0aW9uQnJva2VyQ29uZmlnKHNoYXJlZFRyYW5zYWN0aW9uQnJva2VyLCBhc3luYyAoKSA9PiB7XG4gICAgICByZXR1cm4gYXdhaXQgYnJva2VySWRlbnRpdHkucnVuKHNoYXJlZFRyYW5zYWN0aW9uQnJva2VyLCBhc3luYyAoKSA9PiB7XG4gICAgICAgIHJldHVybiBhd2FpdCBydW5Kb2JQYXlsb2FkKHBheWxvYWQsIHtcbiAgICAgICAgICBjbG9zZUNvbm5lY3Rpb25zOiBmYWxzZSxcbiAgICAgICAgICBtYW5hZ2VQcm9jZXNzVGl0bGU6IGZhbHNlLFxuICAgICAgICAgIG9uUGVyZm9ybVN0YXJ0OiAoKSA9PiBzZW5kQ2hpbGRBY2NlcHRhbmNlKFwiam9iLXN0YXJ0ZWRcIiwgcGF5bG9hZCwgRGF0ZS5ub3coKSksXG4gICAgICAgICAgcHJvY2Vzc1R5cGU6IFwiYmFja2dyb3VuZC1qb2JzLXBvb2xlZC1ydW5uZXJcIlxuICAgICAgICB9KVxuICAgICAgfSlcbiAgICB9KVxuICAgIGF3YWl0IHNlbmRPdXRjb21lKHtqb2JJZDogcGF5bG9hZC5pZCwgYWNrbm93bGVkZ2VkOiB0cnVlLCBzdGF0dXN9KVxuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEJhY2tncm91bmRKb2JQZXJmb3JtZWRGYWlsdXJlKSB7XG4gICAgICBhd2FpdCBzZW5kT3V0Y29tZSh7am9iSWQ6IHBheWxvYWQuaWQsIGFja25vd2xlZGdlZDogdHJ1ZSwgc3RhdHVzOiBcImZhaWxlZFwifSlcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgcmVwb3J0RXJyb3IgPSBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IgOiBuZXcgRXJyb3IoU3RyaW5nKGVycm9yKSlcbiAgICAgIGNvbnNvbGUuZXJyb3IoXCJQb29sZWQgYmFja2dyb3VuZCBqb2IgcnVubmVyIGZhaWxlZCBiZWZvcmUgdGVybWluYWwgYWNrbm93bGVkZ2VtZW50OlwiLCByZXBvcnRFcnJvcilcbiAgICAgIGF3YWl0IHNlbmRPdXRjb21lKHtqb2JJZDogcGF5bG9hZC5pZCwgYWNrbm93bGVkZ2VkOiBmYWxzZSwgZXJyb3I6IHJlcG9ydEVycm9yfSlcbiAgICB9XG4gIH0gZmluYWxseSB7XG4gICAgcnVubmluZ0pvYklkcy5kZWxldGUocGF5bG9hZC5pZClcbiAgICB1cGRhdGVQcm9jZXNzVGl0bGUoKVxuXG4gICAgaWYgKHJ1bm5pbmdKb2JJZHMuc2l6ZSA9PT0gMCkge1xuICAgICAgc3RvcE1lbW9yeU9ic2VydmF0aW9uU2FtcGxpbmcoKVxuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIEhhbmRsZXMgYSBqb2IgbWVzc2FnZSwgc3RhcnRpbmcgaXQgYWxvbmdzaWRlIGFueSBjb25jdXJyZW50IHNpYmxpbmdzLlxuICogQHBhcmFtIHtSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPn0gbWVzc2FnZSAtIElQQyBtZXNzYWdlLlxuICogQHJldHVybnMge3ZvaWR9XG4gKi9cbmZ1bmN0aW9uIGhhbmRsZU1lc3NhZ2UobWVzc2FnZSkge1xuICBpZiAoaXNTaHV0ZG93blJlcXVlc3RNZXNzYWdlKG1lc3NhZ2UpKSB7XG4gICAgdm9pZCBzaHV0ZG93blJ1bm5lcih7XG4gICAgICBleGl0Q29kZTogbWVzc2FnZS5yZWFzb24gPT09IFwicGFyZW50X3JldGlyZV9kcmFpbmVkXCIgPyAwIDogMSxcbiAgICAgIHJlYXNvbjogbWVzc2FnZS5yZWFzb24sXG4gICAgICBzaHV0ZG93blJlcXVlc3RlZEF0TXM6IG1lc3NhZ2Uuc2h1dGRvd25SZXF1ZXN0ZWRBdE1zLFxuICAgICAgc2lnbmFsOiBtZXNzYWdlLnNpZ25hbFxuICAgIH0pXG4gICAgcmV0dXJuXG4gIH1cblxuICBpZiAoaXNNZW1vcnlPYnNlcnZhdGlvblJlcXVlc3RNZXNzYWdlKG1lc3NhZ2UpKSB7XG4gICAgc2VuZE1lbW9yeU9ic2VydmF0aW9uKClcbiAgICByZXR1cm5cbiAgfVxuXG4gIGlmICghaXNKb2JNZXNzYWdlKG1lc3NhZ2UpIHx8IHJ1bm5pbmdKb2JJZHMuaGFzKG1lc3NhZ2UucGF5bG9hZC5pZCkpIHJldHVyblxuXG4gIHJ1bm5pbmdKb2JJZHMuYWRkKG1lc3NhZ2UucGF5bG9hZC5pZClcbiAgdXBkYXRlUHJvY2Vzc1RpdGxlKClcbiAgc2VuZENoaWxkQWNjZXB0YW5jZShcImpvYi1yZWNlaXZlZFwiLCBtZXNzYWdlLnBheWxvYWQsIERhdGUubm93KCkpXG4gIHN0YXJ0TWVtb3J5T2JzZXJ2YXRpb25TYW1wbGluZygpXG4gIHZvaWQgcnVuSm9iKG1lc3NhZ2UucGF5bG9hZCwgbWVzc2FnZS5zaGFyZWRUcmFuc2FjdGlvbkJyb2tlciB8fCB7ZXhwZWN0ZWQ6IGZhbHNlfSlcbn1cblxucHJvY2Vzcy5vbihcIm1lc3NhZ2VcIiwgKG1lc3NhZ2UpID0+IGhhbmRsZU1lc3NhZ2UobWVzc2FnZSkpXG5wcm9jZXNzLm9uY2UoXCJkaXNjb25uZWN0XCIsICgpID0+IHZvaWQgc2h1dGRvd25SdW5uZXIoe2V4aXRDb2RlOiAwLCByZWFzb246IFwiaXBjX2Rpc2Nvbm5lY3RcIn0pKVxucHJvY2Vzcy5vbmNlKFwiU0lHVEVSTVwiLCAoKSA9PiB2b2lkIHNodXRkb3duUnVubmVyKHtleGl0Q29kZTogMSwgcmVhc29uOiBcInNpZ25hbF9zaWd0ZXJtXCIsIHNpZ25hbDogXCJTSUdURVJNXCJ9KSlcbnByb2Nlc3Mub25jZShcIlNJR0lOVFwiLCAoKSA9PiB2b2lkIHNodXRkb3duUnVubmVyKHtleGl0Q29kZTogMSwgcmVhc29uOiBcInNpZ25hbF9zaWdpbnRcIiwgc2lnbmFsOiBcIlNJR0lOVFwifSkpXG5pZiAocHJvY2Vzcy5zZW5kKSBwcm9jZXNzLnNlbmQoe2NoaWxkSW5zdGFuY2VJZCwgY2hpbGRQaWQ6IHByb2Nlc3MucGlkLCB0eXBlOiBcInJlYWR5XCJ9KVxuIl19
|