faastjs
Version:
Serverless batch computing made simple.
432 lines • 53.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsyncOrderedQueue = exports.AsyncIterableQueue = exports.AsyncQueue = exports.throttle = exports.cacheFn = exports.memoizeFn = exports.RateLimiter = exports.Pump = exports.Funnel = exports.retryOp = exports.DeferredWorker = exports.Deferred = void 0;
const tslib_1 = require("tslib");
const assert_1 = tslib_1.__importDefault(require("assert"));
const crypto_1 = require("crypto");
const error_1 = require("./error");
const serialize_1 = require("./serialize");
const shared_1 = require("./shared");
class Deferred {
constructor() {
this.promise = new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
}
}
exports.Deferred = Deferred;
class DeferredWorker extends Deferred {
constructor(worker, cancel) {
super();
this.worker = worker;
this.cancel = cancel;
}
async execute() {
const cancelMessage = this.cancel?.();
if (cancelMessage) {
this.reject(new error_1.FaastError({ name: error_1.FaastErrorNames.ECANCEL }, cancelMessage));
}
else {
try {
const rv = await this.worker();
this.resolve(rv);
}
catch (err) {
this.reject(err);
}
}
}
}
exports.DeferredWorker = DeferredWorker;
function popFirst(set) {
let firstElem;
for (const elem of set) {
firstElem = elem;
break;
}
if (firstElem) {
set.delete(firstElem);
}
return firstElem;
}
async function retryOp(retryN, fn) {
const retryTest = typeof retryN === "function" ? retryN : (_, i) => i < retryN;
for (let i = 0; true; i++) {
try {
return await fn(i);
}
catch (err) {
if (!retryTest(err, i)) {
throw err;
}
await (0, shared_1.sleep)(Math.min(30 * 1000, 1000 * (1 + Math.random()) * 2 ** i) + Math.random());
}
}
}
exports.retryOp = retryOp;
class Funnel {
constructor(concurrency = 0, shouldRetry) {
this.concurrency = concurrency;
this.shouldRetry = shouldRetry;
this.pendingQueue = new Set();
this.executingQueue = new Set();
this.processed = 0;
this.errors = 0;
}
push(worker, shouldRetry, cancel) {
const retryTest = shouldRetry || this.shouldRetry || 0;
const retryWorker = () => retryOp(retryTest, worker);
const future = new DeferredWorker(retryWorker, cancel);
this.pendingQueue.add(future);
setImmediate(() => this.doWork());
return future.promise;
}
clear() {
this.pendingQueue.clear();
this.executingQueue.clear();
}
promises() {
return [...this.executingQueue, ...this.pendingQueue].map(p => p.promise);
}
all() {
return Promise.all(this.promises().map(p => p.catch(_ => { })));
}
size() {
return this.pendingQueue.size + this.executingQueue.size;
}
setMaxConcurrency(maxConcurrency) {
this.concurrency = maxConcurrency;
}
getConcurrency() {
return this.executingQueue.size;
}
doWork() {
const { pendingQueue } = this;
while (pendingQueue.size > 0 &&
(!this.concurrency || this.executingQueue.size < this.concurrency)) {
const worker = popFirst(pendingQueue);
this.executingQueue.add(worker);
worker.promise
.then(_ => this.processed++)
.catch(_ => this.errors++)
.then(_ => {
this.executingQueue.delete(worker);
this.doWork();
});
worker.execute();
}
}
}
exports.Funnel = Funnel;
/**
* @internal
*/
class Pump extends Funnel {
constructor(options, worker) {
super(options.concurrency);
this.options = options;
this.worker = worker;
this.stopped = false;
options.verbose = options.verbose ?? true;
}
start() {
const restart = () => {
if (this.stopped) {
return;
}
while (this.executingQueue.size + this.pendingQueue.size < this.concurrency) {
this.push(async () => {
try {
return await this.worker();
}
catch (err) {
this.options.verbose && console.error(err);
return;
}
finally {
setImmediate(restart);
}
});
}
};
this.stopped = false;
restart();
}
stop() {
this.stopped = true;
}
drain() {
this.stop();
return this.all();
}
setMaxConcurrency(concurrency) {
super.setMaxConcurrency(concurrency);
if (!this.stopped) {
this.start();
}
}
}
exports.Pump = Pump;
class RateLimiter {
constructor(targetRequestsPerSecond, burst = 1) {
this.targetRequestsPerSecond = targetRequestsPerSecond;
this.burst = burst;
this.lastTick = 0;
this.bucket = 0;
this.queue = new Set();
(0, assert_1.default)(targetRequestsPerSecond > 0);
(0, assert_1.default)(this.burst >= 1);
}
push(worker, cancel) {
this.updateBucket();
if (this.queue.size === 0 && this.bucket <= this.burst - 1) {
this.bucket++;
return worker();
}
const future = new DeferredWorker(worker, cancel);
this.queue.add(future);
if (this.queue.size === 1) {
this.drainQueue();
}
return future.promise;
}
updateBucket() {
const now = Date.now();
const secondsElapsed = (now - this.lastTick) / 1000;
this.bucket -= secondsElapsed * this.targetRequestsPerSecond;
this.bucket = Math.max(this.bucket, 0);
this.lastTick = now;
}
async drainQueue() {
const requestAmountToDrain = 1 - (this.burst - this.bucket);
const secondsToDrain = requestAmountToDrain / this.targetRequestsPerSecond;
if (secondsToDrain > 0) {
await (0, shared_1.sleep)(Math.ceil(secondsToDrain * 1000));
}
this.updateBucket();
while (this.bucket <= this.burst - 1) {
const next = popFirst(this.queue);
if (!next) {
break;
}
this.bucket++;
next.execute();
}
if (this.queue.size > 0) {
this.drainQueue();
}
}
clear() {
this.queue.clear();
}
}
exports.RateLimiter = RateLimiter;
function memoizeFn(fn, cache = new Map()) {
return (...args) => {
const key = JSON.stringify(args);
const prev = cache.get(key);
if (prev) {
return prev;
}
const value = fn(...args);
cache.set(key, value);
return value;
};
}
exports.memoizeFn = memoizeFn;
function cacheFn(cache, fn) {
return async (...args) => {
const key = (0, serialize_1.serialize)(args, true);
const hasher = (0, crypto_1.createHash)("sha256");
hasher.update(key);
const cacheKey = hasher.digest("hex");
const prev = await cache.get(cacheKey);
if (prev) {
const str = prev.toString();
if (str === "undefined") {
return undefined;
}
return (0, serialize_1.deserialize)(str);
}
const value = await fn(...args);
await cache.set(cacheKey, (0, serialize_1.serialize)(value, true));
return value;
};
}
exports.cacheFn = cacheFn;
/**
* A decorator for rate limiting, concurrency limiting, retry, memoization, and
* on-disk caching. See {@link Limits}.
* @remarks
* When programming against cloud services, databases, and other resources, it
* is often necessary to control the rate of request issuance to avoid
* overwhelming the service provider. In many cases the provider has built-in
* safeguards against abuse, which automatically fail requests if they are
* coming in too fast. Some systems don't have safeguards and precipitously
* degrade their service level or fail outright when faced with excessive load.
*
* With faast.js it becomes very easy to (accidentally) generate requests from
* thousands of cloud functions. The `throttle` function can help manage request
* flow without resorting to setting up a separate service. This is in keeping
* with faast.js' zero-ops philosophy.
*
* Usage is simple:
*
* ```typescript
* async function operation() { ... }
* const throttledOperation = throttle({ concurrency: 10, rate: 5 }, operation);
* for(let i = 0; i < 100; i++) {
* // at most 10 concurrent executions at a rate of 5 invocations per second.
* throttledOperation();
* }
* ```
*
* Note that each invocation to `throttle` creates a separate function with a
* separate limits. Therefore it is likely that you want to use `throttle` in a
* global context, not within a dynamic context:
*
* ```typescript
* async function operation() { ... }
* for(let i = 0; i < 100; i++) {
* // WRONG - each iteration creates a separate throttled function that's only called once.
* const throttledOperation = throttle({ concurrency: 10, rate: 5 }, operation);
* throttledOperation();
* }
* ```
*
* A better way to use throttle avoids creating a named `operation` function
* altogether, ensuring it cannot be accidentally called without throttling:
*
* ```typescript
* const operation = throttle({ concurrency: 10, rate: 5 }, async () => {
* ...
* });
* ```
*
* Throttle supports functions with arguments automatically infers the correct
* type for the returned function:
*
* ```typescript
* // `operation` inferred to have type (str: string) => Promise<string>
* const operation = throttle({ concurrency: 10, rate: 5 }, async (str: string) => {
* return string;
* });
* ```
*
* In addition to limiting concurrency and invocation rate, `throttle` also
* supports retrying failed invocations, memoizing calls, and on-disk caching.
* See {@link Limits} for details.
*
* @param limits - see {@link Limits}.
* @param fn - The function to throttle. It can take any arguments, but must
* return a Promise (which includes `async` functions).
* @returns Returns a throttled function with the same signature as the argument
* `fn`.
* @public
*/
function throttle(limits, fn) {
const { concurrency, retry, rate, burst, memoize, cache, cancel } = limits;
const funnel = new Funnel(concurrency, retry);
const cancellationQueue = [() => funnel.clear()];
let conditionedFunc;
if (rate) {
const rateLimiter = new RateLimiter(rate, burst);
cancellationQueue.push(() => rateLimiter.clear());
conditionedFunc = (...args) => funnel.push(() => rateLimiter.push(() => fn(...args)));
}
else {
conditionedFunc = (...args) => funnel.push(() => fn(...args));
}
if (cache) {
conditionedFunc = cacheFn(cache, conditionedFunc);
}
if (memoize) {
const mcache = new Map();
cancellationQueue.push(() => mcache.clear());
conditionedFunc = memoizeFn(conditionedFunc, mcache);
}
cancel?.then(() => cancellationQueue.forEach(cleanupFn => cleanupFn()));
return conditionedFunc;
}
exports.throttle = throttle;
function iteratorResult(value) {
return Promise.resolve(value).then(v => ({ done: false, value: v }));
}
const done = Promise.resolve({ done: true, value: undefined });
class AsyncQueue {
constructor() {
this.deferred = [];
this.enqueued = [];
}
enqueue(value) {
if (this.deferred.length > 0) {
const d = this.deferred.shift();
d.resolve(value);
}
else {
this.enqueued.push(Promise.resolve(value));
}
}
next() {
if (this.enqueued.length > 0) {
return this.enqueued.shift();
}
const d = new Deferred();
this.deferred.push(d);
return d.promise;
}
clear() {
this.deferred = [];
this.enqueued = [];
}
}
exports.AsyncQueue = AsyncQueue;
class AsyncIterableQueue extends AsyncQueue {
push(value) {
super.enqueue(iteratorResult(value));
}
done() {
super.enqueue(done);
}
[Symbol.asyncIterator]() {
return this;
}
}
exports.AsyncIterableQueue = AsyncIterableQueue;
class AsyncOrderedQueue {
constructor() {
this.queue = new AsyncQueue();
this.arrived = new Map();
this.current = 0;
}
push(value, sequence) {
this.enqueue(Promise.resolve(value), sequence);
}
pushImmediate(value) {
this.queue.enqueue(value);
}
enqueue(value, sequence) {
if (sequence < this.current) {
return;
}
if (!this.arrived.has(sequence)) {
this.arrived.set(sequence, value);
}
while (this.arrived.has(this.current)) {
this.queue.enqueue(this.arrived.get(this.current));
this.arrived.delete(this.current);
this.current++;
}
}
next() {
return this.queue.next();
}
clear() {
this.arrived.clear();
this.queue.clear();
this.current = 0;
}
}
exports.AsyncOrderedQueue = AsyncOrderedQueue;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGhyb3R0bGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdGhyb3R0bGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLDREQUE0QjtBQUM1QixtQ0FBb0M7QUFFcEMsbUNBQXNEO0FBQ3RELDJDQUFxRDtBQUNyRCxxQ0FBaUM7QUFFakMsTUFBYSxRQUFRO0lBSWpCO1FBQ0ksSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLE9BQU8sQ0FBSSxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUM5QyxJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztZQUN2QixJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUN6QixDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7Q0FDSjtBQVZELDRCQVVDO0FBRUQsTUFBYSxjQUF5QixTQUFRLFFBQVc7SUFDckQsWUFDWSxNQUF3QixFQUN4QixNQUFpQztRQUV6QyxLQUFLLEVBQUUsQ0FBQztRQUhBLFdBQU0sR0FBTixNQUFNLENBQWtCO1FBQ3hCLFdBQU0sR0FBTixNQUFNLENBQTJCO0lBRzdDLENBQUM7SUFDRCxLQUFLLENBQUMsT0FBTztRQUNULE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDO1FBQ3RDLElBQUksYUFBYSxFQUFFLENBQUM7WUFDaEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLGtCQUFVLENBQUMsRUFBRSxJQUFJLEVBQUUsdUJBQWUsQ0FBQyxPQUFPLEVBQUUsRUFBRSxhQUFhLENBQUMsQ0FBQyxDQUFDO1FBQ2xGLENBQUM7YUFBTSxDQUFDO1lBQ0osSUFBSSxDQUFDO2dCQUNELE1BQU0sRUFBRSxHQUFHLE1BQU0sSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO2dCQUMvQixJQUFJLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ3JCLENBQUM7WUFBQyxPQUFPLEdBQVEsRUFBRSxDQUFDO2dCQUNoQixJ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S0FBSyxDQUFDLENBQUM7SUFDOUIsQ0FBQztJQUVELE9BQU8sQ0FBQyxLQUFpQixFQUFFLFFBQWdCO1FBQ3ZDLElBQUksUUFBUSxHQUFHLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUMxQixPQUFPO1FBQ1gsQ0FBQztRQUNELElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1lBQzlCLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUN0QyxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUNwQyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFFLENBQUMsQ0FBQztZQUNwRCxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDbEMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ25CLENBQUM7SUFDTCxDQUFDO0lBRUQsSUFBSTtRQUNBLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUM3QixDQUFDO0lBRUQsS0FBSztRQUNELElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDckIsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNuQixJQUFJLENBQUMsT0FBTyxHQUFHLENBQUMsQ0FBQztJQUNyQixDQUFDO0NBQ0o7QUFwQ0QsOENBb0NDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGFzc2VydCBmcm9tIFwiYXNzZXJ0XCI7XG5pbXBvcnQgeyBjcmVhdGVIYXNoIH0gZnJvbSBcImNyeXB0b1wiO1xuaW1wb3J0IHsgUGVyc2lzdGVudENhY2hlIH0gZnJvbSBcIi4vY2FjaGVcIjtcbmltcG9ydCB7IEZhYXN0RXJyb3IsIEZhYXN0RXJyb3JOYW1lcyB9IGZyb20gXCIuL2Vycm9yXCI7XG5pbXBvcnQgeyBkZXNlcmlhbGl6ZSwgc2VyaWFsaXplIH0gZnJvbSBcIi4vc2VyaWFsaXplXCI7XG5pbXBvcnQgeyBzbGVlcCB9IGZyb20gXCIuL3NoYXJlZFwiO1xuXG5leHBvcnQgY2xhc3MgRGVmZXJyZWQ8VCA9IHZvaWQ+IHtcbiAgICBwcm9taXNlOiBQcm9taXNlPFQ+O1xuICAgIHJlc29sdmUhOiAoYXJnOiBUIHwgUHJvbWlzZUxpa2U8VD4pID0+IHZvaWQ7XG4gICAgcmVqZWN0ITogKGVycj86IGFueSkgPT4gdm9pZDtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgdGhpcy5wcm9taXNlID0gbmV3IFByb21pc2U8VD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5yZXNvbHZlID0gcmVzb2x2ZTtcbiAgICAgICAgICAgIHRoaXMucmVqZWN0ID0gcmVqZWN0O1xuICAgICAgICB9KTtcbiAgICB9XG59XG5cbmV4cG9ydCBjbGFzcyBEZWZlcnJlZFdvcmtlcjxUID0gdm9pZD4gZXh0ZW5kcyBEZWZlcnJlZDxUPiB7XG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIHByaXZhdGUgd29ya2VyOiAoKSA9PiBQcm9taXNlPFQ+LFxuICAgICAgICBwcml2YXRlIGNhbmNlbD86ICgpID0+IHN0cmluZyB8IHVuZGVmaW5lZFxuICAgICkge1xuICAgICAgICBzdXBlcigpO1xuICAgIH1cbiAgICBhc3luYyBleGVjdXRlKCkge1xuICAgICAgICBjb25zdCBjYW5jZWxNZXNzYWdlID0gdGhpcy5jYW5jZWw/LigpO1xuICAgICAgICBpZiAoY2FuY2VsTWVzc2FnZSkge1xuICAgICAgICAgICAgdGhpcy5yZWplY3QobmV3IEZhYXN0RXJyb3IoeyBuYW1lOiBGYWFzdEVycm9yTmFtZXMuRUNBTkNFTCB9LCBjYW5jZWxNZXNzYWdlKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHJ2ID0gYXdhaXQgdGhpcy53b3JrZXIoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlc29sdmUocnYpO1xuICAgICAgICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlamVjdChlcnIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufVxuXG5mdW5jdGlvbiBwb3BGaXJzdDxUPihzZXQ6IFNldDxUPik6IFQgfCB1bmRlZmluZWQge1xuICAgIGxldCBmaXJzdEVsZW06IFQgfCB1bmRlZmluZWQ7XG4gICAgZm9yIChjb25zdCBlbGVtIG9mIHNldCkge1xuICAgICAgICBmaXJzdEVsZW0gPSBlbGVtO1xuICAgICAgICBicmVhaztcbiAgICB9XG4gICAgaWYgKGZpcnN0RWxlbSkge1xuICAgICAgICBzZXQuZGVsZXRlKGZpcnN0RWxlbSk7XG4gICAgfVxuICAgIHJldHVybiBmaXJzdEVsZW07XG59XG5cbmV4cG9ydCB0eXBlIFJldHJ5VHlwZSA9IG51bWJlciB8ICgoZXJyOiBhbnksIHJldHJpZXM6IG51bWJlcikgPT4gYm9vbGVhbik7XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZXRyeU9wPFQ+KHJldHJ5TjogUmV0cnlUeXBlLCBmbjogKHJldHJpZXM6IG51bWJlcikgPT4gUHJvbWlzZTxUPikge1xuICAgIGNvbnN0IHJldHJ5VGVzdCA9XG4gICAgICAgIHR5cGVvZiByZXRyeU4gPT09IFwiZnVuY3Rpb25cIiA/IHJldHJ5TiA6IChfOiBhbnksIGk6IG51bWJlcikgPT4gaSA8IHJldHJ5TjtcbiAgICBmb3IgKGxldCBpID0gMDsgdHJ1ZTsgaSsrKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgZm4oaSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgICAgICBpZiAoIXJldHJ5VGVzdChlcnIsIGkpKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYXdhaXQgc2xlZXAoXG4gICAgICAgICAgICAgICAgTWF0aC5taW4oMzAgKiAxMDAwLCAxMDAwICogKDEgKyBNYXRoLnJhbmRvbSgpKSAqIDIgKiogaSkgKyBNYXRoLnJhbmRvbSgpXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfVxufVxuXG5leHBvcnQgY2xhc3MgRnVubmVsPFQgPSB2b2lkPiB7XG4gICAgcHJvdGVjdGVkIHBlbmRpbmdRdWV1ZTogU2V0PERlZmVycmVkV29ya2VyPFQ+PiA9IG5ldyBTZXQoKTtcbiAgICBwcm90ZWN0ZWQgZXhlY3V0aW5nUXVldWU6IFNldDxEZWZlcnJlZFdvcmtlcjxUPj4gPSBuZXcgU2V0KCk7XG4gICAgcHVibGljIHByb2Nlc3NlZCA9IDA7XG4gICAgcHVibGljIGVycm9ycyA9IDA7XG5cbiAgICBjb25zdHJ1Y3RvcihwdWJsaWMgY29uY3VycmVuY3k6IG51bWJlciA9IDAsIHByb3RlY3RlZCBzaG91bGRSZXRyeT86IFJldHJ5VHlwZSkge31cblxuICAgIHB1c2goXG4gICAgICAgIHdvcmtlcjogKCkgPT4gUHJvbWlzZTxUPixcbiAgICAgICAgc2hvdWxkUmV0cnk/OiBSZXRyeVR5cGUsXG4gICAgICAgIGNhbmNlbD86ICgpID0+IHN0cmluZyB8IHVuZGVmaW5lZFxuICAgICkge1xuICAgICAgICBjb25zdCByZXRyeVRlc3QgPSBzaG91bGRSZXRyeSB8fCB0aGlzLnNob3VsZFJldHJ5IHx8IDA7XG4gICAgICAgIGNvbnN0IHJldHJ5V29ya2VyID0gKCkgPT4gcmV0cnlPcChyZXRyeVRlc3QsIHdvcmtlcik7XG4gICAgICAgIGNvbnN0IGZ1dHVyZSA9IG5ldyBEZWZlcnJlZFdvcmtlcihyZXRyeVdvcmtlciwgY2FuY2VsKTtcbiAgICAgICAgdGhpcy5wZW5kaW5nUXVldWUuYWRkKGZ1dHVyZSk7XG4gICAgICAgIHNldEltbWVkaWF0ZSgoKSA9PiB0aGlzLmRvV29yaygpKTtcbiAgICAgICAgcmV0dXJuIGZ1dHVyZS5wcm9taXNlO1xuICAgIH1cblxuICAgIGNsZWFyKCkge1xuICAgICAgICB0aGlzLnBlbmRpbmdRdWV1ZS5jbGVhcigpO1xuICAgICAgICB0aGlzLmV4ZWN1dGluZ1F1ZXVlLmNsZWFyKCk7XG4gICAgfVxuXG4gICAgcHJvbWlzZXMoKSB7XG4gICAgICAgIHJldHVybiBbLi4udGhpcy5leGVjdXRpbmdRdWV1ZSwgLi4udGhpcy5wZW5kaW5nUXVldWVdLm1hcChwID0+IHAucHJvbWlzZSk7XG4gICAgfVxuXG4gICAgYWxsKCkge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5hbGwodGhpcy5wcm9taXNlcygpLm1hcChwID0+IHAuY2F0Y2goXyA9PiB7fSkpKTtcbiAgICB9XG5cbiAgICBzaXplKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5wZW5kaW5nUXVldWUuc2l6ZSArIHRoaXMuZXhlY3V0aW5nUXVldWUuc2l6ZTtcbiAgICB9XG5cbiAgICBzZXRNYXhDb25jdXJyZW5jeShtYXhDb25jdXJyZW5jeTogbnVtYmVyKSB7XG4gICAgICAgIHRoaXMuY29uY3VycmVuY3kgPSBtYXhDb25jdXJyZW5jeTtcbiAgICB9XG5cbiAgICBnZXRDb25jdXJyZW5jeSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZXhlY3V0aW5nUXVldWUuc2l6ZTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgZG9Xb3JrKCkge1xuICAgICAgICBjb25zdCB7IHBlbmRpbmdRdWV1ZSB9ID0gdGhpcztcbiAgICAgICAgd2hpbGUgKFxuICAgICAgICAgICAgcGVuZGluZ1F1ZXVlLnNpemUgPiAwICYmXG4gICAgICAgICAgICAoIXRoaXMuY29uY3VycmVuY3kgfHwgdGhpcy5leGVjdXRpbmdRdWV1ZS5zaXplIDwgdGhpcy5jb25jdXJyZW5jeSlcbiAgICAgICAgKSB7XG4gICAgICAgICAgICBjb25zdCB3b3JrZXIgPSBwb3BGaXJzdChwZW5kaW5nUXVldWUpITtcbiAgICAgICAgICAgIHRoaXMuZXhlY3V0aW5nUXVldWUuYWRkKHdvcmtlcik7XG5cbiAgICAgICAgICAgIHdvcmtlci5wcm9taXNlXG4gICAgICAgICAgICAgICAgLnRoZW4oXyA9PiB0aGlzLnByb2Nlc3NlZCsrKVxuICAgICAgICAgICAgICAgIC5jYXRjaChfID0+IHRoaXMuZXJyb3JzKyspXG4gICAgICAgICAgICAgICAgLnRoZW4oXyA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZXhlY3V0aW5nUXVldWUuZGVsZXRlKHdvcmtlcik7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZG9Xb3JrKCk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB3b3JrZXIuZXhlY3V0ZSgpO1xuICAgICAgICB9XG4gICAgfVxufVxuXG4vKipcbiAqIEBpbnRlcm5hbFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFB1bXBPcHRpb25zIHtcbiAgICBjb25jdXJyZW5jeTogbnVtYmVyO1xuICAgIHZlcmJvc2U/OiBib29sZWFuO1xufVxuXG4vKipcbiAqIEBpbnRlcm5hbFxuICovXG5leHBvcnQgY2xhc3MgUHVtcDxUID0gdm9pZD4gZXh0ZW5kcyBGdW5uZWw8VCB8IHZvaWQ+IHtcbiAgICBzdG9wcGVkOiBib29sZWFuID0gZmFsc2U7XG4gICAgY29uc3RydWN0b3IocHJvdGVjdGVkIG9wdGlvbnM6IFB1bXBPcHRpb25zLCBwcm90ZWN0ZWQgd29ya2VyOiAoKSA9PiBQcm9taXNlPFQ+KSB7XG4gICAgICAgIHN1cGVyKG9wdGlvbnMuY29uY3VycmVuY3kpO1xuICAgICAgICBvcHRpb25zLnZlcmJvc2UgPSBvcHRpb25zLnZlcmJvc2UgPz8gdHJ1ZTtcbiAgICB9XG5cbiAgICBzdGFydCgpIHtcbiAgICAgICAgY29uc3QgcmVzdGFydCA9ICgpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLnN0b3BwZWQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB3aGlsZSAodGhpcy5leGVjdXRpbmdRdWV1ZS5zaXplICsgdGhpcy5wZW5kaW5nUXVldWUuc2l6ZSA8IHRoaXMuY29uY3VycmVuY3kpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnB1c2goYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMud29ya2VyKCk7XG4gICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLm9wdGlvbnMudmVyYm9zZSAmJiBjb25zb2xlLmVycm9yKGVycik7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRJbW1lZGlhdGUocmVzdGFydCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5zdG9wcGVkID0gZmFsc2U7XG4gICAgICAgIHJlc3RhcnQoKTtcbiAgICB9XG5cbiAgICBzdG9wKCkge1xuICAgICAgICB0aGlzLnN0b3BwZWQgPSB0cnVlO1xuICAgIH1cblxuICAgIGRyYWluKCkge1xuICAgICAgICB0aGlzLnN0b3AoKTtcbiAgICAgICAgcmV0dXJuIHRoaXMuYWxsKCk7XG4gICAgfVxuXG4gICAgc2V0TWF4Q29uY3VycmVuY3koY29uY3VycmVuY3k6IG51bWJlcikge1xuICAgICAgICBzdXBlci5zZXRNYXhDb25jdXJyZW5jeShjb25jdXJyZW5jeSk7XG4gICAgICAgIGlmICghdGhpcy5zdG9wcGVkKSB7XG4gICAgICAgICAgICB0aGlzLnN0YXJ0KCk7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbmV4cG9ydCBjbGFzcyBSYXRlTGltaXRlcjxUID0gdm9pZD4ge1xuICAgIHByb3RlY3RlZCBsYXN0VGljayA9IDA7XG4gICAgcHJvdGVjdGVkIGJ1Y2tldCA9IDA7XG4gICAgcHJvdGVjdGVkIHF1ZXVlOiBTZXQ8RGVmZXJyZWRXb3JrZXI8VD4+ID0gbmV3IFNldCgpO1xuXG4gICAgY29uc3RydWN0b3IocHJvdGVjdGVkIHRhcmdldFJlcXVlc3RzUGVyU2Vjb25kOiBudW1iZXIsIHByb3RlY3RlZCBidXJzdDogbnVtYmVyID0gMSkge1xuICAgICAgICBhc3NlcnQodGFyZ2V0UmVxdWVzdHNQZXJTZWNvbmQgPiAwKTtcbiAgICAgICAgYXNzZXJ0KHRoaXMuYnVyc3QgPj0gMSk7XG4gICAgfVxuXG4gICAgcHVzaCh3b3JrZXI6ICgpID0+IFByb21pc2U8VD4sIGNhbmNlbD86ICgpID0+IHN0cmluZyB8IHVuZGVmaW5lZCkge1xuICAgICAgICB0aGlzLnVwZGF0ZUJ1Y2tldCgpO1xuICAgICAgICBpZiAodGhpcy5xdWV1ZS5zaXplID09PSAwICYmIHRoaXMuYnVja2V0IDw9IHRoaXMuYnVyc3QgLSAxKSB7XG4gICAgICAgICAgICB0aGlzLmJ1Y2tldCsrO1xuICAgICAgICAgICAgcmV0dXJuIHdvcmtlcigpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZnV0dXJlID0gbmV3IERlZmVycmVkV29ya2VyKHdvcmtlciwgY2FuY2VsKTtcbiAgICAgICAgdGhpcy5xdWV1ZS5hZGQoZnV0dXJlKTtcbiAgICAgICAgaWYgKHRoaXMucXVldWUuc2l6ZSA9PT0gMSkge1xuICAgICAgICAgICAgdGhpcy5kcmFpblF1ZXVlKCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZ1dHVyZS5wcm9taXNlO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCB1cGRhdGVCdWNrZXQoKSB7XG4gICAgICAgIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gICAgICAgIGNvbnN0IHNlY29uZHNFbGFwc2VkID0gKG5vdyAtIHRoaXMubGFzdFRpY2spIC8gMTAwMDtcbiAgICAgICAgdGhpcy5idWNrZXQgLT0gc2Vjb25kc0VsYXBzZWQgKiB0aGlzLnRhcmdldFJlcXVlc3RzUGVyU2Vjb25kO1xuICAgICAgICB0aGlzLmJ1Y2tldCA9IE1hdGgubWF4KHRoaXMuYnVja2V0LCAwKTtcbiAgICAgICAgdGhpcy5sYXN0VGljayA9IG5vdztcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgYXN5bmMgZHJhaW5RdWV1ZSgpIHtcbiAgICAgICAgY29uc3QgcmVxdWVzdEFtb3VudFRvRHJhaW4gPSAxIC0gKHRoaXMuYnVyc3QgLSB0aGlzLmJ1Y2tldCk7XG4gICAgICAgIGNvbnN0IHNlY29uZHNUb0RyYWluID0gcmVxdWVzdEFtb3VudFRvRHJhaW4gLyB0aGlzLnRhcmdldFJlcXVlc3RzUGVyU2Vjb25kO1xuICAgICAgICBpZiAoc2Vjb25kc1RvRHJhaW4gPiAwKSB7XG4gICAgICAgICAgICBhd2FpdCBzbGVlcChNYXRoLmNlaWwoc2Vjb25kc1RvRHJhaW4gKiAxMDAwKSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy51cGRhdGVCdWNrZXQoKTtcbiAgICAgICAgd2hpbGUgKHRoaXMuYnVja2V0IDw9IHRoaXMuYnVyc3QgLSAxKSB7XG4gICAgICAgICAgICBjb25zdCBuZXh0ID0gcG9wRmlyc3QodGhpcy5xdWV1ZSk7XG4gICAgICAgICAgICBpZiAoIW5leHQpIHtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuYnVja2V0Kys7XG4gICAgICAgICAgICBuZXh0LmV4ZWN1dGUoKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5xdWV1ZS5zaXplID4gMCkge1xuICAgICAgICAgICAgdGhpcy5kcmFpblF1ZXVlKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBjbGVhcigpIHtcbiAgICAgICAgdGhpcy5xdWV1ZS5jbGVhcigpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBTcGVjaWZ5IHtAbGluayB0aHJvdHRsZX0gbGltaXRzLiBUaGVzZSBsaW1pdHMgc2hhcGUgdGhlIHdheSB0aHJvdHRsZSBpbnZva2VzXG4gKiB0aGUgdW5kZXJseWluZyBmdW5jdGlvbi5cbiAqIEBwdWJsaWNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBMaW1pdHMge1xuICAgIC8qKlxuICAgICAqIFRoZSBtYXhpbXVtIG51bWJlciBvZiBjb25jdXJyZW50IGV4ZWN1dGlvbnMgb2YgdGhlIHVuZGVybHlpbmcgZnVuY3Rpb24gdG9cbiAgICAgKiBhbGxvdy4gTXVzdCBiZSBzdXBwbGllZCwgdGhlcmUgaXMgbm8gZGVmYXVsdC4gU3BlY2lmeWluZyBgMGAgb3JcbiAgICAgKiBgSW5maW5pdHlgIGlzIGFsbG93ZWQgYW5kIG1lYW5zIHRoZXJlIGlzIG5vIGNvbmN1cnJlbmN5IGxpbWl0LlxuICAgICAqL1xuICAgIGNvbmN1cnJlbmN5OiBudW1iZXI7XG4gICAgLyoqXG4gICAgICogVGhlIG1heGltdW0gbnVtYmVyIG9mIGNhbGxzIHBlciBzZWNvbmQgdG8gYWxsb3cgdG8gdGhlIHVuZGVybHlpbmdcbiAgICAgKiBmdW5jdGlvbi4gRGVmYXVsdDogbm8gcmF0ZSBsaW1pdC5cbiAgICAgKi9cbiAgICByYXRlPzogbnVtYmVyO1xuICAgIC8qKlxuICAgICAqIFRoZSBtYXhpbXVtIG51bWJlciBvZiBjYWxscyB0byB0aGUgdW5kZXJseWluZyBmdW5jdGlvbiB0byBcImJ1cnN0XCIgLS0gZS5nLlxuICAgICAqIHRoZSBudW1iZXIgdGhhdCBjYW4gYmUgaXNzdWVkIGltbWVkaWF0ZWx5IGFzIGxvbmcgYXMgdGhlIHJhdGUgbGltaXQgaXNcbiAgICAgKiBub3QgZXhjZWVkZWQuIEZvciBleGFtcGxlLCBpZiByYXRlIGlzIDUgYW5kIGJ1cnN0IGlzIDUsIGFuZCAxMCBjYWxscyBhcmVcbiAgICAgKiBtYWRlIHRvIHRoZSB0aHJvdHRsZWQgZnVuY3Rpb24sIDUgY2FsbHMgYXJlIG1hZGUgaW1tZWRpYXRlbHkgYW5kIHRoZW5cbiAgICAgKiBhZnRlciAxIHNlY29uZCwgYW5vdGhlciA1IGNhbGxzIGFyZSBtYWRlIGltbWVkaWF0ZWx5LiBTZXR0aW5nIGJ1cnN0IHRvIDFcbiAgICAgKiBtZWFucyBjYWxscyBhcmUgaXNzdWVkIHVuaWZvcm1seSBldmVyeSBgMS9yYXRlYCBzZWNvbmRzLiBJZiBgcmF0ZWAgaXMgbm90XG4gICAgICogc3BlY2lmaWVkLCB0aGVuIGBidXJzdGAgZG9lcyBub3QgYXBwbHkuIERlZmF1bHQ6IDEuXG4gICAgICovXG4gICAgYnVyc3Q/OiBudW1iZXI7XG4gICAgLyoqXG4gICAgICogUmV0cnkgaWYgdGhlIHRocm90dGxlZCBmdW5jdGlvbiByZXR1cm5zIGEgcmVqZWN0ZWQgcHJvbWlzZS4gYHJldHJ5YCBjYW5cbiAgICAgKiBiZSBhIG51bWJlciBvciBhIGZ1bmN0aW9uLiBJZiBpdCBpcyBhIG51bWJlciBgTmAsIHRoZW4gdXAgdG8gYE5gXG4gICAgICogYWRkaXRpb25hbCBhdHRlbXB0cyBhcmUgbWFkZSBpbiBhZGRpdGlvbiB0byB0aGUgaW5pdGlhbCBjYWxsLiBJZiByZXRyeSBpc1xuICAgICAqIGEgZnVuY3Rpb24sIGl0IHNob3VsZCByZXR1cm4gYHRydWVgIGlmIGFub3RoZXIgcmV0cnkgYXR0ZW1wdCBzaG91bGQgYmVcbiAgICAgKiBtYWRlLCBvdGhlcndpc2UgYGZhbHNlYC4gVGhlIGZpcnN0IGFyZ3VtZW50IHdpbGwgYmUgdGhlIHZhbHVlIG9mIHRoZVxuICAgICAqIHJlamVjdGVkIHByb21pc2UgZnJvbSB0aGUgcHJldmlvdXMgY2FsbCBhdHRlbXB0LCBhbmQgdGhlIHNlY29uZCBhcmd1bWVudFxuICAgICAqIHdpbGwgYmUgdGhlIG51bWJlciBvZiBwcmV2aW91cyByZXRyeSBhdHRlbXB0cyAoZS5nLiB0aGUgZmlyc3QgY2FsbCB3aWxsXG4gICAgICogaGF2ZSB2YWx1ZSAwKS4gRGVmYXVsdDogMCAobm8gcmV0cnkgYXR0ZW1wdHMpLlxuICAgICAqL1xuICAgIHJldHJ5PzogbnVtYmVyIHwgKChlcnI6IGFueSwgcmV0cmllczogbnVtYmVyKSA9PiBib29sZWFuKTtcbiAgICAvKipcbiAgICAgKiBJZiBgbWVtb2l6ZWAgaXMgYHRydWVgLCB0aGVuIGV2ZXJ5IGNhbGwgdG8gdGhlIHRocm90dGxlZCBmdW5jdGlvbiB3aWxsIGJlXG4gICAgICogc2F2ZWQgYXMgYW4gZW50cnkgaW4gYSBtYXAgZnJvbSBhcmd1bWVudHMgdG8gcmV0dXJuIHZhbHVlLiBJZiBzYW1lXG4gICAgICogYXJndW1lbnRzIGFyZSBzZWVuIGFnYWluIGluIGEgZnV0dXJlIGNhbGwsIHRoZSByZXR1cm4gdmFsdWUgaXMgcmV0cmlldmVkXG4gICAgICogZnJvbSB0aGUgTWFwIHJhdGhlciB0aGFuIGNhbGxpbmcgdGhlIGZ1bmN0aW9uIGFnYWluLiBUaGlzIGNhbiBiZSB1c2VmdWxcbiAgICAgKiBmb3IgYXZvaWRpbmcgcmVkdW5kYW50IGNhbGxzIHRoYXQgYXJlIGV4cGVjdGVkIHRvIHJldHVybiB0aGUgc2FtZSByZXN1bHRzXG4gICAgICogZ2l2ZW4gdGhlIHNhbWUgYXJndW1lbnRzLlxuICAgICAqXG4gICAgICogVGhlIGFyZ3VtZW50cyB3aWxsIGJlIGNhcHR1cmVkIHdpdGggYEpTT04uc3RyaW5naWZ5YCwgdGhlcmVmb3JlIHR5cGVzXG4gICAgICogdGhhdCBkbyBub3Qgc3RyaW5naWZ5IHVuaXF1ZWx5IHdvbid0IGJlIGRpc3Rpbmd1aXNoZWQgZnJvbSBlYWNoIG90aGVyLlxuICAgICAqIENhcmUgbXVzdCBiZSB0YWtlbiB3aGVuIHNwZWNpZnlpbmcgYG1lbW9pemVgIHRvIGVuc3VyZSBhdm9pZCBpbmNvcnJlY3RcbiAgICAgKiByZXN1bHRzLlxuICAgICAqL1xuICAgIG1lbW9pemU/OiBib29sZWFuO1xuICAgIC8qKlxuICAgICAqIFNpbWlsYXIgdG8gYG1lbW9pemVgIGV4Y2VwdCB0aGUgbWFwIGZyb20gZnVuY3Rpb24gYXJndW1lbnRzIHRvIHJlc3VsdHMgaXNcbiAgICAgKiBzdG9yZWQgaW4gYSBwZXJzaXN0ZW50IGNhY2hlIG9uIGRpc2suIFRoaXMgaXMgdXNlZnVsIHRvIHByZXZlbnQgcmVkdW5kYW50XG4gICAgICogY2FsbHMgdG8gQVBJcyB3aGljaCBhcmUgZXhwZWN0ZWQgdG8gcmV0dXJuIHRoZSBzYW1lIHJlc3VsdHMgZm9yIHRoZSBzYW1lXG4gICAgICogYXJndW1lbnRzLCBhbmQgd2hpY2ggYXJlIGxpa2VseSB0byBiZSBjYWxsZWQgYWNyb3NzIG1hbnkgZmFhc3QuanMgbW9kdWxlXG4gICAgICogaW5zdGFudGlhdGlvbnMuIFRoaXMgaXMgdXNlZCBpbnRlcm5hbGx5IGJ5IGZhYXN0LmpzIGZvciBjYWNoaW5nIGNsb3VkXG4gICAgICogcHJpY2VzIGZvciBBV1MsIGFuZCBmb3Igc2F2aW5nIHRoZSBsYXN0IGdhcmJhZ2UgY29sbGVjdGlvblxuICAgICAqIGRhdGUgZm9yIEFXUy4gUGVyc2lzdGVudCBjYWNoZSBlbnRyaWVzIGV4cGlyZSBhZnRlciBhIHBlcmlvZCBvZiB0aW1lLiBTZWVcbiAgICAgKiB7QGxpbmsgUGVyc2lzdGVudENhY2hlfS5cbiAgICAgKi9cbiAgICBjYWNoZT86IFBlcnNpc3RlbnRDYWNoZTtcbiAgICAvKipcbiAgICAgKiBBIHByb21pc2UgdGhhdCwgaWYgcmVzb2x2ZWQsIGNhdXNlcyBjYW5jZWxsYXRpb24gb2YgcGVuZGluZyB0aHJvdHRsZWRcbiAgICAgKiBpbnZvY2F0aW9ucy4gVGhpcyBpcyB0eXBpY2FsbHkgY3JlYXRlZCB1c2luZyBgRGVmZXJyZWRgLiBUaGUgaWRlYSBpcyB0b1xuICAgICAqIHVzZSB0aGUgcmVzb2x2aW5nIG9mIHRoZSBwcm9taXNlIGFzIGFuIGFzeW5jaHJvbm91cyBzaWduYWwgdGhhdCBhbnlcbiAgICAgKiBwZW5kaW5nIGludm9jYXRpb25zIGluIHRoaXMgdGhyb3R0bGVkIGZ1bmN0aW9uIHNob3VsZCBiZSBjbGVhcmVkLlxuICAgICAqIEBpbnRlcm5hbFxuICAgICAqL1xuICAgIGNhbmNlbD86IFByb21pc2U8dm9pZD47XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBtZW1vaXplRm48QSBleHRlbmRzIGFueVtdLCBSPihcbiAgICBmbjogKC4uLmFyZ3M6IEEpID0+IFIsXG4gICAgY2FjaGU6IE1hcDxzdHJpbmcsIFI+ID0gbmV3IE1hcCgpXG4pIHtcbiAgICByZXR1cm4gKC4uLmFyZ3M6IEEpID0+IHtcbiAgICAgICAgY29uc3Qga2V5ID0gSlNPTi5zdHJpbmdpZnkoYXJncyk7XG4gICAgICAgIGNvbnN0IHByZXYgPSBjYWNoZS5nZXQoa2V5KTtcbiAgICAgICAgaWYgKHByZXYpIHtcbiAgICAgICAgICAgIHJldHVybiBwcmV2O1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHZhbHVlID0gZm4oLi4uYXJncyk7XG4gICAgICAgIGNhY2hlLnNldChrZXksIHZhbHVlKTtcbiAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjYWNoZUZuPEEgZXh0ZW5kcyBhbnlbXSwgUj4oXG4gICAgY2FjaGU6IFBlcnNpc3RlbnRDYWNoZSxcbiAgICBmbjogKC4uLmFyZ3M6IEEpID0+IFByb21pc2U8Uj5cbikge1xuICAgIHJldHVybiBhc3luYyAoLi4uYXJnczogQSkgPT4ge1xuICAgICAgICBjb25zdCBrZXkgPSBzZXJpYWxpemUoYXJncywgdHJ1ZSk7XG4gICAgICAgIGNvbnN0IGhhc2hlciA9IGNyZWF0ZUhhc2goXCJzaGEyNTZcIik7XG4gICAgICAgIGhhc2hlci51cGRhdGUoa2V5KTtcbiAgICAgICAgY29uc3QgY2FjaGVLZXkgPSBoYXNoZXIuZGlnZXN0KFwiaGV4XCIpO1xuICAgICAgICBjb25zdCBwcmV2ID0gYXdhaXQgY2FjaGUuZ2V0KGNhY2hlS2V5KTtcbiAgICAgICAgaWYgKHByZXYpIHtcbiAgICAgICAgICAgIGNvbnN0IHN0ciA9IHByZXYudG9TdHJpbmcoKTtcbiAgICAgICAgICAgIGlmIChzdHIgPT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGRlc2VyaWFsaXplKHN0cik7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgdmFsdWUgPSBhd2FpdCBmbiguLi5hcmdzKTtcbiAgICAgICAgYXdhaXQgY2FjaGUuc2V0KGNhY2hlS2V5LCBzZXJpYWxpemUodmFsdWUsIHRydWUpKTtcbiAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIH07XG59XG5cbi8qKlxuICogQSBkZWNvcmF0b3IgZm9yIHJhdGUgbGltaXRpbmcsIGNvbmN1cnJlbmN5IGxpbWl0aW5nLCByZXRyeSwgbWVtb2l6YXRpb24sIGFuZFxuICogb24tZGlzayBjYWNoaW5nLiBTZWUge0BsaW5rIExpbWl0c30uXG4gKiBAcmVtYXJrc1xuICogV2hlbiBwcm9ncmFtbWluZyBhZ2FpbnN0IGNsb3VkIHNlcnZpY2VzLCBkYXRhYmFzZXMsIGFuZCBvdGhlciByZXNvdXJjZXMsIGl0XG4gKiBpcyBvZnRlbiBuZWNlc3NhcnkgdG8gY29udHJvbCB0aGUgcmF0ZSBvZiByZXF1ZXN0IGlzc3VhbmNlIHRvIGF2b2lkXG4gKiBvdmVyd2hlbG1pbmcgdGhlIHNlcnZpY2UgcHJvdmlkZXIuIEluIG1hbnkgY2FzZXMgdGhlIHByb3ZpZGVyIGhhcyBidWlsdC1pblxuICogc2FmZWd1YXJkcyBhZ2FpbnN0IGFidXNlLCB3aGljaCBhdXRvbWF0aWNhbGx5IGZhaWwgcmVxdWVzdHMgaWYgdGhleSBhcmVcbiAqIGNvbWluZyBpbiB0b28gZmFzdC4gU29tZSBzeXN0ZW1zIGRvbid0IGhhdmUgc2FmZWd1YXJkcyBhbmQgcHJlY2lwaXRvdXNseVxuICogZGVncmFkZSB0aGVpciBzZXJ2aWNlIGxldmVsIG9yIGZhaWwgb3V0cmlnaHQgd2hlbiBmYWNlZCB3aXRoIGV4Y2Vzc2l2ZSBsb2FkLlxuICpcbiAqIFdpdGggZmFhc3QuanMgaXQgYmVjb21lcyB2ZXJ5IGVhc3kgdG8gKGFjY2lkZW50YWxseSkgZ2VuZXJhdGUgcmVxdWVzdHMgZnJvbVxuICogdGhvdXNhbmRzIG9mIGNsb3VkIGZ1bmN0aW9ucy4gVGhlIGB0aHJvdHRsZWAgZnVuY3Rpb24gY2FuIGhlbHAgbWFuYWdlIHJlcXVlc3RcbiAqIGZsb3cgd2l0aG91dCByZXNvcnRpbmcgdG8gc2V0dGluZyB1cCBhIHNlcGFyYXRlIHNlcnZpY2UuIFRoaXMgaXMgaW4ga2VlcGluZ1xuICogd2l0aCBmYWFzdC5qcycgemVyby1vcHMgcGhpbG9zb3BoeS5cbiAqXG4gKiBVc2FnZSBpcyBzaW1wbGU6XG4gKlxuICogYGBgdHlwZXNjcmlwdFxuICogYXN5bmMgZnVuY3Rpb24gb3BlcmF0aW9uKCkgeyAuLi4gfVxuICogY29uc3QgdGhyb3R0bGVkT3BlcmF0aW9uID0gdGhyb3R0bGUoeyBjb25jdXJyZW5jeTogMTAsIHJhdGU6IDUgfSwgb3BlcmF0aW9uKTtcbiAqIGZvcihsZXQgaSA9IDA7IGkgPCAxMDA7IGkrKykge1xuICogICAgIC8vIGF0IG1vc3QgMTAgY29uY3VycmVudCBleGVjdXRpb25zIGF0IGEgcmF0ZSBvZiA1IGludm9jYXRpb25zIHBlciBzZWNvbmQuXG4gKiAgICAgdGhyb3R0bGVkT3BlcmF0aW9uKCk7XG4gKiB9XG4gKiBgYGBcbiAqXG4gKiBOb3RlIHRoYXQgZWFjaCBpbnZvY2F0aW9uIHRvIGB0aHJvdHRsZWAgY3JlYXRlcyBhIHNlcGFyYXRlIGZ1bmN0aW9uIHdpdGggYVxuICogc2VwYXJhdGUgbGltaXRzLiBUaGVyZWZvcmUgaXQgaXMgbGlrZWx5IHRoYXQgeW91IHdhbnQgdG8gdXNlIGB0aHJvdHRsZWAgaW4gYVxuICogZ2xvYmFsIGNvbnRleHQsIG5vdCB3aXRoaW4gYSBkeW5hbWljIGNvbnRleHQ6XG4gKlxuICogYGBgdHlwZXNjcmlwdFxuICogYXN5bmMgZnVuY3Rpb24gb3BlcmF0aW9uKCkgeyAuLi4gfVxuICogZm9yKGxldCBpID0gMDsgaSA8IDEwMDsgaSsrKSB7XG4gKiAgICAgLy8gV1JPTkcgLSBlYWNoIGl0ZXJhdGlvbiBjcmVhdGVzIGEgc2VwYXJhdGUgdGhyb3R0bGVkIGZ1bmN0aW9uIHRoYXQncyBvbmx5IGNhbGxlZCBvbmNlLlxuICogICAgIGNvbnN0IHRocm90dGxlZE9wZXJhdGlvbiA9IHRocm90dGxlKHsgY29uY3VycmVuY3k6IDEwLCByYXRlOiA1IH0sIG9wZXJhdGlvbik7XG4gKiAgICAgdGhyb3R0bGVkT3BlcmF0aW9uKCk7XG4gKiB9XG4gKiBgYGBcbiAqXG4gKiBBIGJldHRlciB3YXkgdG8gdXNlIHRocm90dGxlIGF2b2lkcyBjcmVhdGluZyBhIG5hbWVkIGBvcGVyYXRpb25gIGZ1bmN0aW9uXG4gKiBhbHRvZ2V0aGVyLCBlbnN1cmluZyBpdCBjYW5ub3QgYmUgYWNjaWRlbnRhbGx5IGNhbGxlZCB3aXRob3V0IHRocm90dGxpbmc6XG4gKlxuICogYGBgdHlwZXNjcmlwdFxuICogY29uc3Qgb3BlcmF0aW9uID0gdGhyb3R0bGUoeyBjb25jdXJyZW5jeTogMTAsIHJhdGU6IDUgfSwgYXN5bmMgKCkgPT4ge1xuICogICAgIC4uLlxuICogfSk7XG4gKiBgYGBcbiAqXG4gKiBUaHJvdHRsZSBzdXBwb3J0cyBmdW5jdGlvbnMgd2l0aCBhcmd1bWVudHMgYXV0b21hdGljYWxseSBpbmZlcnMgdGhlIGNvcnJlY3RcbiAqIHR5cGUgZm9yIHRoZSByZXR1cm5lZCBmdW5jdGlvbjpcbiAqXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBgb3BlcmF0aW9uYCBpbmZlcnJlZCB0byBoYXZlIHR5cGUgKHN0cjogc3RyaW5nKSA9PiBQcm9taXNlPHN0cmluZz5cbiAqIGNvbnN0IG9wZXJhdGlvbiA9IHRocm90dGxlKHsgY29uY3VycmVuY3k6IDEwLCByYXRlOiA1IH0sIGFzeW5jIChzdHI6IHN0cmluZykgPT4ge1xuICogICAgIHJldHVybiBzdHJpbmc7XG4gKiB9KTtcbiAqIGBgYFxuICpcbiAqIEluIGFkZGl0aW9uIHRvIGxpbWl0aW5nIGNvbmN1cnJlbmN5IGFuZCBpbnZvY2F0aW9uIHJhdGUsIGB0aHJvdHRsZWAgYWxzb1xuICogc3VwcG9ydHMgcmV0cnlpbmcgZmFpbGVkIGludm9jYXRpb25zLCBtZW1vaXppbmcgY2FsbHMsIGFuZCBvbi1kaXNrIGNhY2hpbmcuXG4gKiBTZWUge0BsaW5rIExpbWl0c30gZm9yIGRldGFpbHMuXG4gKlxuICogQHBhcmFtIGxpbWl0cyAtIHNlZSB7QGxpbmsgTGltaXRzfS5cbiAqIEBwYXJhbSBmbiAtIFRoZSBmdW5jdGlvbiB0byB0aHJvdHRsZS4gSXQgY2FuIHRha2UgYW55IGFyZ3VtZW50cywgYnV0IG11c3RcbiAqIHJldHVybiBhIFByb21pc2UgKHdoaWNoIGluY2x1ZGVzIGBhc3luY2AgZnVuY3Rpb25zKS5cbiAqIEByZXR1cm5zIFJldHVybnMgYSB0aHJvdHRsZWQgZnVuY3Rpb24gd2l0aCB0aGUgc2FtZSBzaWduYXR1cmUgYXMgdGhlIGFyZ3VtZW50XG4gKiBgZm5gLlxuICogQHB1YmxpY1xuICovXG5leHBvcnQgZnVuY3Rpb24gdGhyb3R0bGU8QSBleHRlbmRzIGFueVtdLCBSPihcbiAgICBsaW1pdHM6IExpbWl0cyxcbiAgICBmbjogKC4uLmFyZ3M6IEEpID0+IFByb21pc2U8Uj5cbik6ICguLi5hcmdzOiBBKSA9PiBQcm9taXNlPFI+IHtcbiAgICBjb25zdCB7IGNvbmN1cnJlbmN5LCByZXRyeSwgcmF0ZSwgYnVyc3QsIG1lbW9pemUsIGNhY2hlLCBjYW5jZWwgfSA9IGxpbWl0cztcbiAgICBjb25zdCBmdW5uZWwgPSBuZXcgRnVubmVsPFI+KGNvbmN1cnJlbmN5LCByZXRyeSk7XG4gICAgY29uc3QgY2FuY2VsbGF0aW9uUXVldWUgPSBbKCkgPT4gZnVubmVsLmNsZWFyKCldO1xuXG4gICAgbGV0IGNvbmRpdGlvbmVkRnVuYzogKC4uLmFyZ3M6IEEpID0+IFByb21pc2U8Uj47XG5cbiAgICBpZiAocmF0ZSkge1xuICAgICAgICBjb25zdCByYXRlTGltaXRlciA9IG5ldyBSYXRlTGltaXRlcjxSPihyYXRlLCBidXJzdCk7XG4gICAgICAgIGNhbmNlbGxhdGlvblF1ZXVlLnB1c2goKCkgPT4gcmF0ZUxpbWl0ZXIuY2xlYXIoKSk7XG4gICAgICAgIGNvbmRpdGlvbmVkRnVuYyA9ICguLi5hcmdzOiBBKSA9PlxuICAgICAgICAgICAgZnVubmVsLnB1c2goKCkgPT4gcmF0ZUxpbWl0ZXIucHVzaCgoKSA9PiBmbiguLi5hcmdzKSkpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbmRpdGlvbmVkRnVuYyA9ICguLi5hcmdzOiBBKSA9PiBmdW5uZWwucHVzaCgoKSA9PiBmbiguLi5hcmdzKSk7XG4gICAgfVxuXG4gICAgaWYgKGNhY2hlKSB7XG4gICAgICAgIGNvbmRpdGlvbmVkRnVuYyA9IGNhY2hlRm4oY2FjaGUsIGNvbmRpdGlvbmVkRnVuYyk7