1 | ;
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.faastLocal = exports.faastGoogle = exports.faastAws = exports.faast = exports.FaastModuleProxy = exports.FunctionStatsEvent = exports.providers = void 0;
|
4 | const events_1 = require("events");
|
5 | const util_1 = require("util");
|
6 | const uuid_1 = require("uuid");
|
7 | const aws_faast_1 = require("./aws/aws-faast");
|
8 | const cost_1 = require("./cost");
|
9 | const error_1 = require("./error");
|
10 | const google_faast_1 = require("./google/google-faast");
|
11 | const local_faast_1 = require("./local/local-faast");
|
12 | const log_1 = require("./log");
|
13 | const metrics_1 = require("./metrics");
|
14 | const provider_1 = require("./provider");
|
15 | const serialize_1 = require("./serialize");
|
16 | const shared_1 = require("./shared");
|
17 | const throttle_1 = require("./throttle");
|
18 | const wrapper_1 = require("./wrapper");
|
19 | const Module = require("module");
|
20 | /**
|
21 | * An array of all available provider.
|
22 | * @public
|
23 | */
|
24 | exports.providers = ["aws", "google", "local"];
|
25 | async function createFaastModuleProxy(impl, fmodule, userOptions) {
|
26 | try {
|
27 | const resolvedModule = resolve(fmodule);
|
28 | const functionId = (0, uuid_1.v4)();
|
29 | const options = { ...impl.defaults, ...userOptions };
|
30 | log_1.log.provider(`options ${(0, log_1.inspectProvider)(options)}`);
|
31 | return new FaastModuleProxy(impl, await impl.initialize(resolvedModule, functionId, options), fmodule, resolvedModule, options);
|
32 | }
|
33 | catch (err) {
|
34 | throw new error_1.FaastError(err, "could not initialize cloud function");
|
35 | }
|
36 | }
|
37 | /**
|
38 | * Summarize statistics about cloud function invocations.
|
39 | * @public
|
40 | */
|
41 | class FunctionStatsEvent {
|
42 | /**
|
43 | * @internal
|
44 | */
|
45 | constructor(
|
46 | /** The name of the cloud function the statistics are about. */
|
47 | fn,
|
48 | /** See {@link FunctionStats}. */
|
49 | stats) {
|
50 | this.fn = fn;
|
51 | this.stats = stats;
|
52 | this.stats = stats.clone();
|
53 | }
|
54 | /**
|
55 | * Returns a string summarizing the statistics event.
|
56 | * @remarks
|
57 | * The string includes number of completed calls, errors, and retries, and
|
58 | * the mean execution time for the calls that completed within the last time
|
59 | * interval (1s).
|
60 | */
|
61 | toString() {
|
62 | const executionTime = this.stats ? this.stats.executionTime.mean : 0;
|
63 | return `[${this.fn}] ${this.stats}, executionTime: ${(executionTime / 1000).toFixed(2)}s`;
|
64 | }
|
65 | }
|
66 | exports.FunctionStatsEvent = FunctionStatsEvent;
|
67 | class PendingRequest {
|
68 | constructor(call) {
|
69 | this.call = call;
|
70 | this.queue = new throttle_1.AsyncOrderedQueue();
|
71 | this.created = Date.now();
|
72 | }
|
73 | }
|
74 | /**
|
75 | * Implementation of {@link FaastModule}.
|
76 | * @remarks
|
77 | * `FaastModuleProxy` provides a unified developer experience for faast.js
|
78 | * modules on top of provider-specific runtime APIs. Most users will not create
|
79 | * `FaastModuleProxy` instances themselves; instead use {@link faast}, or
|
80 | * {@link faastAws}, {@link faastGoogle}, or {@link faastLocal}.
|
81 | * `FaastModuleProxy` implements the {@link FaastModule} interface, which is the
|
82 | * preferred public interface for faast modules. `FaastModuleProxy` can be used
|
83 | * to access provider-specific details and state, and is useful for deeper
|
84 | * testing.
|
85 | * @public
|
86 | */
|
87 | class FaastModuleProxy {
|
88 | /**
|
89 | * Constructor
|
90 | * @internal
|
91 | */
|
92 | constructor(impl,
|
93 | /** @internal */
|
94 | state, fmodule, modulePath,
|
95 | /** The options set for this instance, which includes default values. */
|
96 | options) {
|
97 | this.impl = impl;
|
98 | this.state = state;
|
99 | this.fmodule = fmodule;
|
100 | this.modulePath = modulePath;
|
101 | this.options = options;
|
102 | /** The {@link Provider}, e.g. "aws" or "google". */
|
103 | this.provider = this.impl.name;
|
104 | /** @internal */
|
105 | this._stats = new metrics_1.FunctionStatsMap();
|
106 | this._cpuUsage = new metrics_1.FactoryMap(() => new metrics_1.FactoryMap((_) => new metrics_1.FunctionCpuUsage()));
|
107 | this._skew = new shared_1.ExponentiallyDecayingAverageValue(0.3);
|
108 | this._cleanupHooks = new Set();
|
109 | this._initialInvocationTime = new metrics_1.FactoryMap(() => Date.now());
|
110 | this._callResultsPending = new Map();
|
111 | this._emitter = new events_1.EventEmitter();
|
112 | log_1.log.info(`Node version: ${process.version}`);
|
113 | log_1.log.provider(`name: ${this.impl.name}`);
|
114 | log_1.log.provider(`responseQueueId: ${this.impl.responseQueueId(state)}`);
|
115 | log_1.log.provider(`logUrl: ${this.impl.logUrl(state)}`);
|
116 | log_1.log.info(`Log url: ${impl.logUrl(state)}`);
|
117 | this._funnel = new throttle_1.Funnel(options.concurrency);
|
118 | if (options.rate) {
|
119 | this._rateLimiter = new throttle_1.RateLimiter(options.rate, 1);
|
120 | }
|
121 | this._memoryLeakDetector = new metrics_1.MemoryLeakDetector(options.memorySize);
|
122 | const functionsDetail = {};
|
123 | const functions = {};
|
124 | for (const name of Object.keys(fmodule)) {
|
125 | const origFunction = fmodule[name];
|
126 | if (typeof origFunction === "function") {
|
127 | if ((0, wrapper_1.isGenerator)(origFunction)) {
|
128 | const func = this.wrapGenerator(origFunction);
|
129 | functionsDetail[name] = func;
|
130 | functions[name] = async function* (...args) {
|
131 | const generator = func(...args);
|
132 | for await (const iter of generator) {
|
133 | yield iter.value;
|
134 | }
|
135 | };
|
136 | }
|
137 | else {
|
138 | const func = this.wrapFunction(origFunction);
|
139 | functionsDetail[name] = func;
|
140 | functions[name] = (...args) => func(...args).then(p => p.value);
|
141 | }
|
142 | }
|
143 | }
|
144 | this.functions = functions;
|
145 | this.functionsDetail = functionsDetail;
|
146 | this._collectorPump = new throttle_1.Pump({ concurrency: 2 }, () => this.resultCollector());
|
147 | this._collectorPump.start();
|
148 | }
|
149 | /** {@inheritdoc FaastModule.cleanup} */
|
150 | async cleanup(userCleanupOptions = {}) {
|
151 | try {
|
152 | this._stats.clear();
|
153 | this._memoryLeakDetector.clear();
|
154 | this._funnel.clear();
|
155 | this._rateLimiter?.clear();
|
156 | this._cleanupHooks.forEach(hook => hook.resolve());
|
157 | this._cleanupHooks.clear();
|
158 | this._emitter.removeAllListeners();
|
159 | this.stopStats();
|
160 | this._initialInvocationTime.clear();
|
161 | this._callResultsPending.clear();
|
162 | this._collectorPump.stop();
|
163 | log_1.log.provider(`cleanup`);
|
164 | const options = { ...provider_1.CleanupOptionDefaults, ...userCleanupOptions };
|
165 | const { gcTimeout } = options;
|
166 | let timedout = false;
|
167 | if (gcTimeout > 0) {
|
168 | const timeout = (0, shared_1.sleep)(gcTimeout * 1000).then(() => (timedout = true));
|
169 | await Promise.race([this.impl.cleanup(this.state, options), timeout]);
|
170 | }
|
171 | else {
|
172 | await this.impl.cleanup(this.state, options);
|
173 | }
|
174 | if (timedout) {
|
175 | log_1.log.provider(`cleanup timed out after ${gcTimeout}s`);
|
176 | }
|
177 | else {
|
178 | log_1.log.provider(`cleanup done`);
|
179 | }
|
180 | }
|
181 | catch (err) {
|
182 | throw new error_1.FaastError(err, "failed in cleanup");
|
183 | }
|
184 | }
|
185 | /** {@inheritdoc FaastModule.logUrl} */
|
186 | logUrl() {
|
187 | const rv = this.impl.logUrl(this.state);
|
188 | log_1.log.provider(`logUrl ${rv}`);
|
189 | return rv;
|
190 | }
|
191 | startStats(interval = 1000) {
|
192 | this._statsTimer = setInterval(() => {
|
193 | this._stats.fIncremental.forEach((stats, fn) => {
|
194 | this._emitter.emit("stats", new FunctionStatsEvent(fn, stats));
|
195 | });
|
196 | this._stats.resetIncremental();
|
197 | }, interval);
|
198 | }
|
199 | stopStats() {
|
200 | this._statsTimer && clearInterval(this._statsTimer);
|
201 | this._statsTimer = undefined;
|
202 | }
|
203 | /** {@inheritdoc FaastModule.on} */
|
204 | on(name, listener) {
|
205 | if (!this._statsTimer) {
|
206 | this.startStats();
|
207 | }
|
208 | this._emitter.on(name, listener);
|
209 | }
|
210 | /** {@inheritdoc FaastModule.off} */
|
211 | off(name, listener) {
|
212 | this._emitter.off(name, listener);
|
213 | if (this._emitter.listenerCount(name) === 0) {
|
214 | this.stopStats();
|
215 | }
|
216 | }
|
217 | async withCancellation(fn) {
|
218 | const deferred = new throttle_1.Deferred();
|
219 | this._cleanupHooks.add(deferred);
|
220 | const promise = fn(deferred.promise);
|
221 | try {
|
222 | return await promise;
|
223 | }
|
224 | finally {
|
225 | this._cleanupHooks.delete(deferred);
|
226 | }
|
227 | }
|
228 | processResponse(returned, functionName, localStartTime) {
|
229 | const { response } = returned;
|
230 | const { logUrl, instanceId, memoryUsage } = response;
|
231 | let value;
|
232 | if (response.type === "reject") {
|
233 | const error = response.isErrorObject
|
234 | ? (0, error_1.synthesizeFaastError)({
|
235 | errObj: returned.value,
|
236 | logUrl: ` ${logUrl} `,
|
237 | functionName
|
238 | })
|
239 | : returned.value;
|
240 | value = Promise.reject(error);
|
241 | value.catch((_silenceWarningLackOfSynchronousCatch) => { });
|
242 | }
|
243 | else {
|
244 | const { executionId } = returned.response;
|
245 | const detail = {
|
246 | value: returned.value[0],
|
247 | logUrl,
|
248 | executionId,
|
249 | instanceId,
|
250 | memoryUsage
|
251 | };
|
252 | value = Promise.resolve(detail);
|
253 | }
|
254 | const { localRequestSentTime, remoteResponseSentTime, localEndTime } = returned;
|
255 | const { remoteExecutionStartTime, remoteExecutionEndTime } = response;
|
256 | const fstats = this._stats;
|
257 | if (remoteExecutionStartTime && remoteExecutionEndTime) {
|
258 | const localStartLatency = localRequestSentTime - localStartTime;
|
259 | const roundTripLatency = localEndTime - localRequestSentTime;
|
260 | const executionTime = remoteExecutionEndTime - remoteExecutionStartTime;
|
261 | const sendResponseLatency = Math.max(0, (remoteResponseSentTime || remoteExecutionEndTime) -
|
262 | remoteExecutionEndTime);
|
263 | const networkLatency = roundTripLatency - executionTime - sendResponseLatency;
|
264 | const estimatedRemoteStartTime = localRequestSentTime + networkLatency / 2;
|
265 | const estimatedSkew = estimatedRemoteStartTime - remoteExecutionStartTime;
|
266 | let skew = estimatedSkew;
|
267 | if (fstats.aggregate.completed > 1) {
|
268 | this._skew.update(skew);
|
269 | skew = this._skew.value;
|
270 | }
|
271 | const remoteStartLatency = Math.max(1, remoteExecutionStartTime + skew - localRequestSentTime);
|
272 | const returnLatency = Math.max(1, localEndTime - (remoteExecutionEndTime + skew));
|
273 | fstats.update(functionName, "localStartLatency", localStartLatency);
|
274 | fstats.update(functionName, "remoteStartLatency", remoteStartLatency);
|
275 | fstats.update(functionName, "executionTime", executionTime);
|
276 | fstats.update(functionName, "sendResponseLatency", sendResponseLatency);
|
277 | fstats.update(functionName, "returnLatency", returnLatency);
|
278 | const billed = (executionTime || 0) + (sendResponseLatency || 0);
|
279 | const estimatedBilledTime = Math.max(100, Math.ceil(billed / 100) * 100);
|
280 | fstats.update(functionName, "estimatedBilledTime", estimatedBilledTime);
|
281 | }
|
282 | if (response.type === "reject") {
|
283 | fstats.incr(functionName, "errors");
|
284 | }
|
285 | else {
|
286 | fstats.incr(functionName, "completed");
|
287 | }
|
288 | if (instanceId && memoryUsage) {
|
289 | if (this._memoryLeakDetector.detectedNewLeak(functionName, instanceId, memoryUsage)) {
|
290 | log_1.log.leaks(`Possible memory leak detected in function '${functionName}'.`);
|
291 | log_1.log.leaks(`Memory use before execution leaked from prior calls: %O`, memoryUsage);
|
292 | log_1.log.leaks(`Logs: ${logUrl} `);
|
293 | log_1.log.leaks(`These logs show only one example faast cloud function invocation that may have a leak.`);
|
294 | }
|
295 | }
|
296 | return value;
|
297 | }
|
298 | invoke(fname, args, callId) {
|
299 | const ResponseQueueId = this.impl.responseQueueId(this.state);
|
300 | const callObject = {
|
301 | name: fname,
|
302 | args: (0, serialize_1.serializeFunctionArgs)(fname, args, this.options.validateSerialization),
|
303 | callId,
|
304 | modulePath: this.modulePath,
|
305 | ResponseQueueId
|
306 | };
|
307 | log_1.log.calls(`Calling '${fname}' (${callId})`);
|
308 | const pending = new PendingRequest(callObject);
|
309 | this._callResultsPending.set(callId, pending);
|
310 | if (this._collectorPump.stopped) {
|
311 | this._collectorPump.start();
|
312 | }
|
313 | this.withCancellation(async (cancel) => {
|
314 | await this.impl.invoke(this.state, pending.call, cancel).catch(err => pending.queue.pushImmediate({
|
315 | response: {
|
316 | kind: "promise",
|
317 | type: "reject",
|
318 | callId,
|
319 | isErrorObject: typeof err === "object" && err instanceof Error,
|
320 | value: (0, serialize_1.serialize)(err)
|
321 | },
|
322 | value: err,
|
323 | localEndTime: Date.now(),
|
324 | localRequestSentTime: pending.created
|
325 | }));
|
326 | });
|
327 | return pending;
|
328 | }
|
329 | lookupFname(fn) {
|
330 | let fname = fn.name;
|
331 | if (!fname) {
|
332 | for (const key of Object.keys(this.fmodule)) {
|
333 | if (this.fmodule[key] === fn) {
|
334 | fname = key;
|
335 | log_1.log.info(`Found arrow function name: ${key}`);
|
336 | break;
|
337 | }
|
338 | }
|
339 | }
|
340 | if (!fname) {
|
341 | throw new error_1.FaastError(`Could not find function name`);
|
342 | }
|
343 | return fname;
|
344 | }
|
345 | createCallId() {
|
346 | return (0, uuid_1.v4)();
|
347 | }
|
348 | wrapGenerator(fn) {
|
349 | return (...args) => {
|
350 | const startTime = Date.now();
|
351 | let fname = this.lookupFname(fn);
|
352 | const callId = this.createCallId();
|
353 | const pending = this.invoke(fname, args, callId);
|
354 | log_1.log.provider(`invoke ${(0, log_1.inspectProvider)(pending.call)}`);
|
355 | this._stats.incr(fname, "invocations");
|
356 | return {
|
357 | [Symbol.asyncIterator]() {
|
358 | return this;
|
359 | },
|
360 | next: () => pending.queue.next().then(async (next) => {
|
361 | const promise = this.processResponse(next, fname, startTime);
|
362 | const result = await promise;
|
363 | log_1.log.calls(`yielded ${(0, util_1.inspect)(result)}`);
|
364 | const { value, ...rest } = result;
|
365 | if (result.value.done) {
|
366 | this.clearPending(callId);
|
367 | return { done: true, value: rest };
|
368 | }
|
369 | else {
|
370 | return {
|
371 | done: false,
|
372 | value: { ...rest, value: value.value }
|
373 | };
|
374 | }
|
375 | })
|
376 | };
|
377 | };
|
378 | }
|
379 | clearPending(callId) {
|
380 | this._callResultsPending.delete(callId);
|
381 | if (this._callResultsPending.size === 0) {
|
382 | this._collectorPump.stop();
|
383 | }
|
384 | }
|
385 | wrapFunction(fn) {
|
386 | return (...args) => {
|
387 | const startTime = Date.now();
|
388 | let fname = this.lookupFname(fn);
|
389 | const callId = this.createCallId();
|
390 | const tryInvoke = async () => {
|
391 | const pending = this.invoke(fname, args, callId);
|
392 | log_1.log.provider(`invoke ${(0, log_1.inspectProvider)(pending.call)}`);
|
393 | this._stats.incr(fname, "invocations");
|
394 | const responsePromise = pending.queue.next();
|
395 | const rv = await responsePromise;
|
396 | this.clearPending(callId);
|
397 | log_1.log.calls(`Returning '${fname}' (${callId}): ${(0, util_1.inspect)(rv)}`);
|
398 | return this.processResponse(rv, fname, startTime);
|
399 | };
|
400 | const funnel = this._funnel;
|
401 | let retries = 0;
|
402 | const shouldRetry = (err) => {
|
403 | if (err instanceof error_1.FaastError) {
|
404 | if (error_1.FaastError.hasCauseWithName(err, error_1.FaastErrorNames.ESERIALIZE)) {
|
405 | return false;
|
406 | }
|
407 | // Don't retry user-generated errors. Only errors caused by
|
408 | // failures of operations faast itself initiated (e.g. cloud
|
409 | // service APIs) are retried.
|
410 | if (error_1.FaastError.hasCauseWithName(err, error_1.FaastErrorNames.EEXCEPTION)) {
|
411 | return false;
|
412 | }
|
413 | }
|
414 | if (retries < this.options.maxRetries) {
|
415 | retries++;
|
416 | this._stats.incr(fname, "retries");
|
417 | log_1.log.info(`faast: func: ${fname} attempts: ${retries}, err: ${(0, log_1.inspectProvider)(err)}`);
|
418 | return true;
|
419 | }
|
420 | return false;
|
421 | };
|
422 | if (this._rateLimiter) {
|
423 | return funnel.push(() => this._rateLimiter.push(tryInvoke), shouldRetry);
|
424 | }
|
425 | else {
|
426 | return funnel.push(tryInvoke, shouldRetry);
|
427 | }
|
428 | };
|
429 | }
|
430 | /** {@inheritdoc FaastModule.costSnapshot} */
|
431 | async costSnapshot() {
|
432 | const estimate = await this.impl.costSnapshot(this.state, this._stats.aggregate);
|
433 | log_1.log.provider(`costSnapshot returned ${(0, log_1.inspectProvider)(estimate)}`);
|
434 | if (this._stats.aggregate.retries > 0) {
|
435 | const { retries, invocations } = this._stats.aggregate;
|
436 | const retryPct = ((retries / invocations) * 100).toFixed(1);
|
437 | estimate.push(new cost_1.CostMetric({
|
438 | name: "retries",
|
439 | pricing: 0,
|
440 | measured: retries,
|
441 | unit: "retry",
|
442 | unitPlural: "retries",
|
443 | comment: `Retries were ${retryPct}% of requests and may have incurred charges not accounted for by faast.`,
|
444 | informationalOnly: true
|
445 | }));
|
446 | }
|
447 | return estimate;
|
448 | }
|
449 | /** {@inheritdoc FaastModule.stats} */
|
450 | stats(functionName) {
|
451 | if (functionName) {
|
452 | return this._stats.fAggregate.getOrCreate(functionName).clone();
|
453 | }
|
454 | return this._stats.aggregate.clone();
|
455 | }
|
456 | async resultCollector() {
|
457 | const { _callResultsPending: callResultsPending } = this;
|
458 | if (!callResultsPending.size) {
|
459 | return;
|
460 | }
|
461 | log_1.log.provider(`polling ${this.impl.responseQueueId(this.state)}`);
|
462 | const pollResult = await this.withCancellation(cancel => this.impl.poll(this.state, cancel));
|
463 | log_1.log.provider(`poll returned ${(0, log_1.inspectProvider)(pollResult)}`);
|
464 | const { Messages, isFullMessageBatch } = pollResult;
|
465 | const localEndTime = Date.now();
|
466 | this.adjustCollectorConcurrencyLevel(isFullMessageBatch);
|
467 | for (const m of Messages) {
|
468 | switch (m.kind) {
|
469 | case "functionstarted": {
|
470 | const pending = callResultsPending.get(m.callId);
|
471 | if (pending) {
|
472 | pending.executing = true;
|
473 | }
|
474 | break;
|
475 | }
|
476 | case "promise":
|
477 | case "iterator":
|
478 | try {
|
479 | const { timestamp } = m;
|
480 | const value = (0, serialize_1.deserialize)(m.value);
|
481 | const pending = callResultsPending.get(m.callId);
|
482 | if (pending) {
|
483 | const rv = {
|
484 | response: m,
|
485 | value,
|
486 | remoteResponseSentTime: timestamp,
|
487 | localRequestSentTime: pending.created,
|
488 | localEndTime
|
489 | };
|
490 | log_1.log.provider(`returned ${(0, log_1.inspectProvider)(value)}`);
|
491 | if (m.kind === "iterator") {
|
492 | pending.queue.push(rv, m.sequence);
|
493 | }
|
494 | else {
|
495 | pending.queue.pushImmediate(rv);
|
496 | }
|
497 | }
|
498 | else {
|
499 | log_1.log.info(`Pending promise not found for CallId: ${m.callId}`);
|
500 | }
|
501 | }
|
502 | catch (err) {
|
503 | log_1.log.warn(err);
|
504 | }
|
505 | break;
|
506 | case "cpumetrics":
|
507 | const { metrics } = m;
|
508 | const pending = callResultsPending.get(m.callId);
|
509 | if (!pending) {
|
510 | return;
|
511 | }
|
512 | const stats = this._cpuUsage.getOrCreate(pending.call.name);
|
513 | const secondMetrics = stats.getOrCreate(Math.round(metrics.elapsed / 1000));
|
514 | secondMetrics.stime.update(metrics.stime);
|
515 | secondMetrics.utime.update(metrics.utime);
|
516 | secondMetrics.cpuTime.update(metrics.stime + metrics.utime);
|
517 | break;
|
518 | }
|
519 | }
|
520 | }
|
521 | adjustCollectorConcurrencyLevel(full) {
|
522 | const nPending = this._callResultsPending.size;
|
523 | if (nPending > 0) {
|
524 | let nCollectors = full ? Math.floor(nPending / 20) + 2 : 2;
|
525 | nCollectors = Math.min(nCollectors, 10);
|
526 | const pump = this._collectorPump;
|
527 | const previous = pump.concurrency;
|
528 | pump.setMaxConcurrency(nCollectors);
|
529 | if (previous !== pump.concurrency) {
|
530 | log_1.log.info(`Result collectors running: ${pump.getConcurrency()}, new max: ${pump.concurrency}`);
|
531 | }
|
532 | }
|
533 | }
|
534 | }
|
535 | exports.FaastModuleProxy = FaastModuleProxy;
|
536 | function resolve(fmodule) {
|
537 | const cache = Module._cache;
|
538 | let modulePath;
|
539 | for (const key of Object.keys(cache).reverse()) {
|
540 | if (cache[key].exports === fmodule) {
|
541 | modulePath = key;
|
542 | break;
|
543 | }
|
544 | }
|
545 | if (!modulePath) {
|
546 | throw new error_1.FaastError({ info: { module: fmodule } }, `Could not find file for module, must use "import * as X from Y" or "X = require(Y)" to load a module for faast.`);
|
547 | }
|
548 | log_1.log.info(`Found file: ${modulePath}`);
|
549 | return modulePath;
|
550 | }
|
551 | /**
|
552 | * The main entry point for faast with any provider and only common options.
|
553 | * @param provider - One of `"aws"`, `"google"`, or `"local"`. See
|
554 | * {@link Provider}.
|
555 | * @param fmodule - A module imported with `import * as X from "Y";`. Using
|
556 | * `require` also works but loses type information.
|
557 | * @param options - See {@link CommonOptions}.
|
558 | * @returns See {@link FaastModule}.
|
559 | * @remarks
|
560 | * Example of usage:
|
561 | * ```typescript
|
562 | * import { faast } from "faastjs";
|
563 | * import * as mod from "./path/to/module";
|
564 | * (async () => {
|
565 | * const faastModule = await faast("aws", mod);
|
566 | * try {
|
567 | * const result = await faastModule.functions.func("arg");
|
568 | * } finally {
|
569 | * await faastModule.cleanup();
|
570 | * }
|
571 | * })();
|
572 | * ```
|
573 | * @public
|
574 | */
|
575 | async function faast(provider, fmodule, options) {
|
576 | switch (provider) {
|
577 | case "aws":
|
578 | return faastAws(fmodule, options);
|
579 | case "google":
|
580 | return faastGoogle(fmodule, options);
|
581 | case "local":
|
582 | return faastLocal(fmodule, options);
|
583 | default:
|
584 | throw new error_1.FaastError(`Unknown cloud provider option '${provider}'`);
|
585 | }
|
586 | }
|
587 | exports.faast = faast;
|
588 | /**
|
589 | * The main entry point for faast with AWS provider.
|
590 | * @param fmodule - A module imported with `import * as X from "Y";`. Using
|
591 | * `require` also works but loses type information.
|
592 | * @param options - Most common options are in {@link CommonOptions}.
|
593 | * Additional AWS-specific options are in {@link AwsOptions}.
|
594 | * @public
|
595 | */
|
596 | function faastAws(fmodule, options) {
|
597 | return createFaastModuleProxy(aws_faast_1.AwsImpl, fmodule, options);
|
598 | }
|
599 | exports.faastAws = faastAws;
|
600 | /**
|
601 | * The main entry point for faast with Google provider.
|
602 | * @param fmodule - A module imported with `import * as X from "Y";`. Using
|
603 | * `require` also works but loses type information.
|
604 | * @param options - Most common options are in {@link CommonOptions}.
|
605 | * Additional Google-specific options are in {@link GoogleOptions}.
|
606 | * @public
|
607 | */
|
608 | function faastGoogle(fmodule, options) {
|
609 | return createFaastModuleProxy(google_faast_1.GoogleImpl, fmodule, options);
|
610 | }
|
611 | exports.faastGoogle = faastGoogle;
|
612 | /**
|
613 | * The main entry point for faast with Local provider.
|
614 | * @param fmodule - A module imported with `import * as X from "Y";`. Using
|
615 | * `require` also works but loses type information.
|
616 | * @param options - Most common options are in {@link CommonOptions}.
|
617 | * Additional Local-specific options are in {@link LocalOptions}.
|
618 | * @returns a Promise for {@link LocalFaastModule}.
|
619 | * @public
|
620 | */
|
621 | function faastLocal(fmodule, options) {
|
622 | return createFaastModuleProxy(local_faast_1.LocalImpl, fmodule, options);
|
623 | }
|
624 | exports.faastLocal = faastLocal;
|
625 | function estimateFunctionLatency(fnStats) {
|
626 | const { executionTime, localStartLatency, remoteStartLatency, returnLatency } = fnStats;
|
627 | return (localStartLatency.mean +
|
628 | remoteStartLatency.mean +
|
629 | executionTime.mean +
|
630 | returnLatency.mean || 0);
|
631 | }
|
632 | function estimateTailLatency(fnStats, nStdDev) {
|
633 | return estimateFunctionLatency(fnStats) + nStdDev * fnStats.executionTime.stdev;
|
634 | }
|
635 | async function retryFunctionIfNeededToReduceTailLatency(timeSinceInitialInvocation, getTimeout, worker, shouldRetry, cancel) {
|
636 | let pending = true;
|
637 | let lastInvocationTime = Date.now();
|
638 | cancel.then(() => (pending = false));
|
639 | const doWork = async () => {
|
640 | lastInvocationTime = Date.now();
|
641 | await worker().catch(_ => { });
|
642 | pending = false;
|
643 | };
|
644 | const latency = () => Date.now() - lastInvocationTime;
|
645 | doWork();
|
646 | while (pending) {
|
647 | const timeout = getTimeout();
|
648 | if (latency() >= timeout && timeSinceInitialInvocation() > timeout + 1000) {
|
649 | if (shouldRetry()) {
|
650 | doWork();
|
651 | }
|
652 | else {
|
653 | return;
|
654 | }
|
655 | }
|
656 | const waitTime = (0, shared_1.roundTo100ms)(Math.max(timeout - latency(), 5000));
|
657 | await (0, shared_1.sleep)(waitTime, cancel);
|
658 | }
|
659 | }
|
660 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFhc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZmFhc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsbUNBQXNDO0FBQ3RDLCtCQUErQjtBQUMvQiwrQkFBb0M7QUFDcEMsK0NBQWdFO0FBQ2hFLGlDQUFrRDtBQUNsRCxtQ0FBNEU7QUFDNUUsd0RBQStFO0FBQy9FLHFEQUEwRTtBQUMxRSwrQkFBNkM7QUFDN0MsdUNBS21CO0FBQ25CLHlDQVdvQjtBQUNwQiwyQ0FBNEU7QUFDNUUscUNBQWtGO0FBQ2xGLHlDQUFvRjtBQUNwRix1Q0FBc0Q7QUFDdEQsaUNBQWtDO0FBRWxDOzs7R0FHRztBQUNVLFFBQUEsU0FBUyxHQUFlLENBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRSxPQUFPLENBQUMsQ0FBQztBQXdHaEUsS0FBSyxVQUFVLHNCQUFzQixDQUNqQyxJQUF3QixFQUN4QixPQUFVLEVBQ1YsV0FBZTtJQUVmLElBQUk7UUFDQSxNQUFNLGNBQWMsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDeEMsTUFBTSxVQUFVLEdBQUcsSUFBQSxTQUFNLEdBQVUsQ0FBQztRQUNwQyxNQUFNLE9BQU8sR0FBZ0IsRUFBRSxHQUFHLElBQUksQ0FBQyxRQUFRLEVBQUUsR0FBRyxXQUFXLEVBQUUsQ0FBQztRQUNsRSxTQUFHLENBQUMsUUFBUSxDQUFDLFdBQVcsSUFBQSxxQkFBZSxFQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNwRCxPQUFPLElBQUksZ0JBQWdCLENBQ3ZCLElBQUksRUFDSixNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsY0FBYyxFQUFFLFVBQVUsRUFBRSxPQUFPLENBQUMsRUFDMUQsT0FBTyxFQUNQLGNBQWMsRUFDZCxPQUFrQyxDQUNyQyxDQUFDO0tBQ0w7SUFBQyxPQUFPLEdBQVEsRUFBRTtRQUNmLE1BQU0sSUFBSSxrQkFBVSxDQUFDLEdBQUcsRUFBRSxxQ0FBcUMsQ0FBQyxDQUFDO0tB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LEdBQUcsRUFBRSxDQUFDO1FBQ2hDLE1BQU0sTUFBTSxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUUsQ0FBQyxDQUFDLENBQUM7UUFDOUIsT0FBTyxHQUFHLEtBQUssQ0FBQztJQUNwQixDQUFDLENBQUM7SUFFRixNQUFNLE9BQU8sR0FBRyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsa0JBQWtCLENBQUM7SUFFdEQsTUFBTSxFQUFFLENBQUM7SUFFVCxPQUFPLE9BQU8sRUFBRTtRQUNaLE1BQU0sT0FBTyxHQUFHLFVBQVUsRUFBRSxDQUFDO1FBQzdCLElBQUksT0FBTyxFQUFFLElBQUksT0FBTyxJQUFJLDBCQUEwQixFQUFFLEdBQUcsT0FBTyxHQUFHLElBQUksRUFBRTtZQUN2RSxJQUFJLFdBQVcsRUFBRSxFQUFFO2dCQUNmLE1BQU0sRUFBRSxDQUFDO2FBQ1o7aUJBQU07Z0JBQ0gsT0FBTzthQUNWO1NBQ0o7UUFDRCxNQUFNLFFBQVEsR0FBRyxJQUFBLHFCQUFZLEVBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEdBQUcsT0FBTyxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUNuRSxNQUFNLElBQUEsY0FBSyxFQUFDLFFBQVEsRUFBRSxNQUFNLENBQUMsQ0FBQztLQUNqQztBQUNMLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBFdmVudEVtaXR0ZXIgfSBmcm9tIFwiZXZlbnRzXCI7XG5pbXBvcnQgeyBpbnNwZWN0IH0gZnJvbSBcInV0aWxcIjtcbmltcG9ydCB7IHY0IGFzIHV1aWR2NCB9IGZyb20gXCJ1dWlkXCI7XG5pbXBvcnQgeyBBd3NJbXBsLCBBd3NPcHRpb25zLCBBd3NTdGF0ZSB9IGZyb20gXCIuL2F3cy9hd3MtZmFhc3RcIjtcbmltcG9ydCB7IENvc3RNZXRyaWMsIENvc3RTbmFwc2hvdCB9IGZyb20gXCIuL2Nvc3RcIjtcbmltcG9ydCB7IEZhYXN0RXJyb3IsIEZhYXN0RXJyb3JOYW1lcywgc3ludGhlc2l6ZUZhYXN0RXJyb3IgfSBmcm9tIFwiLi9lcnJvclwiO1xuaW1wb3J0IHsgR29vZ2xlSW1wbCwgR29vZ2xlT3B0aW9ucywgR29vZ2xlU3RhdGUgfSBmcm9tIFwiLi9nb29nbGUvZ29vZ2xlLWZhYXN0XCI7XG5pbXBvcnQgeyBMb2NhbEltcGwsIExvY2FsT3B0aW9ucywgTG9jYWxTdGF0ZSB9IGZyb20gXCIuL2xvY2FsL2xvY2FsLWZhYXN0XCI7XG5pbXBvcnQgeyBpbnNwZWN0UHJvdmlkZXIsIGxvZyB9IGZyb20gXCIuL2xvZ1wiO1xuaW1wb3J0IHtcbiAgICBGYWN0b3J5TWFwLFxuICAgIEZ1bmN0aW9uQ3B1VXNhZ2UsXG4gICAgRnVuY3Rpb25TdGF0c01hcCxcbiAgICBNZW1vcnlMZWFrRGV0ZWN0b3Jcbn0gZnJvbSBcIi4vbWV0cmljc1wiO1xuaW1wb3J0IHtcbiAgICBDYWxsSWQsXG4gICAgQ2xlYW51cE9wdGlvbkRlZmF1bHRzLFxuICAgIENsZWFudXBPcHRpb25zLFxuICAgIENvbW1vbk9wdGlvbnMsXG4gICAgRnVuY3Rpb25TdGF0cyxcbiAgICBJdGVyYXRvclJlc3BvbnNlTWVzc2FnZSxcbiAgICBQcm9taXNlUmVzcG9uc2VNZXNzYWdlLFxuICAgIFByb3ZpZGVyLFxuICAgIFByb3ZpZGVySW1wbCxcbiAgICBVVUlEXG59IGZyb20gXCIuL3Byb3ZpZGVyXCI7XG5pbXBvcnQgeyBkZXNlcmlhbGl6ZSwgc2VyaWFsaXplLCBzZXJpYWxpemVGdW5jdGlvbkFyZ3MgfSBmcm9tIFwiLi9zZXJpYWxpemVcIjtcbmltcG9ydCB7IEV4cG9uZW50aWFsbHlEZWNheWluZ0F2ZXJhZ2VWYWx1ZSwgcm91bmRUbzEwMG1zLCBzbGVlcCB9IGZyb20gXCIuL3NoYXJlZFwiO1xuaW1wb3J0IHsgQXN5bmNPcmRlcmVkUXVldWUsIERlZmVycmVkLCBGdW5uZWwsIFB1bXAsIFJhdGVMaW1pdGVyIH0gZnJvbSBcIi4vdGhyb3R0bGVcIjtcbmltcG9ydCB7IEZ1bmN0aW9uQ2FsbCwgaXNHZW5lcmF0b3IgfSBmcm9tIFwiLi93cmFwcGVyXCI7XG5pbXBvcnQgTW9kdWxlID0gcmVxdWlyZShcIm1vZHVsZVwiKTtcblxuLyoqXG4gKiBBbiBhcnJheSBvZiBhbGwgYXZhaWxhYmxlIHByb3ZpZGVyLlxuICogQHB1YmxpY1xuICovXG5leHBvcnQgY29uc3QgcHJvdmlkZXJzOiBQcm92aWRlcltdID0gW1wiYXdzXCIsIFwiZ29vZ2xlXCIsIFwibG9jYWxcIl07XG5cbi8qKlxuICogYEFzeW5jPFQ+YCBtYXBzIHJlZ3VsYXIgdmFsdWVzIHRvIFByb21pc2VzIGFuZCBJdGVyYXRvcnMgdG8gQXN5bmNJdGVyYXRvcnMsXG4gKiBJZiBgVGAgaXMgYWxyZWFkeSBhIFByb21pc2Ugb3IgYW4gQXN5bmNJdGVyYXRvciwgaXQgcmVtYWlucyB0aGUgc2FtZS4gVGhpc1xuICogdHlwZSBpcyB1c2VkIHRvIGluZmVyIHRoZSByZXR1cm4gdmFsdWUgb2YgY2xvdWQgZnVuY3Rpb25zIGZyb20gdGhlIHR5cGVzIG9mXG4gKiB0aGUgZnVuY3Rpb25zIGluIHRoZSB1c2VyJ3MgaW5wdXQgbW9kdWxlLlxuICogQHB1YmxpY1xuICovXG5leHBvcnQgdHlwZSBBc3luYzxUPiA9IFQgZXh0ZW5kcyBBc3luY0dlbmVyYXRvcjxpbmZlciBSPlxuICAgID8gQXN5bmNHZW5lcmF0b3I8Uj5cbiAgICA6IFQgZXh0ZW5kcyBHZW5lcmF0b3I8aW5mZXIgUj5cbiAgICA/IEFzeW5jR2VuZXJhdG9yPFI+XG4gICAgOiBUIGV4dGVuZHMgUHJvbWlzZTxpbmZlciBSPlxuICAgID8gUHJvbWlzZTxSPlxuICAgIDogUHJvbWlzZTxUPjtcblxuLyoqXG4gKiBgQXN5bmNEZXRhaWw8VD5gIGlzIHNpbWlsYXIgdG8ge0BsaW5rIEFzeW5jfSBleGNlcHQgaXQgbWFwcyByZXR1biB2YWx1ZXMgUiB0b1xuICogYERldGFpbDxSPmAsIHdoaWNoIGlzIHRoZSByZXR1cm4gdmFsdWUgd2l0aCBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIGFib3V0IGVhY2hcbiAqIGNsb3VkIGZ1bmN0aW9uIGludm9jYXRpb24uXG4gKiBAcHVibGljXG4gKi9cbmV4cG9ydCB0eXBlIEFzeW5jRGV0YWlsPFQ+ID0gVCBleHRlbmRzIEFzeW5jR2VuZXJhdG9yPGluZmVyIFI+XG4gICAgPyBBc3luY0dlbmVyYXRvcjxEZXRhaWw8Uj4+XG4gICAgOiBUIGV4dGVuZHMgR2VuZXJhdG9yPGluZmVyIFI+XG4gICAgPyBBc3luY0dlbmVyYXRvcjxEZXRhaWw8Uj4+XG4gICAgOiBUIGV4dGVuZHMgUHJvbWlzZTxpbmZlciBSPlxuICAgID8gUHJvbWlzZTxEZXRhaWw8Uj4+XG4gICAgOiBQcm9taXNlPERldGFpbDxUPj47XG5cbi8qKlxuICogYFByb3h5TW9kdWxlPE0+YCBpcyB0aGUgdHlwZSBvZiB7QGxpbmsgRmFhc3RNb2R1bGUuZnVuY3Rpb25zfS5cbiAqIEByZW1hcmtzXG4gKiBgUHJveHlNb2R1bGU8TT5gIG1hcHMgYW4gaW1wb3J0ZWQgbW9kdWxlJ3MgZnVuY3Rpb25zIHRvIHByb21pc2UtcmV0dXJuaW5nIG9yXG4gKiBhc3luYy1pdGVyYXRhYmxlIHZlcnNpb25zIG9mIHRob3NlIGZ1bmN0aW9ucy4gTm9uLWZ1bmN0aW9uIGV4cG9ydHMgb2YgdGhlXG4gKiBtb2R1bGUgYXJlIG9taXR0ZWQuIFdoZW4gaW52b2tlZCwgdGhlIGZ1bmN0aW9ucyBpbiBhIGBQcm94eU1vZHVsZWAgaW52b2tlIGFcbiAqIHJlbW90ZSBjbG91ZCBmdW5jdGlvbi5cbiAqIEBwdWJsaWNcbiAqL1xuZXhwb3J0IHR5cGUgUHJveHlNb2R1bGU8TT4gPSB7XG4gICAgW0sgaW4ga2V5b2YgTV06IE1bS10gZXh0ZW5kcyAoLi4uYXJnczogaW5mZXIgQSkgPT4gaW5mZXIgUlxuICAgICAgICA/ICguLi5hcmdzOiBBKSA9PiBBc3luYzxSPlxuICAgICAgICA6IG5ldmVyO1xufTtcblxuLyoqXG4gKiBTaW1pbGFyIHRvIHtAbGluayBQcm94eU1vZHVsZX0gZXhjZXB0IGVhY2ggZnVuY3Rpb24gcmV0dXJucyBhIHtAbGluayBEZXRhaWx9XG4gKiBvYmplY3QuXG4gKiBAcmVtYXJrc1xuICogU2VlIHtAbGluayBGYWFzdE1vZHVsZS5mdW5jdGlvbnNEZXRhaWx9LlxuICogQHB1YmxpY1xuICovXG5leHBvcnQgdHlwZSBQcm94eU1vZHVsZURldGFpbDxNPiA9IHtcbiAgICBbSyBpbiBrZXlvZiBNXTogTVtLXSBleHRlbmRzICguLi5hcmdzOiBpbmZlciBBKSA9PiBpbmZlciBSXG4gICAgICAgID8gKC4uLmFyZ3M6IEEpID0+IEFzeW5jRGV0YWlsPFI+XG4gICAgICAgIDogbmV2ZXI7XG59O1xuXG4vKipcbiAqIEEgZnVuY3Rpb24gcmV0dXJuIHZhbHVlIHdpdGggYWRkaXRpb25hbCBkZXRhaWxlZCBpbmZvcm1hdGlvbi5cbiAqIEBwdWJsaWNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEZXRhaWw8Uj4ge1xuICAgIC8qKlxuICAgICAqIEEgUHJvbWlzZSBmb3IgdGhlIGZ1bmN0aW9uJ3MgcmV0dXJuIHZhbHVlLlxuICAgICAqL1xuICAgIHZhbHVlOiBSO1xuICAgIC8qKlxuICAgICAqIFRoZSBVUkwgb2YgdGhlIGxvZ3MgZm9yIHRoZSBzcGVjaWZpYyBleGVjdXRpb24gb2YgdGhpcyBmdW5jdGlvbiBjYWxsLlxuICAgICAqIEByZW1hcmtzXG4gICAgICogVGhpcyBpcyBkaWZmZXJlbnQgZnJvbSB0aGUgZ2VuZXJhbCBsb2dVcmwgZnJvbVxuICAgICAqIHtAbGluayBGYWFzdE1vZHVsZS5sb2dVcmx9LCB3aGljaCBwcm92aWRlcyBhIGxpbmsgdG8gdGhlIGxvZ3MgZm9yIGFsbFxuICAgICAqIGludm9jYXRpb25zIG9mIGFsbCBmdW5jdGlvbnMgd2l0aGluIHRoYXQgbW9kdWxlLiBXaGVyZWFzIHRoaXMgbG9nVXJsIGlzXG4gICAgICogb25seSBmb3IgdGhpcyBzcGVjaWZpYyBpbnZvY2F0aW9uLlxuICAgICAqL1xuICAgIGxvZ1VybD86IHN0cmluZztcbiAgICAvKipcbiAgICAgKiBJZiBhdmFpbGFibGUsIHRoZSBwcm92aWRlci1zcGVjaWZpYyBleGVjdXRpb24gaWRlbnRpZmllciBmb3IgdGhpc1xuICAgICAqIGludm9jYXRpb24uXG4gICAgICogQHJlbWFya3NcbiAgICAgKiBUaGlzIElEIG1heSBiZSBhZGRlZCB0byB0aGUgbG9nIGVudHJpZXMgZm9yIHRoaXMgaW52b2NhdGlvbiBieSB0aGUgY2xvdWRcbiAgICAgKiBwcm92aWRlci5cbiAgICAgKi9cbiAgICBleGVjdXRpb25JZD86IHN0cmluZztcbiAgICAvKipcbiAgICAgKiBJZiBhdmFpbGFibGUsIHRoZSBwcm92aWRlci1zcGVjaWZpYyBpbnN0YW5jZSBpZGVudGlmaWVyIGZvciB0aGlzXG4gICAgICogaW52b2NhdGlvbi5cbiAgICAgKiBAcmVtYXJrc1xuICAgICAqIFRoaXMgSUQgcmVmZXJzIHRvIHRoZSBzcGVjaWZpYyBjb250YWluZXIgb3IgVk0gdXNlZCB0byBleGVjdXRlIHRoaXNcbiAgICAgKiBmdW5jdGlvbiBpbnZvY2F0aW9uLiBUaGUgaW5zdGFuY2UgbWF5IGJlIHJldXNlZCBhY3Jvc3MgbXVsdGlwbGVcbiAgICAgKiBpbnZvY2F0aW9ucy5cbiAgICAgKi9cbiAgICBpbnN0YW5jZUlkPzogc3RyaW5nO1xufVxuXG5pbnRlcmZhY2UgRnVuY3Rpb25SZXR1cm5XaXRoTWV0cmljcyB7XG4gICAgcmVzcG9uc2U6IFByb21pc2VSZXNwb25zZU1lc3NhZ2UgfCBJdGVyYXRvclJlc3BvbnNlTWVzc2FnZTtcbiAgICB2YWx1ZTogYW55O1xuICAgIGxvY2FsUmVxdWVzdFNlbnRUaW1lOiBudW1iZXI7XG4gICAgbG9jYWxFbmRUaW1lOiBudW1iZXI7XG4gICAgcmVtb3RlUmVzcG9uc2VTZW50VGltZT86IG51bWJlcjtcbn1cblxuYXN5bmMgZnVuY3Rpb24gY3JlYXRlRmFhc3RNb2R1bGVQcm94eTxNIGV4dGVuZHMgb2JqZWN0LCBPIGV4dGVuZHMgQ29tbW9uT3B0aW9ucywgUz4oXG4gICAgaW1wbDogUHJvdmlkZXJJbXBsPE8sIFM+LFxuICAgIGZtb2R1bGU6IE0sXG4gICAgdXNlck9wdGlvbnM/OiBPXG4pOiBQcm9taXNlPEZhYXN0TW9kdWxlUHJveHk8TSwgTywgUz4+IHtcbiAgICB0cnkge1xuICAgICAgICBjb25zdCByZXNvbHZlZE1vZHVsZSA9IHJlc29sdmUoZm1vZHVsZSk7XG4gICAgICAgIGNvbnN0IGZ1bmN0aW9uSWQgPSB1dWlkdjQoKSBhcyBVVUlEO1xuICAgICAgICBjb25zdCBvcHRpb25zOiBSZXF1aXJlZDxPPiA9IHsgLi4uaW1wbC5kZWZhdWx0cywgLi4udXNlck9wdGlvbnMgfTtcbiAgICAgICAgbG9nLnByb3ZpZGVyKGBvcHRpb25zICR7aW5zcGVjdFByb3ZpZGVyKG9wdGlvbnMpfWApO1xuICAgICAgICByZXR1cm4gbmV3IEZhYXN0TW9kdWxlUHJveHkoXG4gICAgICAgICAgICBpbXBsLFxuICAgICAgICAgICAgYXdhaXQgaW1wbC5pbml0aWFsaXplKHJlc29sdmVkTW9kdWxlLCBmdW5jdGlvbklkLCBvcHRpb25zKSxcbiAgICAgICAgICAgIGZtb2R1bGUsXG4gICAgICAgICAgICByZXNvbHZlZE1vZHVsZSxcbiAgICAgICAgICAgIG9wdGlvbnMgYXMgUmVxdWlyZWQ8Q29tbW9uT3B0aW9ucz5cbiAgICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICB0aHJvdyBuZXcgRmFhc3RFcnJvcihlcnIsIFwiY291bGQgbm90IGluaXRpYWxpemUgY2xvdWQgZnVuY3Rpb25cIik7XG4gICAgfVxufVxuXG4vKipcbiAqIFN1bW1hcml6ZSBzdGF0aXN0aWNzIGFib3V0IGNsb3VkIGZ1bmN0aW9uIGludm9jYXRpb25zLlxuICogQHB1YmxpY1xuICovXG5leHBvcnQgY2xhc3MgRnVuY3Rpb25TdGF0c0V2ZW50IHtcbiAgICAvKipcbiAgICAgKiBAaW50ZXJuYWxcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgLyoqIFRoZSBuYW1lIG9mIHRoZSBjbG91ZCBmdW5jdGlvbiB0aGUgc3RhdGlzdGljcyBhcmUgYWJvdXQuICovXG4gICAgICAgIHJlYWRvbmx5IGZuOiBzdHJpbmcsXG4gICAgICAgIC8qKiBTZWUge0BsaW5rIEZ1bmN0aW9uU3RhdHN9LiAqL1xuICAgICAgICByZWFkb25seSBzdGF0czogRnVuY3Rpb25TdGF0c1xuICAgICkge1xuICAgICAgICB0aGlzLnN0YXRzID0gc3RhdHMuY2xvbmUoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIGEgc3RyaW5nIHN1bW1hcml6aW5nIHRoZSBzdGF0aXN0aWNzIGV2ZW50LlxuICAgICAqIEByZW1hcmtzXG4gICAgICogVGhlIHN0cmluZyBpbmNsdWRlcyBudW1iZXIgb2YgY29tcGxldGVkIGNhbGxzLCBlcnJvcnMsIGFuZCByZXRyaWVzLCBhbmRcbiAgICAgKiB0aGUgbWVhbiBleGVjdXRpb24gdGltZSBmb3IgdGhlIGNhbGxzIHRoYXQgY29tcGxldGVkIHdpdGhpbiB0aGUgbGFzdCB0aW1lXG4gICAgICogaW50ZXJ2YWwgKDFzKS5cbiAgICAgKi9cbiAgICB0b1N0cmluZygpIHtcbiAgICAgICAgY29uc3QgZXhlY3V0aW9uVGltZSA9IHRoaXMuc3RhdHMgPyB0aGlzLnN0YXRzLmV4ZWN1dGlvblRpbWUubWVhbiA6IDA7XG4gICAgICAgIHJldHVybiBgWyR7dGhpcy5mbn1dICR7dGhpcy5zdGF0c30sIGV4ZWN1dGlvblRpbWU6ICR7KFxuICAgICAgICAgICAgZXhlY3V0aW9uVGltZSAvIDEwMDBcbiAgICAgICAgKS50b0ZpeGVkKDIpfXNgO1xuICAgIH1cbn1cblxuY2xhc3MgUGVuZGluZ1JlcXVlc3Qge1xuICAgIHF1ZXVlOiBBc3luY09yZGVyZWRRdWV1ZTxGdW5jdGlvblJldHVybldpdGhNZXRyaWNzPiA9IG5ldyBBc3luY09yZGVyZWRRdWV1ZSgpO1xuICAgIGNyZWF0ZWQ6IG51bWJlciA9IERhdGUubm93KCk7XG4gICAgZXhlY3V0aW5nPzogYm9vbGVhbjtcblxuICAgIGNvbnN0cnVjdG9yKHJlYWRvbmx5IGNhbGw6IEZ1bmN0aW9uQ2FsbCkge31cbn1cblxuLyoqXG4gKiBUaGUgbWFpbiBpbnRlcmZhY2UgZm9yIGludm9raW5nLCBjbGVhbmluZyB1cCwgYW5kIG1hbmFnaW5nIGZhYXN0LmpzIGNsb3VkXG4gKiBmdW5jdGlvbnMuIFJldHVybmVkIGJ5IHtAbGluayBmYWFzdH0uXG4gKiBAcHVibGljXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRmFhc3RNb2R1bGU8TSBleHRlbmRzIG9iamVjdD4ge1xuICAgIC8qKiBTZWUge0BsaW5rIFByb3ZpZGVyfS4gICovXG4gICAgcHJvdmlkZXI6IFByb3ZpZGVyO1xuICAgIC8qKlxuICAgICAqIEVhY2ggY2FsbCBvZiBhIGNsb3VkIGZ1bmN0aW9uIGNyZWF0ZXMgYSBzZXBhcmF0ZSByZW1vdGUgaW52b2NhdGlvbi5cbiAgICAgKiBAcmVtYXJrc1xuICAgICAqIFRoZSBtb2R1bGUgcGFzc2VkIGludG8ge0BsaW5rIGZhYXN0fSBvciBpdHMgcHJvdmlkZXItc3BlY2lmaWMgdmFyaWFudHNcbiAgICAgKiAoe0BsaW5rIGZhYXN0QXdzfSwge0BsaW5rIGZhYXN0R29vZ2xlfSwgYW5kIHtAbGluayBmYWFzdExvY2FsfSkgaXMgbWFwcGVkXG4gICAgICogdG8gYSB7QGxpbmsgUHJveHlNb2R1bGV9IHZlcnNpb24gb2YgdGhlIG1vZHVsZSwgd2hpY2ggcGVyZm9ybXMgdGhlXG4gICAgICogZm9sbG93aW5nIG1hcHBpbmc6XG4gICAgICpcbiAgICAgKiAtIEFsbCBmdW5jdGlvbiBleHBvcnRzIHRoYXQgYXJlIGdlbmVyYXRvcnMgYXJlIG1hcHBlZCB0byBhc3luY1xuICAgICAqICAgZ2VuZXJhdG9ycy5cbiAgICAgKlxuICAgICAqIC0gQWxsIGZ1bmN0aW9uIGV4cG9ydHMgdGhhdCByZXR1cm4gYXN5bmMgZ2VuZXJhdG9ycyBhcmUgcHJlc2VydmVkIGFzLWlzLlxuICAgICAqXG4gICAgICogLSBBbGwgZnVuY3Rpb24gZXhwb3J0cyB0aGF0IHJldHVybiBwcm9taXNlcyBoYXZlIHRoZWlyIHR5cGUgc2lnbmF0dXJlc1xuICAgICAqICAgcHJlc2VydmVkIGFzLWlzLlxuICAgICAqXG4gICAgICogLSBBbGwgZnVuY3Rpb24gZXhwb3J0cyB0aGF0IHJldHVybiB0eXBlIFQsIHdoZXJlIFQgaXMgbm90IGEgUHJvbWlzZSxcbiAgICAgKiAgIEdlbmVyYXRvciwgb3IgQXN5bmNHZW5lcmF0b3IsIGFyZSBtYXBwZWQgdG8gZnVuY3Rpb25zIHRoYXQgcmV0dXJuXG4gICAgICogICBQcm9taXNlPFQ+LiBBcmd1bWVudCB0eXBlcyBhcmUgcHJlc2VydmVkIGFzLWlzLlxuICAgICAqXG4gICAgICogLSBBbGwgbm9uLWZ1bmN0aW9uIGV4cG9ydHMgYXJlIG9taXR0ZWQgaW4gdGhlIHJlbW90ZSBtb2R1bGUuXG4gICAgICpcbiAgICAgKiBBcmd1bWVudHMgYW5kIHJldHVybiB2YWx1ZXMgYXJlIHNlcmlhbGl6ZWQgd2l0aCBgSlNPTi5zdHJpbmdpZnlgIHdoZW5cbiAgICAgKiBjbG91ZCBmdW5jdGlvbnMgYXJlIGNhbGxlZCwgdGhlcmVmb3JlIHdoYXQgaXMgcmVjZWl2ZWQgb24gdGhlIHJlbW90ZSBzaWRlXG4gICAgICogbWlnaHQgbm90IG1hdGNoIHdoYXQgd2FzIHNlbnQuIEZhYXN0LmpzIGF0dGVtcHRzIHRvIGRldGVjdCBub25zdXBwb3J0ZWRcbiAgICAgKiBhcmd1bWVudHMgb24gYSBiZXN0IGVmZm9ydCBiYXNpcy5cbiAgICAgKlxuICAgICAqIElmIHRoZSBjbG91ZCBmdW5jdGlvbiB0aHJvd3MgYW4gZXhjZXB0aW9uIG9yIHJlamVjdHMgaXRzIHByb21pc2Ugd2l0aCBhblxuICAgICAqIGluc3RhbmNlIG9mIGBFcnJvcmAsIHRoZW4gdGhlIGZ1bmN0aW9uIHdpbGwgcmVqZWN0IHdpdGhcbiAgICAgKiB7QGxpbmsgRmFhc3RFcnJvcn0gb24gdGhlIGxvY2FsIHNpZGUuIElmIHRoZSBleGNlcHRpb24gb3IgcmVqZWN0aW9uXG4gICAgICogcmVzb2x2ZXMgdG8gYW55IHZhbHVlIHRoYXQgaXMgbm90IGFuIGluc3RhbmNlIG9mIGBFcnJvcmAsIHRoZSByZW1vdGVcbiAgICAgKiBmdW5jdGlvbiBwcm94eSB3aWxsIHJlamVjdCB3aXRoIHRoZSB2YWx1ZSBvZlxuICAgICAqIGBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KGVycikpYC5cbiAgICAgKlxuICAgICAqIEFyZ3VtZW50cyBhbmQgcmV0dXJuIHZhbHVlcyBoYXZlIHNpemUgbGltaXRhdGlvbnMgdGhhdCB2YXJ5IGJ5IHByb3ZpZGVyXG4gICAgICogYW5kIG1vZGU6XG4gICAgICpcbiAgICAgKiAtIEFXUzogMjU2S0IgaW4gcXVldWUgbW9kZSwgNk1CIGFyZ3VtZW50cyBhbmQgMjU2S0IgcmV0dXJuIHZhbHVlcyBpbiBodHRwcyBtb2RlLiBTZWVcbiAgICAgKiAgIHtAbGluayBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vbGFtYmRhL2xhdGVzdC9kZy9saW1pdHMuaHRtbCB8IEFXUyBMYW1iZGEgTGltaXRzfS5cbiAgICAgKlxuICAgICAqIC0gR29vZ2xlOiAxME1CIGluIGh0dHBzIGFuZCBxdWV1ZSBtb2Rlcy4gU2VlXG4gICAgICogICB7QGxpbmsgaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL2Z1bmN0aW9ucy9xdW90YXMgfCBHb29nbGUgQ2xvdWQgRnVuY3Rpb24gUXVvdGFzfS5cbiAgICAgKlxuICAgICAqIC0gTG9jYWw6IGxpbWl0ZWQgb25seSBieSBhdmFpbGFibGUgbWVtb3J5IGFuZCB0aGUgbGltaXRzIG9mXG4gICAgICogICB7QGxpbmsgaHR0cHM6Ly9ub2RlanMub3JnL2FwaS9jaGlsZF9wcm9jZXNzLmh0bWwjY2hpbGRfcHJvY2Vzc19zdWJwcm9jZXNzX3NlbmRfbWVzc2FnZV9zZW5kaGFuZGxlX29wdGlvbnNfY2FsbGJhY2sgfCBjaGlsZHByb2Nlc3Muc2VuZH0uXG4gICAgICpcbiAgICAgKiBOb3RlIHRoYXQgcGF5bG9hZHMgbWF5IGJlIGJhc2U2NCBlbmNvZGVkIGZvciBzb21lIHByb3ZpZGVycyBhbmQgdGhlcmVmb3JlXG4gICAgICogZGlmZmVyZW50IGluIHNpemUgdGhhbiB0aGUgb3JpZ2luYWwgcGF5bG9hZC4gQWxzbywgc29tZSBib29ra2VlcGluZyBkYXRhXG4gICAgICogYXJlIHBhc3NlZCBhbG9uZyB3aXRoIGFyZ3VtZW50cyBhbmQgY29udHJpYnV0ZSB0byB0aGUgc2l6ZSBsaW1pdC5cbiAgICAgKi9cbiAgICBmdW5jdGlvbnM6IFByb3h5TW9kdWxlPE0+O1xuICAgIC8qKlxuICAgICAqIFNpbWlsYXIgdG8ge0BsaW5rIEZhYXN0TW9kdWxlLmZ1bmN0aW9uc30gZXhjZXB0IGVhY2ggZnVuY3Rpb24gcmV0dXJucyBhXG4gICAgICoge0BsaW5rIERldGFpbH0gb2JqZWN0XG4gICAgICogQHJlbWFya3NcbiAgICAgKiBBZHZhbmNlZCB1c2VycyBvZiBmYWFzdC5qcyBtYXkgd2FudCBtb3JlIGluZm9ybWF0aW9uIGFib3V0IGVhY2ggZnVuY3Rpb25cbiAgICAgKiBpbnZvY2F0aW9uIHRoYW4gc2ltcGx5IHRoZSByZXN1bHQgb2YgdGhlIGZ1bmN0aW9uIGNhbGwuIEZvciBleGFtcGxlLCB0aGVcbiAgICAgKiBzcGVjaWZpYyBsb2dVcmwgZm9yIGVhY2ggaW52b2NhdGlvbiwgdG8gaGVscCB3aXRoIGRldGFpbGVkIGRlYnVnZ2luZy5cbiAgICAgKiBUaGlzIGludGVyZmFjZSBwcm92aWRlcyBhIHdheSB0byBnZXQgdGhpcyBkZXRhaWxlZCBpbmZvcm1hdGlvbi5cbiAgICAgKi9cbiAgICBmdW5jdGlvbnNEZXRhaWw6IFByb3h5TW9kdWxlRGV0YWlsPE0+O1xuICAgIC8qKlxuICAgICAqIFN0b3AgdGhlIGZhYXN0LmpzIHJ1bnRpbWUgZm9yIHRoaXMgY2xvdWQgZnVuY3Rpb24gYW5kIGNsZWFuIHVwIGVwaGVtZXJhbFxuICAgICAqIGNsb3VkIHJlc291cmNlcy5cbiAgICAgKiBAcmV0dXJucyBhIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBgRmFhc3RNb2R1bGVgIHJ1bnRpbWUgc3RvcHMgYW5kXG4gICAgICogZXBoZW1lcmFsIHJlc291cmNlcyBoYXZlIGJlZW4gZGVsZXRlZC5cbiAgICAgKiBAcmVtYXJrc1xuICAgICAqIEl0IGlzIGJlc3QgcHJhY3RpY2UgdG8gYWx3YXlzIGNhbGwgYGNsZWFudXBgIHdoZW4gZG9uZSB3aXRoIGEgY2xvdWRcbiAgICAgKiBmdW5jdGlvbi4gQSB0eXBpY2FsIHdheSB0byBlbnN1cmUgdGhpcyBpbiBub3JtYWwgZXhlY3V0aW9uIGlzIHRvIHVzZSB0aGVcbiAgICAgKiBgZmluYWxseWAgY29uc3RydWN0OlxuICAgICAqXG4gICAgICogYGBgdHlwZXNjcmlwdFxuICAgICAqIGNvbnN0IGZhYXN0TW9kdWxlID0gYXdhaXQgZmFhc3QoXCJhd3NcIiwgbSk7XG4gICAgICogdHJ5IHtcbiAgICAgKiAgICAgLy8gQ2FsbCBmYWFzdE1vZHVsZS5mdW5jdGlvbnMuKlxuICAgICAqIH0gZmluYWxseSB7XG4gICAgICogICAgIC8vIE5vdGUgdGhlIGBhd2FpdGBcbiAgICAgKiAgICAgYXdhaXQgZmFhc3RNb2R1bGUuY2xlYW51cCgpO1xuICAgICAqIH1cbiAgICAgKiBgYGBcbiAgICAgKlxuICAgICAqIEFmdGVyIHRoZSBjbGVhbnVwIHByb21pc2UgcmVzb2x2ZXMsIHRoZSBjbG91ZCBmdW5jdGlvbiBpbnN0YW5jZSBjYW4gbm9cbiAgICAgKiBsb25nZXIgaW52b2tlIG5ldyBjYWxscyBvbiB7QGxpbmsgRmFhc3RNb2R1bGUuZnVuY3Rpb25zfS4gSG93ZXZlciwgb3RoZXJcbiAgICAgKiBtZXRob2RzIG9uIHtAbGluayBGYWFzdE1vZHVsZX0gYXJlIHNhZmUgdG8gY2FsbCwgc3VjaCBhc1xuICAgICAqIHtAbGluayBGYWFzdE1vZHVsZS5jb3N0U25hcHNob3R9LlxuICAgICAqXG4gICAgICogQ2xlYW51cCBhbHNvIHN0b3BzIHN0YXRpc3RpY3MgZXZlbnRzIChTZWUge0BsaW5rIEZhYXN0TW9kdWxlLm9mZn0pLlxuICAgICAqXG4gICAgICogQnkgZGVmYXVsdCwgY2xlYW51cCB3aWxsIGRlbGV0ZSBhbGwgZXBoZW1lcmFsIGNsb3VkIHJlc291cmNlcyBidXQgbGVhdmVcbiAgICAgKiBiZWhpbmQgY2FjaGVkIHJlc291cmNlcyBmb3IgdXNlIGJ5IGZ1dHVyZSBjbG91ZCBmdW5jdGlvbnMuIERlbGV0ZWRcbiAgICAgKiByZXNvdXJjZXMgdHlwaWNhbGx5IGluY2x1ZGUgY2xvdWQgZnVuY3Rpb25zLCBxdWV1ZXMsIGFuZCBxdWV1ZVxuICAgICAqIHN1YnNjcmlwdGlvbnMuIExvZ3MgYXJlIG5vdCBkZWxldGVkIGJ5IGNsZWFudXAuXG4gICAgICpcbiAgICAgKiBOb3RlIHRoYXQgYGNsZWFudXBgIGxlYXZlcyBiZWhpbmQgc29tZSBwcm92aWRlci1zcGVjaWZpYyByZXNvdXJjZXM6XG4gICAgICpcbiAgICAgKiAtIEFXUzogQ2xvdWR3YXRjaCBsb2dzIGFyZSBwcmVzZXJ2ZWQgdW50aWwgdGhlIGdhcmJhZ2UgY29sbGVjdG9yIGluIGFcbiAgICAgKiAgIGZ1dHVyZSBjbG91ZCBmdW5jdGlvbiBpbnN0YW5jZSBkZWxldGVzIHRoZW0uIFRoZSBkZWZhdWx0IGxvZyBleHBpcmF0aW9uXG4gICAgICogICB0aW1lIGlzIDI0aCAob3IgdGhlIHZhbHVlIG9mIHtAbGluayBDb21tb25PcHRpb25zLnJldGVudGlvbkluRGF5c30pLiBJblxuICAgICAqICAgYWRkaXRpb24sIHRoZSBBV1MgTGFtYmRhIElBTSByb2xlIGlzIG5vdCBkZWxldGVkIGJ5IGNsZWFudXAuIFRoaXMgcm9sZVxuICAgICAqICAgaXMgc2hhcmVkIGFjcm9zcyBjbG91ZCBmdW5jdGlvbiBpbnN0YW5jZXMuIExhbWJkYSBsYXllcnMgYXJlIGFsc28gbm90XG4gICAgICogICBjbGVhbmVkIHVwIGltbWVkaWF0ZWx5IG9uIEFXUyB3aGVuIHtAbGluayBDb21tb25PcHRpb25zLnBhY2thZ2VKc29ufSBpc1xuICAgICAqICAgdXNlZCBhbmQge0BsaW5rIENvbW1vbk9wdGlvbnMudXNlRGVwZW5kZW5jeUNhY2hpbmd9IGlzIHRydWUuIENhY2hlZFxuICAgICAqICAgbGF5ZXJzIGFyZSBjbGVhbmVkIHVwIGJ5IGdhcmJhZ2UgY29sbGVjdGlvbi4gQWxzbyBzZWVcbiAgICAgKiAgIHtAbGluayBDbGVhbnVwT3B0aW9ucy5kZWxldGVDYWNoZXN9LlxuICAgICAqXG4gICAgICogLSBHb29nbGU6IEdvb2dsZSBTdGFja2RyaXZlciBhdXRvbWF0aWNhbGx5IGRlbGV0ZXMgbG9nIGVudHJpZXMgYWZ0ZXIgMzBcbiAgICAgKiAgIGRheXMuXG4gICAgICpcbiAgICAgKiAtIExvY2FsOiBMb2dzIGFyZSBwcmVzZXJ2ZWQgaW4gYSB0ZW1wb3JhcnkgZGlyZWN0b3J5IG9uIGxvY2FsIGRpc2suXG4gICAgICogICBHYXJiYWdlIGNvbGxlY3Rpb24gaW4gYSBmdXR1cmUgY2xvdWQgZnVuY3Rpb24gaW5zdGFuY2Ugd2lsbCBkZWxldGUgbG9nc1xuICAgICAqICAgb2xkZXIgdGhhbiAyNGguXG4gICAgICovXG4gICAgY2xlYW51cChvcHRpb25zPzogQ2xlYW51cE9wdGlvbnMpOiBQcm9taXNlPHZvaWQ+O1xuICAgIC8qKlxuICAgICAqIFRoZSBVUkwgb2YgbG9ncyBnZW5lcmF0ZWQgYnkgdGhpcyBjbG91ZCBmdW5jdGlvbi5cbiAgICAgKiBAcmVtYXJrc1xuICAgICAqIExvZ3MgYXJlIG5vdCBhdXRvbWF0aWNhbGx5IGRvd25sb2FkZWQgYmVjYXVzZSB0aGV5IGNhdXNlIG91dGJvdW5kIGRhdGFcbiAgICAgKiB0cmFuc2Zlciwgd2hpY2ggY2FuIGJlIGV4cGVuc2l2ZS4gQWxzbywgbG9ncyBtYXkgYXJyaXZlIGF0IHRoZSBsb2dnaW5nXG4gICAgICogc2VydmljZSB3ZWxsIGFmdGVyIHRoZSBjbG91ZCBmdW5jdGlvbnMgaGF2ZSBjb21wbGV0ZWQuIFRoaXMgbG9nIFVSTFxuICAgICAqIHNwZWNpZmljYWxseSBmaWx0ZXJzIHRoZSBsb2dzIGZvciB0aGlzIGNsb3VkIGZ1bmN0aW9uIGluc3RhbmNlLlxuICAgICAqIEF1dGhlbnRpY2F0aW9uIGlzIHJlcXVpcmVkIHRvIHZpZXcgY2xvdWQgcHJvdmlkZXIgbG9ncy5cbiAgICAgKlxuICAgICAqIFRoZSBsb2NhbCBwcm92aWRlciByZXR1cm5zIGEgYGZpbGU6Ly9gIHVybCBwb2ludGluZyB0byBhIGZpbGUgZm9yIGxvZ3MuXG4gICAgICovXG4gICAgbG9nVXJsKCk6IHN0cmluZztcbiAgICAvKipcbiAgICAgKiBSZWdpc3RlciBhIGNhbGxiYWNrIGZvciBzdGF0aXN0aWNzIGV2ZW50cy5cbiAgICAgKiBAcmVtYXJrc1xuICAgICAqIFRoZSBjYWxsYmFjayBpcyBpbnZva2VkIG9uY2UgZm9yIGVhY2ggY2xvdWQgZnVuY3Rpb24gdGhhdCB3YXMgaW52b2tlZFxuICAgICAqIHdpdGhpbiB0aGUgbGFzdCAxcyBpbnRlcnZhbCwgd2l0aCBhIHtAbGluayBGdW5jdGlvblN0YXRzRXZlbnR9XG4gICAgICogc3VtbWFyaXppbmcgdGhlIHN0YXRpc3RpY3MgZm9yIGVhY2ggZnVuY3Rpb24uIFR5cGljYWwgdXNhZ2U6XG4gICAgICpcbiAgICAgKiBgYGB0eXBlc2NyaXB0XG4gICAgICogZmFhc3RNb2R1bGUub24oXCJzdGF0c1wiLCBjb25zb2xlLmxvZyk7XG4gICAgICogYGBgXG4gICAgICovXG4gICAgb24obmFtZTogXCJzdGF0c1wiLCBsaXN0ZW5lcjogKHN0YXRzRXZlbnQ6IEZ1bmN0aW9uU3RhdHNFdmVudCkgPT4gdm9pZCk6IHZvaWQ7XG4gICAgLyoqXG4gICAgICogRGVyZWdpc3RlciBhIGNhbGxiYWNrIGZvciBzdGF0aXN0aWNzIGV2ZW50cy5cbiAgICAgKiBAcmVtYXJrc1xuICAgICAqIFN0b3BzIHRoZSBjYWxsYmFjayBsaXN0ZW5lciBmcm9tIHJlY2VpdmluZyBmdXR1cmUgZnVuY3Rpb24gc3RhdGlzdGljc1xuICAgICAqIGV2ZW50cy4gQ2FsbGluZyB7QGxpbmsgRmFhc3RNb2R1bGUuY2xlYW51cH0gYWxzbyB0dXJucyBvZmYgc3RhdGlzdGljc1xuICAgICAqIGV2ZW50cy5cbiAgICAgKi9cbiAgICBvZmYobmFtZTogXCJzdGF0c1wiLCBsaXN0ZW5lcjogKHN0YXRzRXZlbnQ6IEZ1bmN0aW9uU3RhdHNFdmVudCkgPT4gdm9pZCk6IHZvaWQ7XG4gICAgLyoqXG4gICAgICogR2V0IGEgbmVhciByZWFsLXRpbWUgY29zdCBlc3RpbWF0ZSBvZiBjbG91ZCBmdW5jdGlvbiBpbnZvY2F0aW9ucy5cbiAgICAgKiBAcmV0dXJucyBhIFByb21pc2UgZm9yIGEge0BsaW5rIENvc3RTbmFwc2hvdH0uXG4gICAgICogQHJlbWFya3NcbiAgICAgKiBBIGNvc3Qgc25hcHNob3QgcHJvdmlkZXMgYSBuZWFyIHJlYWwtdGltZSBlc3RpbWF0ZSBvZiB0aGUgY29zdHMgb2YgdGhlXG4gICAgICogY2xvdWQgZnVuY3Rpb25zIGludm9rZWQuIFRoZSBjb3N0IGVzdGltYXRlIG9ubHkgaW5jbHVkZXMgdGhlIGNvc3Qgb2ZcbiAgICAgKiBzdWNjZXNzZnVsbHkgY29tcGxldGVkIGNhbGxzLiBVbnN1Y2Nlc3NmdWwgY2FsbHMgbWF5IGxhY2sgdGhlIGRhdGFcbiAgICAgKiByZXF1aXJlZCB0byBwcm92aWRlIGNvc3QgaW5mb3JtYXRpb24uIENhbGxzIHRoYXQgYXJlIHN0aWxsIGluIGZsaWdodCBhcmVcbiAgICAgKiBub3QgaW5jbHVkZWQgaW4gdGhlIGNvc3Qgc25hcHNob3QuIEZvciB0aGlzIHJlYXNvbiwgaXQgaXMgdHlwaWNhbGx5IGFcbiAgICAgKiBnb29kIGlkZWEgdG8gZ2V0IGEgY29zdCBzbmFwc2hvdCBhZnRlciBhd2FpdGluZyB0aGUgcmVzdWx0IG9mXG4gICAgICoge0BsaW5rIEZhYXN0TW9kdWxlLmNsZWFudXB9LlxuICAgICAqXG4gICAgICogQ29kZSBleGFtcGxlOlxuICAgICAqXG4gICAgICogYGBgdHlwZXNjcmlwdFxuICAgICAqIGNvbnN0IGZhYXN0TW9kdWxlID0gYXdhaXQgZmFhc3QoXCJhd3NcIiwgbSk7XG4gICAgICogdHJ5IHtcbiAgICAgKiAgICAgLy8gaW52b2tlIGNsb3VkIGZ1bmN0aW9ucyBvbiBmYWFzdE1vZHVsZS5mdW5jdGlvbnMuKlxuICAgICAqIH0gZmluYWxseSB7XG4gICAgICogICAgICBhd2FpdCBmYWFzdE1vZHVsZS5jbGVhbnVwKCk7XG4gICAgICogICAgICBjb25zdCBjb3N0U25hcHNob3QgPSBhd2FpdCBmYWFzdE1vZHVsZS5jb3N0U25hcHNob3QoKTtcbiAgICAgKiAgICAgIGNvbnNvbGUubG9nKGNvc3RTbmFwc2hvdCk7XG4gICAgICogfVxuICAgICAqIGBgYFxuICAgICAqL1xuICAgIGNvc3RTbmFwc2hvdCgpOiBQcm9taXNlPENvc3RTbmFwc2hvdD47XG5cbiAgICAvKipcbiAgICAgKiBTdGF0aXN0aWNzIGZvciBhIHNwZWNpZmljIGZ1bmN0aW9uIG9yIHRoZSBlbnRpcmUgZmFhc3QuanMgbW9kdWxlLlxuICAgICAqXG4gICAgICogQHBhcmFtIGZ1bmN0aW9uTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBmdW5jdGlvbiB0byByZXRyaWV2ZSBzdGF0aXN0aWNzXG4gICAgICogZm9yLiBJZiB0aGUgZnVuY3Rpb24gZG9lcyBub3QgZXhpc3Qgb3IgaGFzIG5vdCBiZWVuIGludm9rZWQsIGEgbmV3XG4gICAgICogaW5zdGFuY2Ugb2Yge0BsaW5rIEZ1bmN0aW9uU3RhdHN9IGlzIHJldHVybmVkIHdpdGggemVybyB2YWx1ZXMuIElmXG4gICAgICogYGZ1bmN0aW9uTmFtZWAgb21pdHRlZCAodW5kZWZpbmVkKSwgdGhlbiBhZ2dyZWdhdGUgc3RhdGlzdGljcyBhcmVcbiAgICAgKiByZXR1cm5lZCB0aGF0IHN1bW1hcml6ZSBhbGwgY2xvdWQgZnVuY3Rpb25zIHdpdGhpbiB0aGlzIGZhYXN0LmpzIG1vZHVsZS5cbiAgICAgKiBAcmV0dXJucyBhbiBzbmFwc2hvdCBvZiB7QGxpbmsgRnVuY3Rpb25TdGF0c30gYXQgYSBwb2ludCBpbiB0aW1lLlxuICAgICAqL1xuICAgIHN0YXRzKGZ1bmN0aW9uTmFtZT86IHN0cmluZyk6IEZ1bmN0aW9uU3RhdHM7XG59XG5cbi8qKlxuICogSW1wbGVtZW50YXRpb24gb2Yge0BsaW5rIEZhYXN0TW9kdWxlfS5cbiAqIEByZW1hcmtzXG4gKiBgRmFhc3RNb2R1bGVQcm94eWAgcHJvdmlkZXMgYSB1bmlmaWVkIGRldmVsb3BlciBleHBlcmllbmNlIGZvciBmYWFzdC5qc1xuICogbW9kdWxlcyBvbiB0b3Agb2YgcHJvdmlkZXItc3BlY2lmaWMgcnVudGltZSBBUElzLiBNb3N0IHVzZXJzIHdpbGwgbm90IGNyZWF0ZVxuICogYEZhYXN0TW9kdWxlUHJveHlgIGluc3RhbmNlcyB0aGVtc2VsdmVzOyBpbnN0ZWFkIHVzZSB7QGxpbmsgZmFhc3R9LCBvclxuICoge0BsaW5rIGZhYXN0QXdzfSwge0BsaW5rIGZhYXN0R29vZ2xlfSwgb3Ige0BsaW5rIGZhYXN0TG9jYWx9LlxuICogYEZhYXN0TW9kdWxlUHJveHlgIGltcGxlbWVudHMgdGhlIHtAbGluayBGYWFzdE1vZHVsZX0gaW50ZXJmYWNlLCB3aGljaCBpcyB0aGVcbiAqIHByZWZlcnJlZCBwdWJsaWMgaW50ZXJmYWNlIGZvciBmYWFzdCBtb2R1bGVzLiBgRmFhc3RNb2R1bGVQcm94eWAgY2FuIGJlIHVzZWRcbiAqIHRvIGFjY2VzcyBwcm92aWRlci1zcGVjaWZpYyBkZXRhaWxzIGFuZCBzdGF0ZSwgYW5kIGlzIHVzZWZ1bCBmb3IgZGVlcGVyXG4gKiB0ZXN0aW5nLlxuICogQHB1YmxpY1xuICovXG5leHBvcnQgY2xhc3MgRmFhc3RNb2R1bGVQcm94eTxNIGV4dGVuZHMgb2JqZWN0LCBPLCBTPiBpbXBsZW1lbnRzIEZhYXN0TW9kdWxlPE0+IHtcbiAgICAvKiogVGhlIHtAbGluayBQcm92aWRlcn0sIGUuZy4gXCJhd3NcIiBvciBcImdvb2dsZVwiLiAqL1xuICAgIHByb3ZpZGVyID0gdGhpcy5pbXBsLm5hbWU7XG4gICAgLyoqIHtAaW5oZXJpdGRvYyBGYWFzdE1vZHVsZS5mdW5jdGlvbnN9ICovXG4gICAgZnVuY3Rpb25zOiBQcm94eU1vZHVsZTxNPjtcbiAgICAvKioge0Bpbmhlcml0ZG9jIEZhYXN0TW9kdWxlLmZ1bmN0aW9uc0RldGFpbH0gKi9cbiAgICBmdW5jdGlvbnNEZXRhaWw6IFByb3h5TW9kdWxlRGV0YWlsPE0+O1xuICAgIC8qKiBAaW50ZXJuYWwgKi9cbiAgICBwcml2YXRlIF9zdGF0cyA9IG5ldyBGdW5jdGlvblN0YXRzTWFwKCk7XG4gICAgcHJpdmF0ZSBfY3B1VXNhZ2UgPSBuZXcgRmFjdG9yeU1hcChcbiAgICAgICAgKCkgPT4gbmV3IEZhY3RvcnlNYXAoKF86IG51bWJlcikgPT4gbmV3IEZ1bmN0aW9uQ3B1VXNhZ2UoKSlcbiAgICApO1xuICAgIHByaXZhdGUgX21lbW9yeUxlYWtEZXRlY3RvcjogTWVtb3J5TGVha0RldGVjdG9yO1xuICAgIHByaXZhdGUgX2Z1bm5lbDogRnVubmVsPGFueT47XG4gICAgcHJpdmF0ZSBfcmF0ZUxpbWl0ZXI/OiBSYXRlTGltaXRlcjxhbnk+O1xuICAgIHByaXZhdGUgX3NrZXcgPSBuZXcgRXhwb25lbnRpYWxseURlY2F5aW5nQXZlcmFnZVZhbHVlKDAuMyk7XG4gICAgcHJpdmF0ZSBfc3RhdHNUaW1lcj86IE5vZGVKUy5UaW1lcjtcbiAgICBwcml2YXRlIF9jbGVhbnVwSG9va3M6IFNldDxEZWZlcnJlZD4gPSBuZXcgU2V0KCk7XG4gICAgcHJpdmF0ZSBfaW5pdGlhbEludm9jYXRpb25UaW1lID0gbmV3IEZhY3RvcnlNYXAoKCkgPT4gRGF0ZS5ub3coKSk7XG4gICAgcHJpdmF0ZSBfY2FsbFJlc3VsdHNQZW5kaW5nOiBNYXA8Q2FsbElkLCBQZW5kaW5nUmVxdWVzdD4gPSBuZXcgTWFwKCk7XG4gICAgcHJpdmF0ZSBfY29sbGVjdG9yUHVtcDogUHVtcDx2b2lkPjtcbiAgICBwcml2YXRlIF9lbWl0dGVyID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gICAgLyoqXG4gICAgICogQ29uc3RydWN0b3JcbiAgICAgKiBAaW50ZXJuYWxcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgcHJpdmF0ZSBpbXBsOiBQcm92aWRlckltcGw8TywgUz4sXG4gICAgICAgIC8qKiBAaW50ZXJuYWwgKi9cbiAgICAgICAgcmVhZG9ubHkgc3RhdGU6IFMsXG4gICAgICAgIHByaXZhdGUgZm1vZHVsZTogTSxcbiAgICAgICAgcHJpdmF0ZSBtb2R1bGVQYXRoOiBzdHJpbmcsXG4gICAgICAgIC8qKiBUaGUgb3B0aW9ucyBzZXQgZm9yIHRoaXMgaW5zdGFuY2UsIHdoaWNoIGluY2x1ZGVzIGRlZmF1bHQgdmFsdWVzLiAqL1xuICAgICAgICByZWFkb25seSBvcHRpb25zOiBSZXF1aXJlZDxDb21tb25PcHRpb25zPlxuICAgICkge1xuICAgICAgICBsb2cuaW5mbyhgTm9kZSB2ZXJzaW9uOiAke3Byb2Nlc3MudmVyc2lvbn1gKTtcbiAgICAgICAgbG9nLnByb3ZpZGVyKGBuYW1lOiAke3RoaXMuaW1wbC5uYW1lfWApO1xuICAgICAgICBsb2cucHJvdmlkZXIoYHJlc3BvbnNlUXVldWVJZDogJHt0aGlzLmltcGwucmVzcG9uc2VRdWV1ZUlkKHN0YXRlKX1gKTtcbiAgICAgICAgbG9nLnByb3ZpZGVyKGBsb2dVcmw6ICR7dGhpcy5pbXBsLmxvZ1VybChzdGF0ZSl9YCk7XG4gICAgICAgIGxvZy5pbmZvKGBMb2cgdXJsOiAke2ltcGwubG9nVXJsKHN0YXRlKX1gKTtcblxuICAgICAgICB0aGlzLl9mdW5uZWwgPSBuZXcgRnVubmVsPGFueT4ob3B0aW9ucy5jb25jdXJyZW5jeSk7XG4gICAgICAgIGlmIChvcHRpb25zLnJhdGUpIHtcbiAgICAgICAgICAgIHRoaXMuX3JhdGVMaW1pdGVyID0gbmV3IFJhdGVMaW1pdGVyKG9wdGlvbnMucmF0ZSwgMSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fbWVtb3J5TGVha0RldGVjdG9yID0gbmV3IE1lbW9yeUxlYWtEZXRlY3RvcihvcHRpb25zLm1lbW9yeVNpemUpO1xuICAgICAgICBjb25zdCBmdW5jdGlvbnNEZXRhaWw6IGFueSA9IHt9O1xuICAgICAgICBjb25zdCBmdW5jdGlvbnM6IGFueSA9IHt9O1xuICAgICAgICBmb3IgKGNvbnN0IG5hbWUgb2YgT2JqZWN0LmtleXMoZm1vZHVsZSkpIHtcbiAgICAgICAgICAgIGNvbnN0IG9yaWdGdW5jdGlvbiA9IChmbW9kdWxlIGFzIGFueSlbbmFtZV07XG4gICAgICAgICAgICBpZiAodHlwZW9mIG9yaWdGdW5jdGlvbiA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICAgICAgaWYgKGlzR2VuZXJhdG9yKG9yaWdGdW5jdGlvbikpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZnVuYyA9IHRoaXMud3JhcEdlbmVyYXRvcihvcmlnRnVuY3Rpb24pO1xuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbnNEZXRhaWxbbmFtZV0gPSBmdW5jO1xuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbnNbbmFtZV0gPSBhc3luYyBmdW5jdGlvbiogKC4uLmFyZ3M6IGFueVtdKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBnZW5lcmF0b3IgPSBmdW5jKC4uLmFyZ3MpO1xuICAgICAgICAgICAgICAgICAgICAgICAgZm9yIGF3YWl0IChjb25zdCBpdGVyIG9mIGdlbmVyYXRvcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlpZWxkIGl0ZXIudmFsdWU7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZnVuYyA9IHRoaXMud3JhcEZ1bmN0aW9uKG9yaWdGdW5jdGlvbik7XG4gICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uc0RldGFpbFtuYW1lXSA9IGZ1bmM7XG4gICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uc1tuYW1lXSA9ICguLi5hcmdzOiBhbnlbXSkgPT5cbiAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmMoLi4uYXJncykudGhlbihwID0+IHAudmFsdWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0aGlzLmZ1bmN0aW9ucyA9IGZ1bmN0aW9ucztcbiAgICAgICAgdGhpcy5mdW5jdGlvbnNEZXRhaWwgPSBmdW5jdGlvbnNEZXRhaWw7XG4gICAgICAgIHRoaXMuX2NvbGxlY3RvclB1bXAgPSBuZXcgUHVtcCh7IGNvbmN1cnJlbmN5OiAyIH0sICgpID0+IHRoaXMucmVzdWx0Q29sbGVjdG9yKCkpO1xuICAgICAgICB0aGlzLl9jb2xsZWN0b3JQdW1wLnN0YXJ0KCk7XG4gICAgfVxuXG4gICAgLyoqIHtAaW5oZXJpdGRvYyBGYWFzdE1vZHVsZS5jbGVhbnVwfSAqL1xuICAgIGFzeW5jIGNsZWFudXAodXNlckNsZWFudXBPcHRpb25zOiBDbGVhbnVwT3B0aW9ucyA9IHt9KSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICB0aGlzLl9zdGF0cy5jbGVhcigpO1xuICAgICAgICAgICAgdGhpcy5fbWVtb3J5TGVha0RldGVjdG9yLmNsZWFyKCk7XG4gICAgICAgICAgICB0aGlzLl9mdW5uZWwuY2xlYXIoKTtcbiAgICAgICAgICAgIHRoaXMuX3JhdGVMaW1pdGVyPy5jbGVhcigpO1xuICAgICAgICAgICAgdGhpcy5fY2xlYW51cEhvb2tzLmZvckVhY2goaG9vayA9PiBob29rLnJlc29sdmUoKSk7XG4gICAgICAgICAgICB0aGlzLl9jbGVhbnVwSG9va3MuY2xlYXIoKTtcbiAgICAgICAgICAgIHRoaXMuX2VtaXR0ZXIucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gICAgICAgICAgICB0aGlzLnN0b3BTdGF0cygpO1xuICAgICAgICAgICAgdGhpcy5faW5pdGlhbEludm9jYXRpb25UaW1lLmNsZWFyKCk7XG4gICAgICAgICAgICB0aGlzLl9jYWxsUmVzdWx0c1BlbmRpbmcuY2xlYXIoKTtcbiAgICAgICAgICAgIHRoaXMuX2NvbGxlY3RvclB1bXAuc3RvcCgpO1xuICAgICAgICAgICAgbG9nLnByb3ZpZGVyKGBjbGVhbnVwYCk7XG4gICAgICAgICAgICBjb25zdCBvcHRpb25zID0geyAuLi5DbGVhbnVwT3B0aW9uRGVmYXVsdHMsIC4uLnVzZXJDbGVhbnVwT3B0aW9ucyB9O1xuICAgICAgICAgICAgY29uc3QgeyBnY1RpbWVvdXQgfSA9IG9wdGlvbnM7XG4gICAgICAgICAgICBsZXQgdGltZWRvdXQgPSBmYWxzZTtcbiAgICAgICAgICAgIGlmIChnY1RpbWVvdXQgPiAwKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgdGltZW91dCA9IHNsZWVwKGdjVGltZW91dCAqIDEwMDApLnRoZW4oKCkgPT4gKHRpbWVkb3V0ID0gdHJ1ZSkpO1xuICAgICAgICAgICAgICAgIGF3YWl0IFByb21pc2UucmFjZShbdGhpcy5pbXBsLmNsZWFudXAodGhpcy5zdGF0ZSwgb3B0aW9ucyksIHRpbWVvdXRdKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5pbXBsLmNsZWFudXAodGhpcy5zdGF0ZSwgb3B0aW9ucyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodGltZWRvdXQpIHtcbiAgICAgICAgICAgICAgICBsb2cucHJvdmlkZXIoYGNsZWFudXAgdGltZWQgb3V0IGFmdGVyICR7Z2NUaW1lb3V0fXNgKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgbG9nLnByb3ZpZGVyKGBjbGVhbnVwIGRvbmVgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBGYWFzdEVycm9yKGVyciwgXCJmYWlsZWQgaW4gY2xlYW51cFwiKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKiB7QGluaGVyaXRkb2MgRmFhc3RNb2R1bGUubG9nVXJsfSAqL1xuICAgIGxvZ1VybCgpIHtcbiAgICAgICAgY29uc3QgcnYgPSB0aGlzLmltcGwubG9nVXJsKHRoaXMuc3RhdGUpO1xuICAgICAgICBsb2cucHJvdmlkZXIoYGxvZ1VybCAke3J2fWApO1xuICAgICAgICByZXR1cm4gcnY7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzdGFydFN0YXRzKGludGVydmFsOiBudW1iZXIgPSAxMDAwKSB7XG4gICAgICAgIHRoaXMuX3N0YXRzVGltZXIgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLl9zdGF0cy5mSW5jcmVtZW50YWwuZm9yRWFjaCgoc3RhdHMsIGZuKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5fZW1pdHRlci5lbWl0KFwic3RhdHNcIiwgbmV3IEZ1bmN0aW9uU3RhdHNFdmVudChmbiwgc3RhdHMpKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICB0aGlzLl9zdGF0cy5yZXNldEluY3JlbWVudGFsKCk7XG4gICAgICAgIH0sIGludGVydmFsKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHN0b3BTdGF0cygpIHtcbiAgICAgICAgdGhpcy5fc3RhdHNUaW1lciAmJiBjbGVhckludGVydmFsKHRoaXMuX3N0YXRzVGltZXIpO1xuICAgICAgICB0aGlzLl9zdGF0c1RpbWVyID0gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIC8qKiB7QGluaGVyaXRkb2MgRmFhc3RNb2R1bGUub259ICovXG4gICAgb24obmFtZTogXCJzdGF0c1wiLCBsaXN0ZW5lcjogKHN0YXRzRXZlbnQ6IEZ1bmN0aW9uU3RhdHNFdmVudCkgPT4gdm9pZCkge1xuICAgICAgICBpZiAoIXRoaXMuX3N0YXRzVGltZXIpIHtcbiAgICAgICAgICAgIHRoaXMuc3RhcnRTdGF0cygpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuX2VtaXR0ZXIub24obmFtZSwgbGlzdGVuZXIpO1xuICAgIH1cblxuICAgIC8qKiB7QGluaGVyaXRkb2MgRmFhc3RNb2R1bGUub2ZmfSAqL1xuICAgIG9mZihuYW1lOiBcInN0YXRzXCIsIGxpc3RlbmVyOiAoc3RhdHNFdmVudDogRnVuY3Rpb25TdGF0c0V2ZW50KSA9PiB2b2lkKSB7XG4gICAgICAgIHRoaXMuX2VtaXR0ZXIub2ZmKG5hbWUsIGxpc3RlbmVyKTtcbiAgICAgICAgaWYgKHRoaXMuX2VtaXR0ZXIubGlzdGVuZXJDb3VudChuYW1lKSA9PT0gMCkge1xuICAgICAgICAgICAgdGhpcy5zdG9wU3RhdHMoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgd2l0aENhbmNlbGxhdGlvbjxUPihcbiAgICAgICAgZm46IChjYW5jZWw6IFByb21pc2U8dm9pZD4pID0+IFByb21pc2U8VD5cbiAgICApOiBQcm9taXNlPFQ+IHtcbiAgICAgICAgY29uc3QgZGVmZXJyZWQgPSBuZXcgRGVmZXJyZWQoKTtcbiAgICAgICAgdGhpcy5fY2xlYW51cEhvb2tzLmFkZChkZWZlcnJlZCk7XG4gICAgICAgIGNvbnN0IHByb21pc2UgPSBmbihkZWZlcnJlZC5wcm9taXNlKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCBwcm9taXNlO1xuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgICAgdGhpcy5fY2xlYW51cEhvb2tzLmRlbGV0ZShkZWZlcnJlZCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIHByb2Nlc3NSZXNwb25zZTxSPihcbiAgICAgICAgcmV0dXJuZWQ6IEZ1bmN0aW9uUmV0dXJuV2l0aE1ldHJpY3MsXG4gICAgICAgIGZ1bmN0aW9uTmFtZTogc3RyaW5nLFxuICAgICAgICBsb2NhbFN0YXJ0VGltZTogbnVtYmVyXG4gICAgKTogUHJvbWlzZTxEZXRhaWw8Uj4+IHtcbiAgICAgICAgY29uc3QgeyByZXNwb25zZSB9ID0gcmV0dXJuZWQ7XG4gICAgICAgIGNvbnN0IHsgbG9nVXJsLCBpbnN0YW5jZUlkLCBtZW1vcnlVc2FnZSB9ID0gcmVzcG9uc2U7XG4gICAgICAgIGxldCB2YWx1ZTogUHJvbWlzZTxEZXRhaWw8Uj4+O1xuXG4gICAgICAgIGlmIChyZXNwb25zZS50eXBlID09PSBcInJlamVjdFwiKSB7XG4gICAgICAgICAgICBjb25zdCBlcnJvciA9IHJlc3BvbnNlLmlzRXJyb3JPYmplY3RcbiAgICAgICAgICAgICAgICA/IHN5bnRoZXNpemVGYWFzdEVycm9yKHtcbiAgICAgICAgICAgICAgICAgICAgICBlcnJPYmo6IHJldHVybmVkLnZhbHVlLFxuICAgICAgICAgICAgICAgICAgICAgIGxvZ1VybDogYCAke2xvZ1VybH0gYCxcbiAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbk5hbWVcbiAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgOiByZXR1cm5lZC52YWx1ZTtcbiAgICAgICAgICAgIHZhbHVlID0gUHJvbWlzZS5yZWplY3QoZXJyb3IpO1xuICAgICAgICAgICAgdmFsdWUuY2F0Y2goKF9zaWxlbmNlV2FybmluZ0xhY2tPZlN5bmNocm9ub3VzQ2F0Y2g6IGFueSkgPT4ge30pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc3QgeyBleGVjdXRpb25JZCB9ID0gcmV0dXJuZWQucmVzcG9uc2U7XG4gICAgICAgICAgICBjb25zdCBkZXRhaWwgPSB7XG4gICAgICAgICAgICAgICAgdmFsdWU6IHJldHVybmVkLnZhbHVlWzBdLFxuICAgICAgICAgICAgICAgIGxvZ1VybCxcbiAgICAgICAgICAgICAgICBleGVjdXRpb25JZCxcbiAgICAgICAgICAgICAgICBpbnN0YW5jZUlkLFxuICAgICAgICAgICAgICAgIG1lbW9yeVVzYWdlXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgdmFsdWUgPSBQcm9taXNlLnJlc29sdmUoZGV0YWlsKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCB7IGxvY2FsUmVxdWVzdFNlbnRUaW1lLCByZW1vdGVSZXNwb25zZVNlbnRUaW1lLCBsb2NhbEVuZFRpbWUgfSA9IHJldHVybmVkO1xuICAgICAgICBjb25zdCB7IHJlbW90ZUV4ZWN1dGlvblN0YXJ0VGltZSwgcmVtb3RlRXhlY3V0aW9uRW5kVGltZSB9ID0gcmVzcG9uc2U7XG4gICAgICAgIGNvbnN0IGZzdGF0cyA9IHRoaXMuX3N0YXRzO1xuICAgICAgICBpZiAocmVtb3RlRXhlY3V0aW9uU3RhcnRUaW1lICYmIHJlbW90ZUV4ZWN1dGlvbkVuZFRpbWUpIHtcbiAgICAgICAgICAgIGNvbnN0IGxvY2FsU3RhcnRMYXRlbmN5ID0gbG9jYWxSZXF1ZXN0U2VudFRpbWUgLSBsb2NhbFN0YXJ0VGltZTtcbiAgICAgICAgICAgIGNvbnN0IHJvdW5kVHJpcExhdGVuY3kgPSBsb2NhbEVuZFRpbWUgLSBsb2NhbFJlcXVlc3RTZW50VGltZTtcbiAgICAgICAgICAgIGNvbnN0IGV4ZWN1dGlvblRpbWUgPSByZW1vdGVFeGVjdXRpb25FbmRUaW1lIC0gcmVtb3RlRXhlY3V0aW9uU3RhcnRUaW1lO1xuICAgICAgICAgICAgY29uc3Qgc2VuZFJlc3BvbnNlTGF0ZW5jeSA9IE1hdGgubWF4KFxuICAgICAgICAgICAgICAgIDAsXG4gICAgICAgICAgICAgICAgKHJlbW90ZVJlc3BvbnNlU2VudFRpbWUgfHwgcmVtb3RlRXhlY3V0aW9uRW5kVGltZSkgLVxuICAgICAgICAgICAgICAgICAgICByZW1vdGVFeGVjdXRpb25FbmRUaW1lXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29uc3QgbmV0d29ya0xhdGVuY3kgPSByb3VuZFRyaXBMYXRlbmN5IC0gZXhlY3V0aW9uVGltZSAtIHNlbmRSZXNwb25zZUxhdGVuY3k7XG4gICAgICAgICAgICBjb25zdCBlc3RpbWF0ZWRSZW1vdGVTdGFydFRpbWUgPSBsb2NhbFJlcXVlc3RTZW50VGltZSArIG5ldHdvcmtMYXRlbmN5IC8gMjtcbiAgICAgICAgICAgIGNvbnN0IGVzdGltYXRlZFNrZXcgPSBlc3RpbWF0ZWRSZW1vdGVTdGFydFRpbWUgLSByZW1vdGVFeGVjdXRpb25TdGFydFRpbWU7XG4gICAgICAgICAgICBsZXQgc2tldyA9IGVzdGltYXRlZFNrZXc7XG4gICAgICAgICAgICBpZiAoZnN0YXRzLmFnZ3JlZ2F0ZS5jb21wbGV0ZWQgPiAxKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fc2tldy51cGRhdGUoc2tldyk7XG4gICAgICAgICAgICAgICAgc2tldyA9IHRoaXMuX3NrZXcudmFsdWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnN0IHJlbW90ZVN0YXJ0TGF0ZW5jeSA9IE1hdGgubWF4KFxuICAgICAgICAgICAgICAgIDEsXG4gICAgICAgICAgICAgICAgcmVtb3RlRXhlY3V0aW9uU3RhcnRUaW1lICsgc2tldyAtIGxvY2FsUmVxdWVzdFNlbnRUaW1lXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29uc3QgcmV0dXJuTGF0ZW5jeSA9IE1hdGgubWF4KFxuICAgICAgICAgICAgICAgIDEsXG4gICAgICAgICAgICAgICAgbG9jYWxFbmRUaW1lIC0gKHJlbW90ZUV4ZWN1dGlvbkVuZFRpbWUgKyBza2V3KVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGZzdGF0cy51cGRhdGUoZnVuY3Rpb25OYW1lLCBcImxvY2FsU3RhcnRMYXRlbmN5XCIsIGxvY2FsU3RhcnRMYXRlbmN5KTtcbiAgICAgICAgICAgIGZzdGF0cy51cGRhdGUoZnVuY3Rpb25OYW1lLCBcInJlbW90ZVN0YXJ0TGF0ZW5jeVwiLCByZW1vdGVTdGFydExhdGVuY3kpO1xuICAgICAgICAgICAgZnN0YXRzLnVwZGF0ZShmdW5jdGlvbk5hbWUsIFwiZXhlY3V0aW9uVGltZVwiLCBleGVjdXRpb25UaW1lKTtcbiAgICAgICAgICAgIGZzdGF0cy51cGRhdGUoZnVuY3Rpb25OYW1lLCBcInNlbmRSZXNwb25zZUxhdGVuY3lcIiwgc2VuZFJlc3BvbnNlTGF0ZW5jeSk7XG4gICAgICAgICAgICBmc3RhdHMudXBkYXRlKGZ1bmN0aW9uTmFtZSwgXCJyZXR1cm5MYXRlbmN5XCIsIHJldHVybkxhdGVuY3kpO1xuXG4gICAgICAgICAgICBjb25zdCBiaWxsZWQgPSAoZXhlY3V0aW9uVGltZSB8fCAwKSArIChzZW5kUmVzcG9uc2VMYXRlbmN5IHx8IDApO1xuICAgICAgICAgICAgY29uc3QgZXN0aW1hdGVkQmlsbGVkVGltZSA9IE1hdGgubWF4KDEwMCwgTWF0aC5jZWlsKGJpbGxlZCAvIDEwMCkgKiAxMDApO1xuICAgICAgICAgICAgZnN0YXRzLnVwZGF0ZShmdW5jdGlvbk5hbWUsIFwiZXN0aW1hdGVkQmlsbGVkVGltZVwiLCBlc3RpbWF0ZWRCaWxsZWRUaW1lKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChyZXNwb25zZS50eXBlID09PSBcInJlamVjdFwiKSB7XG4gICAgICAgICAgICBmc3RhdHMuaW5jcihmdW5jdGlvbk5hbWUsIFwiZXJyb3JzXCIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZnN0YXRzLmluY3IoZnVuY3Rpb25OYW1lLCBcImNvbXBsZXRlZFwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChpbnN0YW5jZUlkICYmIG1lbW9yeVVzYWdlKSB7XG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgdGhpcy5fbWVtb3J5TGVha0RldGVjdG9yLmRldGVjdGVkTmV3TGVhayhcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb25OYW1lLFxuICAgICAgICAgICAgICAgICAgICBpbnN0YW5jZUlkLFxuICAgICAgICAgICAgICAgICAgICBtZW1vcnlVc2FnZVxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIGxvZy5sZWFrcyhgUG9zc2libGUgbWVtb3J5IGxlYWsgZGV0ZWN0ZWQgaW4gZnVuY3Rpb24gJyR7ZnVuY3Rpb25OYW1lfScuYCk7XG4gICAgICAgICAgICAgICAgbG9nLmxlYWtzKFxuICAgICAgICAgICAgICAgICAgICBgTWVtb3J5IHVzZSBiZWZvcmUgZXhlY3V0aW9uIGxlYWtlZCBmcm9tIHByaW9yIGNhbGxzOiAlT2AsXG4gICAgICAgICAgICAgICAgICAgIG1lbW9yeVVzYWdlXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBsb2cubGVha3MoYExvZ3M6ICR7bG9nVXJsfSBgKTtcbiAgICAgICAgICAgICAgICBsb2cubGVha3MoXG4gICAgICAgICAgICAgICAgICAgIGBUaGVzZSBsb2dzIHNob3cgb25seSBvbmUgZXhhbXBsZSBmYWFzdCBjbG91ZCBmdW5jdGlvbiBpbnZvY2F0aW9uIHRoYXQgbWF5IGhhdmUgYSBsZWFrLmBcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGludm9rZShmbmFtZTogc3RyaW5nLCBhcmdzOiBhbnlbXSwgY2FsbElkOiBzdHJpbmcpIHtcbiAgICAgICAgY29uc3QgUmVzcG9uc2VRdWV1ZUlkID0gdGhpcy5pbXBsLnJlc3BvbnNlUXVldWVJZCh0aGlzLnN0YXRlKTtcbiAgICAgICAgY29uc3QgY2FsbE9iamVjdDogRnVuY3Rpb25DYWxsID0ge1xuICAgICAgICAgICAgbmFtZTogZm5hbWUsXG4gICAgICAgICAgICBhcmdzOiBzZXJpYWxpemVGdW5jdGlvbkFyZ3MoZm5hbWUsIGFyZ3MsIHRoaXMub3B0aW9ucy52YWxpZGF0ZVNlcmlhbGl6YXRpb24pLFxuICAgICAgICAgICAgY2FsbElkLFxuICAgICAgICAgICAgbW9kdWxlUGF0aDogdGhpcy5tb2R1bGVQYXRoLFxuICAgICAgICAgICAgUmVzcG9uc2VRdWV1ZUlkXG4gICAgICAgIH07XG5cbiAgICAgICAgbG9nLmNhbGxzKGBDYWxsaW5nICcke2ZuYW1lfScgKCR7Y2FsbElkfSlgKTtcbiAgICAgICAgY29uc3QgcGVuZGluZyA9IG5ldyBQZW5kaW5nUmVxdWVzdChjYWxsT2JqZWN0KTtcbiAgICAgICAgdGhpcy5fY2FsbFJlc3VsdHNQZW5kaW5nLnNldChjYWxsSWQsIHBlbmRpbmcpO1xuICAgICAgICBpZiAodGhpcy5fY29sbGVjdG9yUHVtcC5zdG9wcGVkKSB7XG4gICAgICAgICAgICB0aGlzLl9jb2xsZWN0b3JQdW1wLnN0YXJ0KCk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLndpdGhDYW5jZWxsYXRpb24oYXN5bmMgY2FuY2VsID0+IHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuaW1wbC5pbnZva2UodGhpcy5zdGF0ZSwgcGVuZGluZy5jYWxsLCBjYW5jZWwpLmNhdGNoKGVyciA9PlxuICAgICAgICAgICAgICAgIHBlbmRpbmcucXVldWUucHVzaEltbWVkaWF0ZSh7XG4gICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBraW5kOiBcInByb21pc2VcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6IFwicmVqZWN0XCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBjYWxsSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICBpc0Vycm9yT2JqZWN0OiB0eXBlb2YgZXJyID09PSBcIm9iamVjdFwiICYmIGVyciBpbnN0YW5jZW9mIEVycm9yLFxuICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU6IHNlcmlhbGl6ZShlcnIpXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlOiBlcnIsXG4gICAgICAgICAgICAgICAgICAgIGxvY2FsRW5kVGltZTogRGF0ZS5ub3coKSxcbiAgICAgICAgICAgICAgICAgICAgbG9jYWxSZXF1ZXN0U2VudFRpbWU6IHBlbmRpbmcuY3JlYXRlZFxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICApO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIHBlbmRpbmc7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBsb29rdXBGbmFtZShmbjogRnVuY3Rpb24pIHtcbiAgICAgICAgbGV0IGZuYW1lID0gZm4ubmFtZTtcbiAgICAgICAgaWYgKCFmbmFtZSkge1xuICAgICAgICAgICAgZm9yIChjb25zdCBrZXkgb2YgT2JqZWN0LmtleXModGhpcy5mbW9kdWxlKSkge1xuICAgICAgICAgICAgICAgIGlmICgodGhpcy5mbW9kdWxlIGFzIGFueSlba2V5XSA9PT0gZm4pIHtcbiAgICAgICAgICAgICAgICAgICAgZm5hbWUgPSBrZXk7XG4gICAgICAgICAgICAgICAgICAgIGxvZy5pbmZvKGBGb3VuZCBhcnJvdyBmdW5jdGlvbiBuYW1lOiAke2tleX1gKTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmICghZm5hbWUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBGYWFzdEVycm9yKGBDb3VsZCBub3QgZmluZCBmdW5jdGlvbiBuYW1lYCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZuYW1lO1xuICAgIH1cblxuICAgIHByaXZhdGUgY3JlYXRlQ2FsbElkKCkge1xuICAgICAgICByZXR1cm4gdXVpZHY0KCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSB3cmFwR2VuZXJhdG9yPEEgZXh0ZW5kcyBhbnlbXSwgUj4oXG4gICAgICAgIGZuOiAoKC4uLmFyZ3M6IEEpID0+IEFzeW5jR2VuZXJhdG9yPFI+KSB8ICgoLi4uYXJnczogQSkgPT4gR2VuZXJhdG9yPFI+KVxuICAgICk6ICguLi5hcmdzOiBBKSA9PiBBc3luY0l0ZXJhYmxlSXRlcmF0b3I8RGV0YWlsPFI+PiB7XG4gICAgICAgIHJldHVybiAoLi4uYXJnczogQSkgPT4ge1xuICAgICAgICAgICAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICAgIGxldCBmbmFtZSA9IHRoaXMubG9va3VwRm5hbWUoZm4pO1xuICAgICAgICAgICAgY29uc3QgY2FsbElkID0gdGhpcy5jcmVhdGVDYWxsSWQoKTtcbiAgICAgICAgICAgIGNvbnN0IHBlbmRpbmcgPSB0aGlzLmludm9rZShmbmFtZSwgYXJncywgY2FsbElkKTtcbiAgICAgICAgICAgIGxvZy5wcm92aWRlcihgaW52b2tlICR7aW5zcGVjdFByb3ZpZGVyKHBlbmRpbmcuY2FsbCl9YCk7XG4gICAgICAgICAgICB0aGlzLl9zdGF0cy5pbmNyKGZuYW1lLCBcImludm9jYXRpb25zXCIpO1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBbU3ltYm9sLmFzeW5jSXRlcmF0b3JdKCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIG5leHQ6ICgpID0+XG4gICAgICAgICAgICAgICAgICAgIHBlbmRpbmcucXVldWUubmV4dCgpLnRoZW4oYXN5bmMgbmV4dCA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBwcm9taXNlID0gdGhpcy5wcm9jZXNzUmVzcG9uc2U8SXRlcmF0b3JZaWVsZFJlc3VsdDxSPj4oXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV4dCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydFRpbWVcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwcm9taXNlO1xuICAgICAgICAgICAgICAgICAgICAgICAgbG9nLmNhbGxzKGB5aWVsZGVkICR7aW5zcGVjdChyZXN1bHQpfWApO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgeyB2YWx1ZSwgLi4ucmVzdCB9ID0gcmVzdWx0O1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3VsdC52YWx1ZS5kb25lKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jbGVhclBlbmRpbmcoY2FsbElkKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4geyBkb25lOiB0cnVlLCB2YWx1ZTogcmVzdCB9O1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb25lOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU6IHsgLi4ucmVzdCwgdmFsdWU6IHZhbHVlLnZhbHVlIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGNsZWFyUGVuZGluZyhjYWxsSWQ6IHN0cmluZykge1xuICAgICAgICB0aGlzLl9jYWxsUmVzdWx0c1BlbmRpbmcuZGVsZXRlKGNhbGxJZCk7XG4gICAgICAgIGlmICh0aGlzLl9jYWxsUmVzdWx0c1BlbmRpbmcuc2l6ZSA9PT0gMCkge1xuICAgICAgICAgICAgdGhpcy5fY29sbGVjdG9yUHVtcC5zdG9wKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIHdyYXBGdW5jdGlvbjxBIGV4dGVuZHMgYW55W10sIFI+KFxuICAgICAgICBmbjogKC4uLmFyZ3M6IEEpID0+IFJcbiAgICApOiAoLi4uYXJnczogQSkgPT4gQXN5bmM8RGV0YWlsPFI+PiB7XG4gICAgICAgIHJldHVybiAoLi4uYXJnczogQSkgPT4ge1xuICAgICAgICAgICAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICAgIGxldCBmbmFtZSA9IHRoaXMubG9va3VwRm5hbWUoZm4pO1xuICAgICAgICAgICAgY29uc3QgY2FsbElkID0gdGhpcy5jcmVhdGVDYWxsSWQoKTtcbiAgICAgICAgICAgIGNvbnN0IHRyeUludm9rZSA9IGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBwZW5kaW5nID0gdGhpcy5pbnZva2UoZm5hbWUsIGFyZ3MsIGNhbGxJZCk7XG4gICAgICAgICAgICAgICAgbG9nLnByb3ZpZGVyKGBpbnZva2UgJHtpbnNwZWN0UHJvdmlkZXIocGVuZGluZy5jYWxsKX1gKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9zdGF0cy5pbmNyKGZuYW1lLCBcImludm9jYXRpb25zXCIpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHJlc3BvbnNlUHJvbWlzZSA9IHBlbmRpbmcucXVldWUubmV4dCgpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHJ2ID0gYXdhaXQgcmVzcG9uc2VQcm9taXNlO1xuICAgICAgICAgICAgICAgIHRoaXMuY2xlYXJQZW5kaW5nKGNhbGxJZCk7XG4gICAgICAgICAgICAgICAgbG9nLmNhbGxzKGBSZXR1cm5pbmcgJyR7Zm5hbWV9JyAoJHtjYWxsSWR9KTogJHtpbnNwZWN0KHJ2KX1gKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5wcm9jZXNzUmVzcG9uc2U8Uj4ocnYsIGZuYW1lLCBzdGFydFRpbWUpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgY29uc3QgZnVubmVsID0gdGhpcy5fZnVubmVsO1xuXG4gICAgICAgICAgICBsZXQgcmV0cmllcyA9IDA7XG4gICAgICAgICAgICBjb25zdCBzaG91bGRSZXRyeSA9IChlcnI6IGFueSkgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChlcnIgaW5zdGFuY2VvZiBGYWFzdEVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChGYWFzdEVycm9yLmhhc0NhdXNlV2l0aE5hbWUoZXJyLCBGYWFzdEVycm9yTmFtZXMuRVNFUklBTElaRSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAvLyBEb24ndCByZXRyeSB1c2VyLWdlbmVyYXRlZCBlcnJvcnMuIE9ubHkgZXJyb3JzIGNhdXNlZCBieVxuICAgICAgICAgICAgICAgICAgICAvLyBmYWlsdXJlcyBvZiBvcGVyYXRpb25zIGZhYXN0IGl0c2VsZiBpbml0aWF0ZWQgKGUuZy4gY2xvdWRcbiAgICAgICAgICAgICAgICAgICAgLy8gc2VydmljZSBBUElzKSBhcmUgcmV0cmllZC5cbiAgICAgICAgICAgICAgICAgICAgaWYgKEZhYXN0RXJyb3IuaGFzQ2F1c2VXaXRoTmFtZShlcnIsIEZhYXN0RXJyb3JOYW1lcy5FRVhDRVBUSU9OKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChyZXRyaWVzIDwgdGhpcy5vcHRpb25zLm1heFJldHJpZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0cmllcysrO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl9zdGF0cy5pbmNyKGZuYW1lLCBcInJldHJpZXNcIik7XG4gICAgICAgICAgICAgICAgICAgIGxvZy5pbmZvKFxuICAgICAgICAgICAgICAgICAgICAgICAgYGZhYXN0OiBmdW5jOiAke2ZuYW1lfSBhdHRlbXB0czogJHtyZXRyaWVzfSwgZXJyOiAke2luc3BlY3RQcm92aWRlcihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJcbiAgICAgICAgICAgICAgICAgICAgICAgICl9YFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKHRoaXMuX3JhdGVMaW1pdGVyKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZ1bm5lbC5wdXNoKFxuICAgICAgICAgICAgICAgICAgICAoKSA9PiB0aGlzLl9yYXRlTGltaXRlciEucHVzaCh0cnlJbnZva2UpLFxuICAgICAgICAgICAgICAgICAgICBzaG91bGRSZXRyeVxuICAgICAgICAgICAgICAgICkgYXMgQXN5bmM8RGV0YWlsPFI+PjtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZ1bm5lbC5wdXNoKHRyeUludm9rZSwgc2hvdWxkUmV0cnkpIGFzIEFzeW5jPERldGFpbDxSPj47XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgLyoqIHtAaW5oZXJpdGRvYyBGYWFzdE1vZHVsZS5jb3N0U25hcHNob3R9ICovXG4gICAgYXN5bmMgY29zdFNuYXBzaG90KCkge1xuICAgICAgICBjb25zdCBlc3RpbWF0ZSA9IGF3YWl0IHRoaXMuaW1wbC5jb3N0U25hcHNob3QodGhpcy5zdGF0ZSwgdGhpcy5fc3RhdHMuYWdncmVnYXRlKTtcbiAgICAgICAgbG9nLnByb3ZpZGVyKGBjb3N0U25hcHNob3QgcmV0dXJuZWQgJHtpbnNwZWN0UHJvdmlkZXIoZXN0aW1hdGUpfWApO1xuICAgICAgICBpZiAodGhpcy5fc3RhdHMuYWdncmVnYXRlLnJldHJpZXMgPiAwKSB7XG4gICAgICAgICAgICBjb25zdCB7IHJldHJpZXMsIGludm9jYXRpb25zIH0gPSB0aGlzLl9zdGF0cy5hZ2dyZWdhdGU7XG4gICAgICAgICAgICBjb25zdCByZXRyeVBjdCA9ICgocmV0cmllcyAvIGludm9jYXRpb25zKSAqIDEwMCkudG9GaXhlZCgxKTtcbiAgICAgICAgICAgIGVzdGltYXRlLnB1c2goXG4gICAgICAgICAgICAgICAgbmV3IENvc3RNZXRyaWMoe1xuICAgICAgICAgICAgICAgICAgICBuYW1lOiBcInJldHJpZXNcIixcbiAgICAgICAgICAgICAgICAgICAgcHJpY2luZzogMCxcbiAgICAgICAgICAgICAgICAgICAgbWVhc3VyZWQ6IHJldHJpZXMsXG4gICAgICAgICAgICAgICAgICAgIHVuaXQ6IFwicmV0cnlcIixcbiAgICAgICAgICAgICAgICAgICAgdW5pdFBsdXJhbDogXCJyZXRyaWVzXCIsXG4gICAgICAgICAgICAgICAgICAgIGNvbW1lbnQ6IGBSZXRyaWVzIHdlcmUgJHtyZXRyeVBjdH0lIG9mIHJlcXVlc3RzIGFuZCBtYXkgaGF2ZSBpbmN1cnJlZCBjaGFyZ2VzIG5vdCBhY2NvdW50ZWQgZm9yIGJ5IGZhYXN0LmAsXG4gICAgICAgICAgICAgICAgICAgIGluZm9ybWF0aW9uYWxPbmx5OiB0cnVlXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGVzdGltYXRlO1xuICAgIH1cblxuICAgIC8qKiB7QGluaGVyaXRkb2MgRmFhc3RNb2R1bGUuc3RhdHN9ICovXG4gICAgc3RhdHMoZnVuY3Rpb25OYW1lPzogc3RyaW5nKSB7XG4gICAgICAgIGlmIChmdW5jdGlvbk5hbWUpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9zdGF0cy5mQWdncmVnYXRlLmdldE9yQ3JlYXRlKGZ1bmN0aW9uTmFtZSkuY2xvbmUoKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5fc3RhdHMuYWdncmVnYXRlLmNsb25lKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyByZXN1bHRDb2xsZWN0b3IoKSB7XG4gICAgICAgIGNvbnN0IHsgX2NhbGxSZXN1bHRzUGVuZGluZzogY2FsbFJlc3VsdHNQZW5kaW5nIH0gPSB0aGlzO1xuICAgICAgICBpZiAoIWNhbGxSZXN1bHRzUGVuZGluZy5zaXplKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBsb2cucHJvdmlkZXIoYHBvbGxpbmcgJHt0aGlzLmltcGwucmVzcG9uc2VRdWV1ZUlkKHRoaXMuc3RhdGUpfWApO1xuICAgICAgICBjb25zdCBwb2xsUmVzdWx0ID0gYXdhaXQgdGhpcy53aXRoQ2FuY2VsbGF0aW9uKGNhbmNlbCA9PlxuICAgICAgICAgICAgdGhpcy5pbXBsLnBvbGwodGhpcy5zdGF0ZSwgY2FuY2VsKVxuICAgICAgICApO1xuICAgICAgICBsb2cucHJvdmlkZXIoYHBvbGwgcmV0dXJuZWQgJHtpbnNwZWN0UHJvdmlkZXIocG9sbFJlc3VsdCl9YCk7XG4gICAgICAgIGNvbnN0IHsgTWVzc2FnZXMsIGlzRnVsbE1lc3NhZ2VCYXRjaCB9ID0gcG9sbFJlc3VsdDtcbiAgICAgICAgY29uc3QgbG9jYWxFbmRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICAgICAgdGhpcy5hZGp1c3RDb2xsZWN0b3JDb25jdXJyZW5jeUxldmVsKGlzRnVsbE1lc3NhZ2VCYXRjaCk7XG5cbiAgICAgICAgZm9yIChjb25zdCBtIG9mIE1lc3NhZ2VzKSB7XG4gICAgICAgICAgICBzd2l0Y2ggKG0ua2luZCkge1xuICAgICAgICAgICAgICAgIGNhc2UgXCJmdW5jdGlvbnN0YXJ0ZWRcIjoge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBwZW5kaW5nID0gY2FsbFJlc3VsdHNQZW5kaW5nLmdldChtLmNhbGxJZCk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChwZW5kaW5nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBwZW5kaW5nIS5leGVjdXRpbmcgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjYXNlIFwicHJvbWlzZVwiOlxuICAgICAgICAgICAgICAgIGNhc2UgXCJpdGVyYXRvclwiOlxuICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgeyB0aW1lc3RhbXAgfSA9IG07XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB2YWx1ZSA9IGRlc2VyaWFsaXplKG0udmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcGVuZGluZyA9IGNhbGxSZXN1bHRzUGVuZGluZy5nZXQobS5jYWxsSWQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBlbmRpbmcpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBydjogRnVuY3Rpb25SZXR1cm5XaXRoTWV0cmljcyA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2U6IG0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZW1vdGVSZXNwb25zZVNlbnRUaW1lOiB0aW1lc3RhbXAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvY2FsUmVxdWVzdFNlbnRUaW1lOiBwZW5kaW5nLmNyZWF0ZWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvY2FsRW5kVGltZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nLnByb3ZpZGVyKGByZXR1cm5lZCAke2luc3BlY3RQcm92aWRlcih2YWx1ZSl9YCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG0ua2luZCA9PT0gXCJpdGVyYXRvclwiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlbmRpbmcucXVldWUucHVzaChydiwgbS5zZXF1ZW5jZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGVuZGluZy5xdWV1ZS5wdXNoSW1tZWRpYXRlKHJ2KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZy5pbmZvKGBQZW5kaW5nIHByb21pc2Ugbm90IGZvdW5kIGZvciBDYWxsSWQ6ICR7bS5jYWxsSWR9YCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBsb2cud2FybihlcnIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgXCJjcHVtZXRyaWNzXCI6XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHsgbWV0cmljcyB9ID0gbTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcGVuZGluZyA9IGNhbGxSZXN1bHRzUGVuZGluZy5nZXQobS5jYWxsSWQpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoIXBlbmRpbmcpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBjb25zdCBzdGF0cyA9IHRoaXMuX2NwdVVzYWdlLmdldE9yQ3JlYXRlKHBlbmRpbmcuY2FsbC5uYW1lKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3Qgc2Vjb25kTWV0cmljcyA9IHN0YXRzLmdldE9yQ3JlYXRlKFxuICAgICAgICAgICAgICAgICAgICAgICAgTWF0aC5yb3VuZChtZXRyaWNzLmVsYXBzZWQgLyAxMDAwKVxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICBzZWNvbmRNZXRyaWNzLnN0aW1lLnVwZGF0ZShtZXRyaWNzLnN0aW1lKTtcbiAgICAgICAgICAgICAgICAgICAgc2Vjb25kTWV0cmljcy51dGltZS51cGRhdGUobWV0cmljcy51dGltZSk7XG4gICAgICAgICAgICAgICAgICAgIHNlY29uZE1ldHJpY3MuY3B1VGltZS51cGRhdGUobWV0cmljcy5zdGltZSArIG1ldHJpY3MudXRpbWUpO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgYWRqdXN0Q29sbGVjdG9yQ29uY3VycmVuY3lMZXZlbChmdWxsPzogYm9vbGVhbikge1xuICAgICAgICBjb25zdCBuUGVuZGluZyA9IHRoaXMuX2NhbGxSZXN1bHRzUGVuZGluZy5zaXplO1xuICAgICAgICBpZiAoblBlbmRpbmcgPiAwKSB7XG4gICAgICAgICAgICBsZXQgbkNvbGxlY3RvcnMgPSBmdWxsID8gTWF0aC5mbG9vcihuUGVuZGluZyAvIDIwKSArIDIgOiAyO1xuICAgICAgICAgICAgbkNvbGxlY3RvcnMgPSBNYXRoLm1pbihuQ29sbGVjdG9ycywgMTApO1xuICAgICAgICAgICAgY29uc3QgcHVtcCA9IHRoaXMuX2NvbGxlY3RvclB1bXA7XG4gICAgICAgICAgICBjb25zdCBwcmV2aW91cyA9IHB1bXAuY29uY3VycmVuY3k7XG4gICAgICAgICAgICBwdW1wLnNldE1heENvbmN1cnJlbmN5KG5Db2xsZWN0b3JzKTtcbiAgICAgICAgICAgIGlmIChwcmV2aW91cyAhPT0gcHVtcC5jb25jdXJyZW5jeSkge1xuICAgICAgICAgICAgICAgIGxvZy5pbmZvKFxuICAgICAgICAgICAgICAgICAgICBgUmVzdWx0IGNvbGxlY3RvcnMgcnVubmluZzogJHtwdW1wLmdldENvbmN1cnJlbmN5KCl9LCBuZXcgbWF4OiAke1xuICAgICAgICAgICAgICAgICAgICAgICAgcHVtcC5jb25jdXJyZW5jeVxuICAgICAgICAgICAgICAgICAgICB9YFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59XG5cbi8qKlxuICogVGhlIHJldHVybiB0eXBlIG9mIHtAbGluayBmYWFzdEF3c30uIFNlZSB7QGxpbmsgRmFhc3RNb2R1bGVQcm94eX0uXG4gKiBAcHVibGljXG4gKi9cbmV4cG9ydCB0eXBlIEF3c0ZhYXN0TW9kdWxlPE0gZXh0ZW5kcyBvYmplY3QgPSBvYmplY3Q+ID0gRmFhc3RNb2R1bGVQcm94eTxcbiAgICBNLFxuICAgIEF3c09wdGlvbnMsXG4gICAgQXdzU3RhdGVcbj47XG5cbi8qKlxuICogVGhlIHJldHVybiB0eXBlIG9mIHtAbGluayBmYWFzdEdvb2dsZX0uIFNlZSB7QGxpbmsgRmFhc3RNb2R1bGVQcm94eX0uXG4gKiBAcHVibGljXG4gKi9cbmV4cG9ydCB0eXBlIEdvb2dsZUZhYXN0TW9kdWxlPE0gZXh0ZW5kcyBvYmplY3QgPSBvYmplY3Q+ID0gRmFhc3RNb2R1bGVQcm94eTxcbiAgICBNLFxuICAgIEdvb2dsZU9wdGlvbnMsXG4gICAgR29vZ2xlU3RhdGVcbj47XG5cbi8qKlxuICogVGhlIHJldHVybiB0eXBlIG9mIHtAbGluayBmYWFzdExvY2FsfS4gU2VlIHtAbGluayBGYWFzdE1vZHVsZVByb3h5fS5cbiAqIEBwdWJsaWNcbiAqL1xuZXhwb3J0IHR5cGUgTG9jYWxGYWFzdE1vZHVsZTxNIGV4dGVuZHMgb2JqZWN0ID0gb2JqZWN0PiA9IEZhYXN0TW9kdWxlUHJveHk8XG4gICAgTSxcbiAgICBMb2NhbE9wdGlvbnMsXG4gICAgTG9jYWxTdGF0ZVxuPjtcblxuZnVuY3Rpb24gcmVzb2x2ZShmbW9kdWxlOiBvYmplY3QpIHtcbiAgICBjb25zdCBjYWNoZSA9IChNb2R1bGUgYXMgYW55KS5fY2FjaGU7XG4gICAgbGV0IG1vZHVsZVBhdGg6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhjYWNoZSkucmV2ZXJzZSgpKSB7XG4gICAgICAgIGlmIChjYWNoZVtrZXldLmV4cG9ydHMgPT09IGZtb2R1bGUpIHtcbiAgICAgICAgICAgIG1vZHVsZVBhdGggPSBrZXk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgIH1cbiAgICBpZiAoIW1vZHVsZVBhdGgpIHtcbiAgICAgICAgdGhyb3cgbmV3IEZhYXN0RXJyb3IoXG4gICAgICAgICAgICB7IGluZm86IHsgbW9kdWxlOiBmbW9kdWxlIH0gfSxcbiAgICAgICAgICAgIGBDb3VsZCBub3QgZmluZCBmaWxlIGZvciBtb2R1bGUsIG11c3QgdXNlIFwiaW1wb3J0ICogYXMgWCBmcm9tIFlcIiBvciBcIlggPSByZXF1aXJlKFkpXCIgdG8gbG9hZCBhIG1vZHVsZSBmb3IgZmFhc3QuYFxuICAgICAgICApO1xuICAgIH1cbiAgICBsb2cuaW5mbyhgRm91bmQgZmlsZTogJHttb2R1bGVQYXRofWApO1xuICAgIHJldHVybiBtb2R1bGVQYXRoO1xufVxuXG4vKipcbiAqIFRoZSBtYWluIGVudHJ5IHBvaW50IGZvciBmYWFzdCB3aXRoIGFueSBwcm92aWRlciBhbmQgb25seSBjb21tb24gb3B0aW9ucy5cbiAqIEBwYXJhbSBwcm92aWRlciAtIE9uZSBvZiBgXCJhd3NcImAsIGBcImdvb2dsZVwiYCwgb3IgYFwibG9jYWxcImAuIFNlZVxuICoge0BsaW5rIFByb3ZpZGVyfS5cbiAqIEBwYXJhbSBmbW9kdWxlIC0gQSBtb2R1bGUgaW1wb3J0ZWQgd2l0aCBgaW1wb3J0ICogYXMgWCBmcm9tIFwiWVwiO2AuIFVzaW5nXG4gKiBgcmVxdWlyZWAgYWxzbyB3b3JrcyBidXQgbG9zZXMgdHlwZSBpbmZvcm1hdGlvbi5cbiAqIEBwYXJhbSBvcHRpb25zIC0gU2VlIHtAbGluayBDb21tb25PcHRpb25zfS5cbiAqIEByZXR1cm5zIFNlZSB7QGxpbmsgRmFhc3RNb2R1bGV9LlxuICogQHJlbWFya3NcbiAqIEV4YW1wbGUgb2YgdXNhZ2U6XG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBmYWFzdCB9IGZyb20gXCJmYWFzdGpzXCI7XG4gKiBpbXBvcnQgKiBhcyBtb2QgZnJvbSBcIi4vcGF0aC90by9tb2R1bGVcIjtcbiAqIChhc3luYyAoKSA9PiB7XG4gKiAgICAgY29uc3QgZmFhc3RNb2R1bGUgPSBhd2FpdCBmYWFzdChcImF3c1wiLCBtb2QpO1xuICogICAgIHRyeSB7XG4gKiAgICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGZhYXN0TW9kdWxlLmZ1bmN0aW9ucy5mdW5jKFwiYXJnXCIpO1xuICogICAgIH0gZmluYWxseSB7XG4gKiAgICAgICAgIGF3YWl0IGZhYXN0TW9kdWxlLmNsZWFudXAoKTtcbiAqICAgICB9XG4gKiB9KSgpO1xuICogYGBgXG4gKiBAcHVibGljXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmYWFzdDxNIGV4dGVuZHMgb2JqZWN0PihcbiAgICBwcm92aWRlcjogUHJvdmlkZXIsXG4gICAgZm1vZHVsZTogTSxcbiAgICBvcHRpb25zPzogQ29tbW9uT3B0aW9uc1xuKTogUHJvbWlzZTxGYWFzdE1vZHVsZTxNPj4ge1xuICAgIHN3aXRjaCAocHJvdmlkZXIpIHtcbiAgICAgICAgY2FzZSBcImF3c1wiOlxuICAgICAgICAgICAgcmV0dXJuIGZhYXN0QXdzKGZtb2R1bGUsIG9wdGlvbnMpO1xuICAgICAgICBjYXNlIFwiZ29vZ2xlXCI6XG4gICAgICAgICAgICByZXR1cm4gZmFhc3RHb29nbGUoZm1vZHVsZSwgb3B0aW9ucyk7XG4gICAgICAgIGNhc2UgXCJsb2NhbFwiOlxuICAgICAgICAgICAgcmV0dXJuIGZhYXN0TG9jYWwoZm1vZHVsZSwgb3B0aW9ucyk7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICB0aHJvdyBuZXcgRmFhc3RFcnJvcihgVW5rbm93biBjbG91ZCBwcm92aWRlciBvcHRpb24gJyR7cHJvdmlkZXJ9J2ApO1xuICAgIH1cbn1cblxuLyoqXG4gKiBUaGUgbWFpbiBlbnRyeSBwb2ludCBmb3IgZmFhc3Qgd2l0aCBBV1MgcHJvdmlkZXIuXG4gKiBAcGFyYW0gZm1vZHVsZSAtIEEgbW9kdWxlIGltcG9ydGVkIHdpdGggYGltcG9ydCAqIGFzIFggZnJvbSBcIllcIjtgLiBVc2luZ1xuICogYHJlcXVpcmVgIGFsc28gd29ya3MgYnV0IGxvc2VzIHR5cGUgaW5mb3JtYXRpb24uXG4gKiBAcGFyYW0gb3B0aW9ucyAtIE1vc3QgY29tbW9uIG9wdGlvbnMgYXJlIGluIHtAbGluayBDb21tb25PcHRpb25zfS5cbiAqIEFkZGl0aW9uYWwgQVdTLXNwZWNpZmljIG9wdGlvbnMgYXJlIGluIHtAbGluayBBd3NPcHRpb25zfS5cbiAqIEBwdWJsaWNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZhYXN0QXdzPE0gZXh0ZW5kcyBvYmplY3Q+KFxuICAgIGZtb2R1bGU6IE0sXG4gICAgb3B0aW9ucz86IEF3c09wdGlvbnNcbik6IFByb21pc2U8QXdzRmFhc3RNb2R1bGU8TT4+IHtcbiAgICByZXR1cm4gY3JlYXRlRmFhc3RNb2R1bGVQcm94eTxNLCBBd3NPcHRpb25zLCBBd3NTdGF0ZT4oQXdzSW1wbCwgZm1vZHVsZSwgb3B0aW9ucyk7XG59XG5cbi8qKlxuICogVGhlIG1haW4gZW50cnkgcG9pbnQgZm9yIGZhYXN0IHdpdGggR29vZ2xlIHByb3ZpZGVyLlxuICogQHBhcmFtIGZtb2R1bGUgLSBBIG1vZHVsZSBpbXBvcnRlZCB3aXRoIGBpbXBvcnQgKiBhcyBYIGZyb20gXCJZXCI7YC4gVXNpbmdcbiAqIGByZXF1aXJlYCBhbHNvIHdvcmtzIGJ1dCBsb3NlcyB0eXBlIGluZm9ybWF0aW9uLlxuICogQHBhcmFtIG9wdGlvbnMgLSBNb3N0IGNvbW1vbiBvcHRpb25zIGFyZSBpbiB7QGxpbmsgQ29tbW9uT3B0aW9uc30uXG4gKiBBZGRpdGlvbmFsIEdvb2dsZS1zcGVjaWZpYyBvcHRpb25zIGFyZSBpbiB7QGxpbmsgR29vZ2xlT3B0aW9uc30uXG4gKiBAcHVibGljXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmYWFzdEdvb2dsZTxNIGV4dGVuZHMgb2JqZWN0PihcbiAgICBmbW9kdWxlOiBNLFxuICAgIG9wdGlvbnM/OiBHb29nbGVPcHRpb25zXG4pOiBQcm9taXNlPEdvb2dsZUZhYXN0TW9kdWxlPE0+PiB7XG4gICAgcmV0dXJuIGNyZWF0ZUZhYXN0TW9kdWxlUHJveHk8TSwgR29vZ2xlT3B0aW9ucywgR29vZ2xlU3RhdGU+KFxuICAgICAgICBHb29nbGVJbXBsLFxuICAgICAgICBmbW9kdWxlLFxuICAgICAgICBvcHRpb25zXG4gICAgKTtcbn1cblxuLyoqXG4gKiBUaGUgbWFpbiBlbnRyeSBwb2ludCBmb3IgZmFhc3Qgd2l0aCBMb2NhbCBwcm92aWRlci5cbiAqIEBwYXJhbSBmbW9kdWxlIC0gQSBtb2R1bGUgaW1wb3J0ZWQgd2l0aCBgaW1wb3J0ICogYXMgWCBmcm9tIFwiWVwiO2AuIFVzaW5nXG4gKiBgcmVxdWlyZWAgYWxzbyB3b3JrcyBidXQgbG9zZXMgdHlwZSBpbmZvcm1hdGlvbi5cbiAqIEBwYXJhbSBvcHRpb25zIC0gTW9zdCBjb21tb24gb3B0aW9ucyBhcmUgaW4ge0BsaW5rIENvbW1vbk9wdGlvbnN9LlxuICogQWRkaXRpb25hbCBMb2NhbC1zcGVjaWZpYyBvcHRpb25zIGFyZSBpbiB7QGxpbmsgTG9jYWxPcHRpb25zfS5cbiAqIEByZXR1cm5zIGEgUHJvbWlzZSBmb3Ige0BsaW5rIExvY2FsRmFhc3RNb2R1bGV9LlxuICogQHB1YmxpY1xuICovXG5leHBvcnQgZnVuY3Rpb24gZmFhc3RMb2NhbDxNIGV4dGVuZHMgb2JqZWN0PihcbiAgICBmbW9kdWxlOiBNLFxuICAgIG9wdGlvbnM/OiBMb2NhbE9wdGlvbnNcbik6IFByb21pc2U8TG9jYWxGYWFzdE1vZHVsZTxNPj4ge1xuICAgIHJldHVybiBjcmVhdGVGYWFzdE1vZHVsZVByb3h5PE0sIExvY2FsT3B0aW9ucywgTG9jYWxTdGF0ZT4oXG4gICAgICAgIExvY2FsSW1wbCxcbiAgICAgICAgZm1vZHVsZSxcbiAgICAgICAgb3B0aW9uc1xuICAgICk7XG59XG5cbmZ1bmN0aW9uIGVzdGltYXRlRnVuY3Rpb25MYXRlbmN5KGZuU3RhdHM6IEZ1bmN0aW9uU3RhdHMpIHtcbiAgICBjb25zdCB7IGV4ZWN1dGlvblRpbWUsIGxvY2FsU3RhcnRMYXRlbmN5LCByZW1vdGVTdGFydExhdGVuY3ksIHJldHVybkxhdGVuY3kgfSA9XG4gICAgICAgIGZuU3RhdHM7XG5cbiAgICByZXR1cm4gKFxuICAgICAgICBsb2NhbFN0YXJ0TGF0ZW5jeS5tZWFuICtcbiAgICAgICAgICAgIHJlbW90ZVN0YXJ0TGF0ZW5jeS5tZWFuICtcbiAgICAgICAgICAgIGV4ZWN1dGlvblRpbWUubWVhbiArXG4gICAgICAgICAgICByZXR1cm5MYXRlbmN5Lm1lYW4gfHwgMFxuICAgICk7XG59XG5cbmZ1bmN0aW9uIGVzdGltYXRlVGFpbExhdGVuY3koZm5TdGF0czogRnVuY3Rpb25TdGF0cywgblN0ZERldjogbnVtYmVyKSB7XG4gICAgcmV0dXJuIGVzdGltYXRlRnVuY3Rpb25MYXRlbmN5KGZuU3RhdHMpICsgblN0ZERldiAqIGZuU3RhdHMuZXhlY3V0aW9uVGltZS5zdGRldjtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcmV0cnlGdW5jdGlvbklmTmVlZGVkVG9SZWR1Y2VUYWlsTGF0ZW5jeShcbiAgICB0aW1lU2luY2VJbml0aWFsSW52b2NhdGlvbjogKCkgPT4gbnVtYmVyLFxuICAgIGdldFRpbWVvdXQ6ICgpID0+IG51bWJlcixcbiAgICB3b3JrZXI6ICgpID0+IFByb21pc2U8dm9pZD4sXG4gICAgc2hvdWxkUmV0cnk6ICgpID0+IGJvb2xlYW4sXG4gICAgY2FuY2VsOiBQcm9taXNlPHZvaWQ+XG4pIHtcbiAgICBsZXQgcGVuZGluZyA9IHRydWU7XG4gICAgbGV0IGxhc3RJbnZvY2F0aW9uVGltZTogbnVtYmVyID0gRGF0ZS5ub3coKTtcblxuICAgIGNhbmNlbC50aGVuKCgpID0+IChwZW5kaW5nID0gZmFsc2UpKTtcblxuICAgIGNvbnN0IGRvV29yayA9IGFzeW5jICgpID0+IHtcbiAgICAgICAgbGFzdEludm9jYXRpb25UaW1lID0gRGF0ZS5ub3coKTtcbiAgICAgICAgYXdhaXQgd29ya2VyKCkuY2F0Y2goXyA9PiB7fSk7XG4gICAgICAgIHBlbmRpbmcgPSBmYWxzZTtcbiAgICB9O1xuXG4gICAgY29uc3QgbGF0ZW5jeSA9ICgpID0+IERhdGUubm93KCkgLSBsYXN0SW52b2NhdGlvblRpbWU7XG5cbiAgICBkb1dvcmsoKTtcblxuICAgIHdoaWxlIChwZW5kaW5nKSB7XG4gICAgICAgIGNvbnN0IHRpbWVvdXQgPSBnZXRUaW1lb3V0KCk7XG4gICAgICAgIGlmIChsYXRlbmN5KCkgPj0gdGltZW91dCAmJiB0aW1lU2luY2VJbml0aWFsSW52b2NhdGlvbigpID4gdGltZW91dCArIDEwMDApIHtcbiAgICAgICAgICAgIGlmIChzaG91bGRSZXRyeSgpKSB7XG4gICAgICAgICAgICAgICAgZG9Xb3JrKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBjb25zdCB3YWl0VGltZSA9IHJvdW5kVG8xMDBtcyhNYXRoLm1heCh0aW1lb3V0IC0gbGF0ZW5jeSgpLCA1MDAwKSk7XG4gICAgICAgIGF3YWl0IHNsZWVwKHdhaXRUaW1lLCBjYW5jZWwpO1xuICAgIH1cbn1cbiJdfQ== |
\ | No newline at end of file |