@ortoo/angular-resource
Version:
Magical CRUD resource management for angular
549 lines • 72.7 kB
JavaScript
import { cloneDeep } from 'lodash';
import { clone } from 'lodash';
import { map } from 'lodash';
import { union } from 'lodash';
import { isFunction } from 'lodash';
import { isEmpty } from 'lodash';
import { isUndefined } from 'lodash';
import { ArrayEmitter } from './array-emitter.js';
import { Chain } from './chain';
import { convertToResolvedSubject, Deferred } from './utils';
export class Query extends ArrayEmitter {
}
export class LocalQuery extends Query {
}
export class ServerQuery extends Query {
}
function normalizeQuery(qry) {
if (!qry) {
return;
}
if (qry._q) {
return qry._q;
}
else if (qry.find) {
return qry;
}
else {
return { find: qry };
}
}
function extendQuery(qry1, qry2) {
// Calc the new query that we want
const _qry = cloneDeep(qry1);
['limit', 'skip', 'sort'].forEach(prop => {
if (qry2[prop]) {
_qry[prop] = qry2[prop];
}
});
if (!isEmpty(qry2.find)) {
// Want to or together - but is the toplevel already an or? (and only an or)
let existingOr = false;
if (_qry.find.$or) {
let valid = true;
for (const key in _qry.find) {
if (key !== '$or') {
valid = false;
break;
}
}
existingOr = valid;
}
if (existingOr) {
_qry.find = clone(_qry.find);
}
else {
_qry.find = { $or: [_qry.find] };
}
_qry.find.$or.push(qry2.find);
}
return _qry;
}
export function createQueryFactory(socket) {
function QueryFactory(url, rootKey, rootKeyPlural, db) {
const sock = socket(url, rootKey, rootKeyPlural);
// Object holding queries (keys are the query ids, values are arrays of arrays)
const _localQueries = [];
/**
* Local Query List
* @param {[type]} qry [description]
* @param {[type]} limit [description]
* @param {[type]} Resource [description]
* @param {[type]} toRes [description]
*
* Strategy - we run the query on the server. However if we can deal with it locally (via
* nedb) then do so. If the query at any time becomes more complicated we just fall through
* to the server version
*/
const LocalQueryList = (qry, limit, Resource, toRes) => {
// Allow qry to be a promise, and we return the raw (non _q bit)
qry = Promise.resolve(qry).then(normalizeQuery).then(_qry => {
if (limit) {
_qry.limit = limit;
}
return _qry;
});
// Generate the ServerQuery. We do this so we have something to fall back on
// and also so that we will (or should!) get notified of changes from the server if
// someone else creates or removes something that should go in these results
const serverResults = ServerQueryList(qry, limit, Resource);
const results = new LocalQuery();
_localQueries.push(results);
let currentLimit = 0;
let currentSkip = 0;
let lastBatchSize = 0;
let fallback = false;
results.loading = true;
// When the server results are updated we want to check paging options and apply
// them to our results
serverResults.$emitter.on('update', syncFromServer);
function syncFromServer() {
results.hasNext = serverResults.hasNext;
results.hasPrev = serverResults.hasPrev;
// If we are falling back then set up and copy our letious properties across
if (fallback) {
results.$hasNext = false;
results.$hasPrev = false;
results.length = 0;
serverResults.forEach(res => {
results.push(res);
});
currentLimit = results.length;
currentSkip = results.$skip;
lastBatchSize = lastBatchSize || results.length;
}
}
function get() {
return Resource.get.apply(Resource, arguments);
}
function chain(Model, qryFn) {
return Chain(results, Model, qryFn);
}
function query(_qry) {
// Store off the qry making sure its a promise
qry = Promise.resolve(_qry);
fallback = !db.qryIsSimple(_qry);
// If we are fallingback then just resolve with our results. The server should
// do the rest.
if (fallback) {
// We want to return the server's promise here so that people will be notified
// when the results are actually loaded
let prom;
if (!serverResults.$resolved) {
prom = serverResults.$promise.then(() => {
return results;
});
}
else {
prom = Promise.resolve(results);
}
return prom;
}
return db.query(_qry).then((ids) => {
// We can set the hasNext and hasPrev values to true here if we know there
// are some. However only the server has the definitive ability to say
// there arent any
results.$hasNext = false;
results.$hasPrev = false;
if (limit && ids.length > limit) {
// We have more results to fetch
results.hasNext = true;
results.$hasNext = true;
// Trim the results down to size
ids.length -= 1;
}
const skip = _qry.skip;
if (skip) {
results.hasPrev = true;
results.$hasPrev = true;
}
// Calculate paging options
currentLimit = ids.length;
currentSkip = skip || 0;
lastBatchSize = lastBatchSize || ids.length;
// Go to resource types
const tmpResults = ids.map(toRes);
// Do we need to do a transform?
let rprom;
if (isFunction(results.transform)) {
rprom = Promise.resolve(results.transform(tmpResults));
}
else {
rprom = Promise.resolve(tmpResults);
}
return rprom.then(transformed => {
// Put the resources into the list
const old = results.slice();
results.length = 0;
transformed.forEach((res) => {
results.push(res);
});
results.$emitter.emit('update', results, old);
return results;
});
});
}
function refreshQuery(forceServer) {
// Perform our query
let prom = qry.then(query).then((res) => {
// If we don't have any results then maybe wait for the server to return
if ((res.length === 0 && !serverResults.$resolved)) {
return serverResults.$promise.then(() => {
return refreshQuery();
});
}
else {
return res;
}
});
if (forceServer) {
prom = serverResults.$refresh(true);
}
return prom.then((res) => {
results.loading = false;
return res;
});
}
function extendResults(obj, noSanitize, retServer) {
// Sanitize the object
if (!noSanitize) {
if (obj._q) {
obj = obj._q;
}
else {
obj = { find: obj };
}
}
return qry.then((resolved) => {
const _qry = extendQuery(resolved, obj);
return replace(_qry, retServer);
});
}
function replace(_qry, retServer) {
// Sync down to the serverquery
const serverProm = serverResults.replace(_qry);
// Do the query but replace the existing query
const localProm = Promise.resolve(_qry).then(normalizeQuery).then(normQry => {
// We allow a query to resolve to something falsy - in which case we just
// drop it
if (!normQry) {
return;
}
return qry.then((oldqry) => {
if (JSON.stringify(oldqry) !== JSON.stringify(normQry)) {
// query is different - continue
return query(normQry);
}
});
});
return retServer ? serverProm : localProm;
}
function next(num) {
let promise;
let extendSize;
if (results.hasNext) {
lastBatchSize = extendSize = num || lastBatchSize;
const extendObj = {
limit: currentLimit + extendSize,
};
promise = extendResults(extendObj, true, !results.$hasNext);
}
else {
const deferred = new Deferred();
deferred.resolve();
promise = deferred.promise;
}
return promise;
}
function prev(num) {
let promise;
let extendSize;
if (results.hasPrev) {
lastBatchSize = extendSize = num || lastBatchSize;
const extendObj = {
limit: currentLimit + extendSize,
skip: Math.max(currentSkip - extendSize, 0),
};
promise = extendResults(extendObj, true, !results.$hasPrev);
}
else {
const deferred = new Deferred();
deferred.resolve();
promise = deferred.promise;
}
return promise;
}
results.$refresh = refreshQuery;
results.extend = extendResults;
results.replace = replace;
results.get = get;
results.next = next;
results.prev = prev;
results.$promise = refreshQuery();
results.$resolvedSubject = convertToResolvedSubject(results.$subject, results.$promise);
results.chain = chain;
results.$Model = Resource;
results.$serverResults = serverResults;
// Put currentSkip and currentLimit onto the results
Object.defineProperty(results, 'currentLimit', {
enumerable: true,
get: () => {
return currentLimit;
},
});
Object.defineProperty(results, 'currentSkip', {
enumerable: true,
get: () => {
return currentSkip;
},
});
return results;
};
let refreshTimer;
LocalQueryList.refresh = () => {
// If we have a timer outstanding then just return - a refresh will happen soon.
if (!refreshTimer) {
refreshTimer = setTimeout(doRefresh, 100);
}
return refreshTimer;
function doRefresh() {
_localQueries.forEach(res => {
res.$refresh();
});
refreshTimer = null;
}
};
/**
* Server query list. The server makes sure we keep in sync
* @param {[type]} qry [description]
* @param {[type]} limit [description]
* @param {[type]} Resource [description]
*/
function ServerQueryList(qry, limit, Resource) {
// Allow qry to be a promise
qry = Promise.resolve(qry).then(normalizeQuery).then(_qry => {
if (limit) {
_qry.limit = limit;
}
return _qry;
});
let emitPromise = null;
const results = new ServerQuery();
let currentLimit = 0;
let currentSkip = 0;
let lastBatchSize = 0;
let _pagingOpts = {};
results.loading = true;
function query(data) {
// We only want to do one emit at a time (otherwise we could get into a bad state)
if (isFunction(data)) {
data = data();
}
// Store off the query - make sure its a promise
qry = Promise.resolve(data);
return qry.then((_data) => {
// If we have an existing emitPromise then wait for it to resolve before we run
let promise;
if (emitPromise) {
promise = emitPromise.then(() => {
return sock.query(_data);
});
}
else {
emitPromise = promise = sock.query(_data);
}
return promise;
});
}
function newData(_qryId, response, force) {
if (!response) {
return;
}
const deferred = new Deferred();
const ids = response.ids;
const pagingOpts = response.pagingOpts;
// So far we've only got the ids of the qry result - go and fetch the actual objects.
// This mechanism saves bandwidth by only getting the object data once then listening
// for changes to it
//
// If we are forcing we want to get both the old and new ids to check for any changes
// deletions etc..
let getIds = ids;
if (force) {
const oldIds = map(results, '_id');
getIds = union(ids, oldIds);
}
Resource.get(getIds, force).$promise.then((ress) => {
const ressmap = {};
ress.forEach(res => {
ressmap[res._id] = res;
});
// We don't allow repeated ids so just iterate over the results
const tmpResults = [];
ids.forEach(id => {
tmpResults.push(ressmap[id]);
});
// Do we need to do a transform?
let rprom;
if (isFunction(results.transform)) {
rprom = Promise.resolve(results.transform(tmpResults));
}
else {
rprom = Promise.resolve(tmpResults);
}
return rprom.then(transformed => {
results.length = 0;
transformed.forEach((res) => {
results.push(res);
});
// Since we now have data in our array store off limit data
currentLimit = tmpResults.length;
results.$skip = currentSkip = (qry && qry.skip) ? qry.skip : 0;
lastBatchSize = lastBatchSize || tmpResults.length;
_pagingOpts = pagingOpts;
results.hasNext = (pagingOpts.next != null);
results.hasPrev = (pagingOpts.prev != null);
// Data has come back
results.loading = false;
results.$emitter.emit('update', results);
deferred.resolve(results);
});
});
return deferred.promise;
}
function refreshQuery(force) {
const req = query(qry);
const promise = req.then((res) => {
// If we get no response (the app could be offline) then just resolve with
// the existing results
if (isUndefined(res)) {
results.loading = false;
return results;
}
const _qryId = res.qryId;
const response = res.data;
return newData(_qryId, response, force);
});
return promise;
}
function replace(_qry) {
// Do the query but replace the existing query
return Promise.resolve(_qry).then(normalizeQuery).then(normQry => {
// We allow a query to resolve to something falsy - in which case we just
// drop it
if (!normQry) {
return;
}
return qry.then((oldqry) => {
if (JSON.stringify(oldqry) !== JSON.stringify(normQry)) {
// query is different - continue
const req = query(normQry);
const promise = req.then((res) => {
// If we get no response (the app could be offline) then just resolve with
// the existing results
if (isUndefined(res)) {
results.loading = false;
return results;
}
// We do have a response. Continue
const _qryId = res.qryId;
const data = res.data;
return newData(_qryId, data);
});
return promise;
}
});
});
}
function extendResults(obj, noSanitize) {
// Sanitize the object
if (!noSanitize) {
if (obj._q) {
obj = obj._q;
}
else {
obj = { find: obj };
}
}
return qry.then((resolved) => {
const _qry = extendQuery(resolved, obj);
return replace(_qry);
});
}
function next(num) {
let promise;
let extendSize;
if (_pagingOpts.next) {
lastBatchSize = extendSize = num || lastBatchSize;
const extendObj = {
limit: currentLimit + extendSize,
};
promise = extendResults(extendObj, true);
}
else {
const deferred = new Deferred();
deferred.resolve();
promise = deferred.promise;
}
return promise;
}
function prev(num) {
let promise;
let extendSize;
if (_pagingOpts.prev) {
lastBatchSize = extendSize = num || lastBatchSize;
const extendObj = {
limit: currentLimit + extendSize,
skip: Math.max(currentSkip - extendSize, 0),
};
promise = extendResults(extendObj, true);
}
else {
const deferred = new Deferred();
deferred.resolve();
promise = deferred.promise;
}
return promise;
}
function get() {
return Resource.get.apply(Resource, arguments);
}
function chain(Model, qryFn) {
return Chain(results, Model, qryFn);
}
results.$newData = newData;
results.$refresh = refreshQuery;
results.extend = extendResults;
results.replace = replace;
results.get = get;
results.next = next;
results.prev = prev;
results.$promise = refreshQuery().then(res => {
results.$resolved = true;
return res;
});
results.$resolvedSubject = convertToResolvedSubject(results.$subject, results.$promise);
results.$resolved = false;
results.chain = chain;
results.$Model = Resource;
results.$skip = 0;
// Put currentSkip and currentLimit onto the results
Object.defineProperty(results, 'currentLimit', {
enumerable: true,
get: () => {
return currentLimit;
},
});
Object.defineProperty(results, 'currentSkip', {
enumerable: true,
get: () => {
return currentSkip;
},
});
return results;
}
return db ? LocalQueryList : ServerQueryList;
}
return QueryFactory;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVlcnkuanMiLCJzb3VyY2VSb290IjoiL0BvcnRvby9hbmd1bGFyLXJlc291cmNlLyIsInNvdXJjZXMiOlsicXVlcnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBSUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUNuQyxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBQy9CLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFDN0IsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUMvQixPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFDakMsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUVyQyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDbEQsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUVoQyxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsUUFBUSxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBRTdELE1BQU0sWUFBZ0IsU0FBUSxZQUFlO0NBd0I1QztBQUVELE1BQU0saUJBQXFCLFNBQVEsS0FBUTtDQUFHO0FBRTlDLE1BQU0sa0JBQXNCLFNBQVEsS0FBUTtDQUUzQztBQUVELHdCQUF3QixHQUFRO0lBQzlCLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNULE1BQU0sQ0FBQztJQUNULENBQUM7SUFFRCxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUNYLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO0lBQ2hCLENBQUM7SUFBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDcEIsTUFBTSxDQUFD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QUMsS0FBSyxHQUFHLEtBQUssQ0FBQztZQUN0QixPQUFPLENBQUMsTUFBTSxHQUFHLFFBQVEsQ0FBQztZQUMxQixPQUFPLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQztZQUVsQixvREFBb0Q7WUFDcEQsTUFBTSxDQUFDLGNBQWMsQ0FBQyxPQUFPLEVBQUUsY0FBYyxFQUFFO2dCQUM3QyxVQUFVLEVBQUUsSUFBSTtnQkFDaEIsR0FBRyxFQUFFO29CQUNILE1BQU0sQ0FBQyxZQUFZLENBQUM7Z0JBQ3RCLENBQUM7YUFDRixDQUFDLENBQUM7WUFDSCxNQUFNLENBQUMsY0FBYyxDQUFDLE9BQU8sRUFBRSxhQUFhLEVBQUU7Z0JBQzVDLFVBQVUsRUFBRSxJQUFJO2dCQUNoQixHQUFHLEVBQUU7b0JBQ0gsTUFBTSxDQUFDLFdBQVcsQ0FBQztnQkFDckIsQ0FBQzthQUNGLENBQUMsQ0FBQztZQUVILE1BQU0sQ0FBQyxPQUFPLENBQUM7UUFDakIsQ0FBQztRQUVELE1BQU0sQ0FBQyxFQUFFLEdBQUcsY0FBYyxHQUFHLGVBQWUsQ0FBQztJQUMvQyxDQUFDO0lBRUQsTUFBTSxDQUFDLFlBQVksQ0FBQztBQUN0QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gdHNsaW50OmRpc2FibGUgbWF4LWNsYXNzZXMtcGVyLWZpbGUgaW50ZXJmYWNlLW5hbWVcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCB9IGZyb20gJ3J4anMvQmVoYXZpb3JTdWJqZWN0JztcbmltcG9ydCB7IFN1YmplY3QgfSBmcm9tICdyeGpzL1N1YmplY3QnO1xuXG5pbXBvcnQgeyBjbG9uZURlZXAgfSBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IHsgY2xvbmUgfSBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IHsgbWFwIH0gZnJvbSAnbG9kYXNoJztcbmltcG9ydCB7IHVuaW9uIH0gZnJvbSAnbG9kYXNoJztcbmltcG9ydCB7IGlzRnVuY3Rpb24gfSBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IHsgaXNFbXB0eSB9IGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgeyBpc1VuZGVmaW5lZCB9IGZyb20gJ2xvZGFzaCc7XG5cbmltcG9ydCB7IEFycmF5RW1pdHRlciB9IGZyb20gJy4vYXJyYXktZW1pdHRlci5qcyc7XG5pbXBvcnQgeyBDaGFpbiB9IGZyb20gJy4vY2hhaW4nO1xuaW1wb3J0IHsgRGF0YWJhc2UsIE1vZGVsLCBRdWVyeSBhcyBJUXVlcnksIFF1ZXJ5RnVuY3Rpb24sIFF1ZXJ5TGlzdCwgUmVzb3VyY2UsIFNvY2tldEZhY3RvcnkgfSBmcm9tICcuL3R5cGVzJztcbmltcG9ydCB7IGNvbnZlcnRUb1Jlc29sdmVkU3ViamVjdCwgRGVmZXJyZWQgfSBmcm9tICcuL3V0aWxzJztcblxuZXhwb3J0IGNsYXNzIFF1ZXJ5PFQ+IGV4dGVuZHMgQXJyYXlFbWl0dGVyPFQ+IGltcGxlbWVudHMgSVF1ZXJ5PFQ+IHtcbiAgcHVibGljICRyZWZyZXNoOiAoZm9yY2U/OiBib29sZWFuKSA9PiBQcm9taXNlPFF1ZXJ5PFQ+PjtcbiAgcHVibGljICRwcm9taXNlOiBQcm9taXNlPFF1ZXJ5PFQ+PjtcbiAgcHVibGljICRzdWJqZWN0OiBCZWhhdmlvclN1YmplY3Q8UXVlcnk8VD4+O1xuICBwdWJsaWMgJHJlc29sdmVkU3ViamVjdDogU3ViamVjdDxRdWVyeTxUPj47XG4gIHB1YmxpYyAkcmVzb2x2ZWQ6IGJvb2xlYW47XG4gIHB1YmxpYyAkTW9kZWw6IGFueTtcbiAgcHVibGljICRzZXJ2ZXJSZXN1bHRzPzogUXVlcnk8VD47XG4gIHB1YmxpYyAkc2tpcD86IG51bWJlcjtcbiAgcHVibGljICRoYXNOZXh0OiBib29sZWFuO1xuICBwdWJsaWMgJGhhc1ByZXY6IGJvb2xlYW47XG5cbiAgcHVibGljIGV4dGVuZDogKG9iajogYW55LCBub1Nhbml0aXplPzogYm9vbGVhbiwgcmV0U2VydmVyPzogYm9vbGVhbikgPT4gUHJvbWlzZTxRdWVyeTxUPj47XG4gIHB1YmxpYyByZXBsYWNlOiAocXJ5OiBhbnksIHJldFNlcnZlcj86IGJvb2xlYW4pID0+IFByb21pc2U8UXVlcnk8VD4+O1xuICBwdWJsaWMgZ2V0OiAoLi4uYXJnczogYW55W10pID0+IGFueTtcbiAgcHVibGljIG5leHQ6IChudW0/OiBudW1iZXIpID0+IFByb21pc2U8UXVlcnk8VD4+O1xuICBwdWJsaWMgcHJldjogKG51bT86IG51bWJlcikgPT4gUHJvbWlzZTxRdWVyeTxUPj47XG4gIHB1YmxpYyBjaGFpbjogKE1vZGVsOiBSZXNvdXJjZTxNb2RlbD4gfCBRdWVyeUZ1bmN0aW9uLCBxcnlGbj86IFF1ZXJ5RnVuY3Rpb24pID0+IElRdWVyeTxNb2RlbD47XG4gIHB1YmxpYyB0cmFuc2Zvcm06ICh0bXBSZXN1bHRzOiBhbnlbXSkgPT4gUHJvbWlzZTxhbnlbXT4gfCBhbnlbXTtcbiAgcHVibGljIGN1cnJlbnRMaW1pdDogbnVtYmVyO1xuICBwdWJsaWMgY3VycmVudFNraXA6IG51bWJlcjtcbiAgcHVibGljIGxvYWRpbmc6IGJvb2xlYW47XG4gIHB1YmxpYyBoYXNOZXh0OiBib29sZWFuO1xuICBwdWJsaWMgaGFzUHJldjogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGNsYXNzIExvY2FsUXVlcnk8VD4gZXh0ZW5kcyBRdWVyeTxUPiB7fVxuXG5leHBvcnQgY2xhc3MgU2VydmVyUXVlcnk8VD4gZXh0ZW5kcyBRdWVyeTxUPiB7XG4gIHB1YmxpYyAkbmV3RGF0YT86IChxcnlJZDogc3RyaW5nLCByZXNwb25zZTogYW55LCBmb3JjZT86IGJvb2xlYW4pID0+IHZvaWQ7XG59XG5cbmZ1bmN0aW9uIG5vcm1hbGl6ZVF1ZXJ5KHFyeTogYW55KSB7XG4gIGlmICghcXJ5KSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaWYgKHFyeS5fcSkge1xuICAgIHJldHVybiBxcnkuX3E7XG4gIH0gZWxzZSBpZiAocXJ5LmZpbmQpIHtcbiAgICByZXR1cm4gcXJ5O1xuICB9IGVsc2Uge1xuICAgIHJldHVybiB7ZmluZDogcXJ5fTtcbiAgfVxufVxuXG5mdW5jdGlvbiBleHRlbmRRdWVyeShxcnkxOiBhbnksIHFyeTI6IGFueSkge1xuICAvLyBDYWxjIHRoZSBuZXcgcXVlcnkgdGhhdCB3ZSB3YW50XG4gIGNvbnN0IF9xcnkgPSBjbG9uZURlZXAocXJ5MSk7XG4gIFsnbGltaXQnLCAnc2tpcCcsICdzb3J0J10uZm9yRWFjaChwcm9wID0+IHtcbiAgICBpZiAocXJ5Mltwcm9wXSkge1xuICAgICAgX3FyeVtwcm9wXSA9IHFyeTJbcHJvcF07XG4gICAgfVxuICB9KTtcblxuICBpZiAoIWlzRW1wdHkocXJ5Mi5maW5kKSkge1xuICAgIC8vIFdhbnQgdG8gb3IgdG9nZXRoZXIgLSBidXQgaXMgdGhlIHRvcGxldmVsIGFscmVhZHkgYW4gb3I/IChhbmQgb25seSBhbiBvcilcbiAgICBsZXQgZXhpc3RpbmdPciA9IGZhbHNlO1xuICAgIGlmIChfcXJ5LmZpbmQuJG9yKSB7XG4gICAgICBsZXQgdmFsaWQgPSB0cnVlO1xuICAgICAgZm9yIChjb25zdCBrZXkgaW4gX3FyeS5maW5kKSB7XG4gICAgICAgIGlmIChrZXkgIT09ICckb3InKSB7XG4gICAgICAgICAgdmFsaWQgPSBmYWxzZTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgZXhpc3RpbmdPciA9IHZhbGlkO1xuICAgIH1cblxuICAgIGlmIChleGlzdGluZ09yKSB7XG4gICAgICBfcXJ5LmZpbmQgPSBjbG9uZShfcXJ5LmZpbmQpO1xuICAgIH0gZWxzZSB7XG4gICAgICBfcXJ5LmZpbmQgPSB7JG9yOiBbX3FyeS5maW5kXX07XG4gICAgfVxuXG4gICAgX3FyeS5maW5kLiRvci5wdXNoKHFyeTIuZmluZCk7XG4gIH1cblxuICByZXR1cm4gX3FyeTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVF1ZXJ5RmFjdG9yeShzb2NrZXQ6IFNvY2tldEZhY3RvcnkpIHtcblxuICBmdW5jdGlvbiBRdWVyeUZhY3RvcnkodXJsOiBzdHJpbmcsIHJvb3RLZXk6IHN0cmluZywgcm9vdEtleVBsdXJhbDogc3RyaW5nLCBkYj86IERhdGFiYXNlKTogUXVlcnlMaXN0IHtcbiAgICBjb25zdCBzb2NrID0gc29ja2V0KHVybCwgcm9vdEtleSwgcm9vdEtleVBsdXJhbCk7XG5cbiAgICAvLyBPYmplY3QgaG9sZGluZyBxdWVyaWVzIChrZXlzIGFyZSB0aGUgcXVlcnkgaWRzLCB2YWx1ZXMgYXJlIGFycmF5cyBvZiBhcnJheXMpXG4gICAgY29uc3QgX2xvY2FsUXVlcmllczogQXJyYXk8TG9jYWxRdWVyeTxNb2RlbD4+ID0gW107XG5cbiAgICAvKipcbiAgICAgKiBMb2NhbCBRdWVyeSBMaXN0XG4gICAgICogQHBhcmFtIHtbdHlwZV19IHFyeSAgICAgIFtkZXNjcmlwdGlvbl1cbiAgICAgKiBAcGFyYW0ge1t0eXBlXX0gbGltaXQgICAgW2Rlc2NyaXB0aW9uXVxuICAgICAqIEBwYXJhbSB7W3R5cGVdfSBSZXNvdXJjZSBbZGVzY3JpcHRpb25dXG4gICAgICogQHBhcmFtIHtbdHlwZV19IHRvUmVzICAgIFtkZXNjcmlwdGlvbl1cbiAgICAgKlxuICAgICAqIFN0cmF0ZWd5IC0gd2UgcnVuIHRoZSBxdWVyeSBvbiB0aGUgc2VydmVyLiBIb3dldmVyIGlmIHdlIGNhbiBkZWFsIHdpdGggaXQgbG9jYWxseSAodmlhXG4gICAgICogbmVkYikgdGhlbiBkbyBzby4gSWYgdGhlIHF1ZXJ5IGF0IGFueSB0aW1lIGJlY29tZXMgbW9yZSBjb21wbGljYXRlZCB3ZSBqdXN0IGZhbGwgdGhyb3VnaFxuICAgICAqIHRvIHRoZSBzZXJ2ZXIgdmVyc2lvblxuICAgICAqL1xuICAgIGNvbnN0IExvY2FsUXVlcnlMaXN0OiBRdWVyeUxpc3QgPSAocXJ5OiBhbnksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW1pdDogbnVtYmVyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUmVzb3VyY2U6IFJlc291cmNlPE1vZGVsPixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvUmVzOiAoaWQ6IHN0cmluZykgPT4gTW9kZWwpOiBMb2NhbFF1ZXJ5PE1vZGVsPiA9PiB7XG4gICAgICAvLyBBbGxvdyBxcnkgdG8gYmUgYSBwcm9taXNlLCBhbmQgd2UgcmV0dXJuIHRoZSByYXcgKG5vbiBfcSBiaXQpXG4gICAgICBxcnkgPSBQcm9taXNlLnJlc29sdmUocXJ5KS50aGVuKG5vcm1hbGl6ZVF1ZXJ5KS50aGVuKF9xcnkgPT4ge1xuICAgICAgICBpZiAobGltaXQpIHtcbiAgICAgICAgICBfcXJ5LmxpbWl0ID0gbGltaXQ7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIF9xcnk7XG4gICAgICB9KTtcblxuICAgICAgLy8gR2VuZXJhdGUgdGhlIFNlcnZlclF1ZXJ5LiBXZSBkbyB0aGlzIHNvIHdlIGhhdmUgc29tZXRoaW5nIHRvIGZhbGwgYmFjayBvblxuICAgICAgLy8gYW5kIGFsc28gc28gdGhhdCB3ZSB3aWxsIChvciBzaG91bGQhKSBnZXQgbm90aWZpZWQgb2YgY2hhbmdlcyBmcm9tIHRoZSBzZXJ2ZXIgaWZcbiAgICAgIC8vIHNvbWVvbmUgZWxzZSBjcmVhdGVzIG9yIHJlbW92ZXMgc29tZXRoaW5nIHRoYXQgc2hvdWxkIGdvIGluIHRoZXNlIHJlc3VsdHNcbiAgICAgIGNvbnN0IHNlcnZlclJlc3VsdHMgPSBTZXJ2ZXJRdWVyeUxpc3QocXJ5LCBsaW1pdCwgUmVzb3VyY2UpO1xuXG4gICAgICBjb25zdCByZXN1bHRzID0gbmV3IExvY2FsUXVlcnk8TW9kZWw+KCk7XG4gICAgICBfbG9jYWxRdWVyaWVzLnB1c2gocmVzdWx0cyk7XG4gICAgICBsZXQgY3VycmVudExpbWl0ID0gMDtcbiAgICAgIGxldCBjdXJyZW50U2tpcCA9IDA7XG4gICAgICBsZXQgbGFzdEJhdGNoU2l6ZSA9IDA7XG4gICAgICBsZXQgZmFsbGJhY2sgPSBmYWxzZTtcblxuICAgICAgcmVzdWx0cy5sb2FkaW5nID0gdHJ1ZTtcblxuICAgICAgLy8gV2hlbiB0aGUgc2VydmVyIHJlc3VsdHMgYXJlIHVwZGF0ZWQgd2Ugd2FudCB0byBjaGVjayBwYWdpbmcgb3B0aW9ucyBhbmQgYXBwbHlcbiAgICAgIC8vIHRoZW0gdG8gb3VyIHJlc3VsdHNcbiAgICAgIHNlcnZlclJlc3VsdHMuJGVtaXR0ZXIub24oJ3VwZGF0ZScsIHN5bmNGcm9tU2VydmVyKTtcblxuICAgICAgZnVuY3Rpb24gc3luY0Zyb21TZXJ2ZXIoKSB7XG4gICAgICAgIHJlc3VsdHMuaGFzTmV4dCA9IHNlcnZlclJlc3VsdHMuaGFzTmV4dDtcbiAgICAgICAgcmVzdWx0cy5oYXNQcmV2ID0gc2VydmVyUmVzdWx0cy5oYXNQcmV2O1xuXG4gICAgICAgIC8vIElmIHdlIGFyZSBmYWxsaW5nIGJhY2sgdGhlbiBzZXQgdXAgYW5kIGNvcHkgb3VyIGxldGlvdXMgcHJvcGVydGllcyBhY3Jvc3NcbiAgICAgICAgaWYgKGZhbGxiYWNrKSB7XG4gICAgICAgICAgcmVzdWx0cy4kaGFzTmV4dCA9IGZhbHNlO1xuICAgICAgICAgIHJlc3VsdHMuJGhhc1ByZXYgPSBmYWxzZTtcbiAgICAgICAgICByZXN1bHRzLmxlbmd0aCA9IDA7XG4gICAgICAgICAgc2VydmVyUmVzdWx0cy5mb3JFYWNoKHJlcyA9PiB7XG4gICAgICAgICAgICByZXN1bHRzLnB1c2gocmVzKTtcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGN1cnJlbnRMaW1pdCA9IHJlc3VsdHMubGVuZ3RoO1xuICAgICAgICAgIGN1cnJlbnRTa2lwID0gcmVzdWx0cy4kc2tpcDtcbiAgICAgICAgICBsYXN0QmF0Y2hTaXplID0gbGFzdEJhdGNoU2l6ZSB8fCByZXN1bHRzLmxlbmd0aDtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBmdW5jdGlvbiBnZXQoKSB7XG4gICAgICAgIHJldHVybiBSZXNvdXJjZS5nZXQuYXBwbHkoUmVzb3VyY2UsIGFyZ3VtZW50cyk7XG4gICAgICB9XG5cbiAgICAgIGZ1bmN0aW9uIGNoYWluKE1vZGVsOiBSZXNvdXJjZTxNb2RlbD4gfCBRdWVyeUZ1bmN0aW9uLCBxcnlGbj86IFF1ZXJ5RnVuY3Rpb24pIHtcbiAgICAgICAgcmV0dXJuIENoYWluKHJlc3VsdHMsIE1vZGVsLCBxcnlGbik7XG4gICAgICB9XG5cbiAgICAgIGZ1bmN0aW9uIHF1ZXJ5KF9xcnk6IGFueSkge1xuXG4gICAgICAgIC8vIFN0b3JlIG9mZiB0aGUgcXJ5IG1ha2luZyBzdXJlIGl0cyBhIHByb21pc2VcbiAgICAgICAgcXJ5ID0gUHJvbWlzZS5yZXNvbHZlKF9xcnkpO1xuXG4gICAgICAgIGZhbGxiYWNrID0gIWRiLnFyeUlzU2ltcGxlKF9xcnkpO1xuXG4gICAgICAgIC8vIElmIHdlIGFyZSBmYWxsaW5nYmFjayB0aGVuIGp1c3QgcmVzb2x2ZSB3aXRoIG91ciByZXN1bHRzLiBUaGUgc2VydmVyIHNob3VsZFxuICAgICAgICAvLyBkbyB0aGUgcmVzdC5cbiAgICAgICAgaWYgKGZhbGxiYWNrKSB7XG4gICAgICAgICAgLy8gV2Ugd2FudCB0byByZXR1cm4gdGhlIHNlcnZlcidzIHByb21pc2UgaGVyZSBzbyB0aGF0IHBlb3BsZSB3aWxsIGJlIG5vdGlmaWVkXG4gICAgICAgICAgLy8gd2hlbiB0aGUgcmVzdWx0cyBhcmUgYWN0dWFsbHkgbG9hZGVkXG4gICAgICAgICAgbGV0IHByb207XG4gICAgICAgICAgaWYgKCFzZXJ2ZXJSZXN1bHRzLiRyZXNvbHZlZCkge1xuICAgICAgICAgICAgcHJvbSA9IHNlcnZlclJlc3VsdHMuJHByb21pc2UudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgIHJldHVybiByZXN1bHRzO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHByb20gPSBQcm9taXNlLnJlc29sdmUocmVzdWx0cyk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIHByb207XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZGIucXVlcnkoX3FyeSkudGhlbigoaWRzOiBzdHJpbmdbXSkgPT4ge1xuXG4gICAgICAgICAgLy8gV2UgY2FuIHNldCB0aGUgaGFzTmV4dCBhbmQgaGFzUHJldiB2YWx1ZXMgdG8gdHJ1ZSBoZXJlIGlmIHdlIGtub3cgdGhlcmVcbiAgICAgICAgICAvLyBhcmUgc29tZS4gSG93ZXZlciBvbmx5IHRoZSBzZXJ2ZXIgaGFzIHRoZSBkZWZpbml0aXZlIGFiaWxpdHkgdG8gc2F5XG4gICAgICAgICAgLy8gdGhlcmUgYXJlbnQgYW55XG4gICAgICAgICAgcmVzdWx0cy4kaGFzTmV4dCA9IGZhbHNlO1xuICAgICAgICAgIHJlc3VsdHMuJGhhc1ByZXYgPSBmYWxzZTtcbiAgICAgICAgICBpZiAobGltaXQgJiYgaWRzLmxlbmd0aCA+IGxpbWl0KSB7XG4gICAgICAgICAgICAvLyBXZSBoYXZlIG1vcmUgcmVzdWx0cyB0byBmZXRjaFxuICAgICAgICAgICAgcmVzdWx0cy5oYXNOZXh0ID0gdHJ1ZTtcbiAgICAgICAgICAgIHJlc3VsdHMuJGhhc05leHQgPSB0cnVlO1xuXG4gICAgICAgICAgICAvLyBUcmltIHRoZSByZXN1bHRzIGRvd24gdG8gc2l6ZVxuICAgICAgICAgICAgaWRzLmxlbmd0aCAtPSAxO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IHNraXAgPSBfcXJ5LnNraXA7XG5cbiAgICAgICAgICBpZiAoc2tpcCkge1xuICAgICAgICAgICAgcmVzdWx0cy5oYXNQcmV2ID0gdHJ1ZTtcbiAgICAgICAgICAgIHJlc3VsdHMuJGhhc1ByZXYgPSB0cnVlO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIENhbGN1bGF0ZSBwYWdpbmcgb3B0aW9uc1xuICAgICAgICAgIGN1cnJlbnRMaW1pdCA9IGlkcy5sZW5ndGg7XG4gICAgICAgICAgY3VycmVudFNraXAgPSBza2lwIHx8IDA7XG4gICAgICAgICAgbGFzdEJhdGNoU2l6ZSA9IGxhc3RCYXRjaFNpemUgfHwgaWRzLmxlbmd0aDtcblxuICAgICAgICAgIC8vIEdvIHRvIHJlc291cmNlIHR5cGVzXG4gICAgICAgICAgY29uc3QgdG1wUmVzdWx0cyA9IGlkcy5tYXAodG9SZXMpO1xuXG4gICAgICAgICAgLy8gRG8gd2UgbmVlZCB0byBkbyBhIHRyYW5zZm9ybT9cbiAgICAgICAgICBsZXQgcnByb207XG4gICAgICAgICAgaWYgKGlzRnVuY3Rpb24ocmVzdWx0cy50cmFuc2Zvcm0pKSB7XG4gICAgICAgICAgICBycHJvbSA9IFByb21pc2UucmVzb2x2ZShyZXN1bHRzLnRyYW5zZm9ybSh0bXBSZXN1bHRzKSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJwcm9tID0gUHJvbWlzZS5yZXNvbHZlKHRtcFJlc3VsdHMpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBycHJvbS50aGVuKHRyYW5zZm9ybWVkID0+IHtcbiAgICAgICAgICAgIC8vIFB1dCB0aGUgcmVzb3VyY2VzIGludG8gdGhlIGxpc3RcbiAgICAgICAgICAgIGNvbnN0IG9sZCA9IHJlc3VsdHMuc2xpY2UoKTtcbiAgICAgICAgICAgIHJlc3VsdHMubGVuZ3RoID0gMDtcbiAgICAgICAgICAgIHRyYW5zZm9ybWVkLmZvckVhY2goKHJlczogTW9kZWwpID0+IHtcbiAgICAgICAgICAgICAgcmVzdWx0cy5wdXNoKHJlcyk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgcmVzdWx0cy4kZW1pdHRlci5lbWl0KCd1cGRhdGUnLCByZXN1bHRzLCBvbGQpO1xuXG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0cztcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG5cbiAgICAgIH1cblxuICAgICAgZnVuY3Rpb24gcmVmcmVzaFF1ZXJ5KGZvcmNlU2VydmVyPzogYm9vbGVhbik6IFByb21pc2U8TG9jYWxRdWVyeTxNb2RlbD4+IHtcbiAgICAgICAgLy8gUGVyZm9ybSBvdXIgcXVlcnlcbiAgICAgICAgbGV0IHByb20gPSBxcnkudGhlbihxdWVyeSkudGhlbigocmVzOiBhbnlbXSkgPT4ge1xuICAgICAgICAgIC8vIElmIHdlIGRvbid0IGhhdmUgYW55IHJlc3VsdHMgdGhlbiBtYXliZSB3YWl0IGZvciB0aGUgc2VydmVyIHRvIHJldHVyblxuICAgICAgICAgIGlmICgocmVzLmxlbmd0aCA9PT0gMCAmJiAhc2VydmVyUmVzdWx0cy4kcmVzb2x2ZWQpKSB7XG4gICAgICAgICAgICByZXR1cm4gc2VydmVyUmVzdWx0cy4kcHJvbWlzZS50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgcmV0dXJuIHJlZnJlc2hRdWVyeSgpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoZm9yY2VTZXJ2ZXIpIHtcbiAgICAgICAgICBwcm9tID0gc2VydmVyUmVzdWx0cy4kcmVmcmVzaCh0cnVlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBwcm9tLnRoZW4oKHJlczogYW55KSA9PiB7XG4gICAgICAgICAgcmVzdWx0cy5sb2FkaW5nID0gZmFsc2U7XG4gICAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGZ1bmN0aW9uIGV4dGVuZFJlc3VsdHMob2JqOiBhbnksIG5vU2FuaXRpemU/OiBib29sZWFuLCByZXRTZXJ2ZXI/OiBib29sZWFuKSB7XG5cbiAgICAgICAgLy8gU2FuaXRpemUgdGhlIG9iamVjdFxuICAgICAgICBpZiAoIW5vU2FuaXRpemUpIHtcbiAgICAgICAgICBpZiAob2JqLl9xKSB7XG4gICAgICAgICAgICBvYmogPSBvYmouX3E7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIG9iaiA9IHtmaW5kOiBvYmp9O1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBxcnkudGhlbigocmVzb2x2ZWQ6IGFueSkgPT4ge1xuICAgICAgICAgIGNvbnN0IF9xcnkgPSBleHRlbmRRdWVyeShyZXNvbHZlZCwgb2JqKTtcbiAgICAgICAgICByZXR1cm4gcmVwbGFjZShfcXJ5LCByZXRTZXJ2ZXIpO1xuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgZnVuY3Rpb24gcmVwbGFjZShfcXJ5OiBhbnksIHJldFNlcnZlcj86IGJvb2xlYW4pIHtcbiAgICAgICAgLy8gU3luYyBkb3duIHRvIHRoZSBzZXJ2ZXJxdWVyeVxuICAgICAgICBjb25zdCBzZXJ2ZXJQcm9tID0gc2VydmVyUmVzdWx0cy5yZXBsYWNlKF9xcnkpO1xuXG4gICAgICAgIC8vIERvIHRoZSBxdWVyeSBidXQgcmVwbGFjZSB0aGUgZXhpc3RpbmcgcXVlcnlcbiAgICAgICAgY29uc3QgbG9jYWxQcm9tID0gUHJvbWlzZS5yZXNvbHZlKF9xcnkpLnRoZW4obm9ybWFsaXplUXVlcnkpLnRoZW4obm9ybVFyeSA9PiB7XG5cbiAgICAgICAgICAvLyBXZSBhbGxvdyBhIHF1ZXJ5IHRvIHJlc29sdmUgdG8gc29tZXRoaW5nIGZhbHN5IC0gaW4gd2hpY2ggY2FzZSB3ZSBqdXN0XG4gICAgICAgICAgLy8gZHJvcCBpdFxuICAgICAgICAgIGlmICghbm9ybVFyeSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBxcnkudGhlbigob2xkcXJ5OiBhbnkpID0+IHtcbiAgICAgICAgICAgIGlmIChKU09OLnN0cmluZ2lmeShvbGRxcnkpICE9PSBKU09OLnN0cmluZ2lmeShub3JtUXJ5KSkge1xuICAgICAgICAgICAgICAvLyBxdWVyeSBpcyBkaWZmZXJlbnQgLSBjb250aW51ZVxuXG4gICAgICAgICAgICAgIHJldHVybiBxdWVyeShub3JtUXJ5KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIHJldFNlcnZlciA/IHNlcnZlclByb20gOiBsb2NhbFByb207XG4gICAgICB9XG5cbiAgICAgIGZ1bmN0aW9uIG5leHQobnVtPzogbnVtYmVyKSB7XG4gICAgICAgIGxldCBwcm9taXNlO1xuICAgICAgICBsZXQgZXh0ZW5kU2l6ZTtcbiAgICAgICAgaWYgKHJlc3VsdHMuaGFzTmV4dCkge1xuICAgICAgICAgIGxhc3RCYXRjaFNpemUgPSBleHRlbmRTaXplID0gbnVtIHx8IGxhc3RCYXRjaFNpemU7XG4gICAgICAgICAgY29uc3QgZXh0ZW5kT2JqID0ge1xuICAgICAgICAgICAgbGltaXQ6IGN1cnJlbnRMaW1pdCArIGV4dGVuZFNpemUsXG4gICAgICAgICAgfTtcbiAgICAgICAgICBwcm9taXNlID0gZXh0ZW5kUmVzdWx0cyhleHRlbmRPYmosIHRydWUsICFyZXN1bHRzLiRoYXNOZXh0KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zdCBkZWZlcnJlZCA9IG5ldyBEZWZlcnJlZCgpO1xuICAgICAgICAgIGRlZmVycmVkLnJlc29sdmUoKTtcbiAgICAgICAgICBwcm9taXNlID0gZGVmZXJyZWQucHJvbWlzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBwcm9taXNlO1xuICAgICAgfVxuXG4gICAgICBmdW5jdGlvbiBwcmV2KG51bT86IG51bWJlcikge1xuICAgICAgICBsZXQgcHJvbWlzZTtcbiAgICAgICAgbGV0IGV4dGVuZFNpemU7XG4gICAgICAgIGlmIChyZXN1bHRzLmhhc1ByZXYpIHtcbiAgICAgICAgICBsYXN0QmF0Y2hTaXplID0gZXh0ZW5kU2l6ZSA9IG51bSB8fCBsYXN0QmF0Y2hTaXplO1xuICAgICAgICAgIGNvbnN0IGV4dGVuZE9iaiA9IHtcbiAgICAgICAgICAgIGxpbWl0OiBjdXJyZW50TGltaXQgKyBleHRlbmRTaXplLFxuICAgICAgICAgICAgc2tpcDogTWF0aC5tYXgoY3VycmVudFNraXAgLSBleHRlbmRTaXplLCAwKSxcbiAgICAgICAgICB9O1xuICAgICAgICAgIHByb21pc2UgPSBleHRlbmRSZXN1bHRzKGV4dGVuZE9iaiwgdHJ1ZSwgIXJlc3VsdHMuJGhhc1ByZXYpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbnN0IGRlZmVycmVkID0gbmV3IERlZmVycmVkKCk7XG4gICAgICAgICAgZGVmZXJyZWQucmVzb2x2ZSgpO1xuICAgICAgICAgIHByb21pc2UgPSBkZWZlcnJlZC5wcm9taXNlO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHByb21pc2U7XG4gICAgICB9XG5cbiAgICAgIHJlc3VsdHMuJHJlZnJlc2ggPSByZWZyZXNoUXVlcnk7XG4gICAgICByZXN1bHRzLmV4dGVuZCA9IGV4dGVuZFJlc3VsdHM7XG4gICAgICByZXN1bHRzLnJlcGxhY2UgPSByZXBsYWNlO1xuICAgICAgcmVzdWx0cy5nZXQgPSBnZXQ7XG4gICAgICByZXN1bHRzLm5leHQgPSBuZXh0O1xuICAgICAgcmVzdWx0cy5wcmV2ID0gcHJldjtcbiAgICAgIHJlc3VsdHMuJHByb21pc2UgPSByZWZyZXNoUXVlcnkoKTtcbiAgICAgIHJlc3VsdHMuJHJlc29sdmVkU3ViamVjdCA9IGNvbnZlcnRUb1Jlc29sdmVkU3ViamVjdChyZXN1bHRzLiRzdWJqZWN0LCByZXN1bHRzLiRwcm9taXNlKTtcbiAgICAgIHJlc3VsdHMuY2hhaW4gPSBjaGFpbjtcbiAgICAgIHJlc3VsdHMuJE1vZGVsID0gUmVzb3VyY2U7XG4gICAgICByZXN1bHRzLiRzZXJ2ZXJSZXN1bHRzID0gc2VydmVyUmVzdWx0cztcblxuICAgICAgLy8gUHV0IGN1cnJlbnRTa2lwIGFuZCBjdXJyZW50TGltaXQgb250byB0aGUgcmVzdWx0c1xuICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHJlc3VsdHMsICdjdXJyZW50TGltaXQnLCB7XG4gICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgIGdldDogKCkgPT4ge1xuICAgICAgICAgIHJldHVybiBjdXJyZW50TGltaXQ7XG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShyZXN1bHRzLCAnY3VycmVudFNraXAnLCB7XG4gICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgIGdldDogKCkgPT4ge1xuICAgICAgICAgIHJldHVybiBjdXJyZW50U2tpcDtcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICByZXR1cm4gcmVzdWx0cztcbiAgICB9O1xuXG4gICAgbGV0IHJlZnJlc2hUaW1lcjogbnVtYmVyO1xuICAgIExvY2FsUXVlcnlMaXN0LnJlZnJlc2ggPSAoKSA9PiB7XG5cbiAgICAgIC8vIElmIHdlIGhhdmUgYSB0aW1lciBvdXRzdGFuZGluZyB0aGVuIGp1c3QgcmV0dXJuIC0gYSByZWZyZXNoIHdpbGwgaGFwcGVuIHNvb24uXG4gICAgICBpZiAoIXJlZnJlc2hUaW1lcikge1xuICAgICAgICByZWZyZXNoVGltZXIgPSBzZXRUaW1lb3V0KGRvUmVmcmVzaCwgMTAwKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHJlZnJlc2hUaW1lcjtcblxuICAgICAgZnVuY3Rpb24gZG9SZWZyZXNoKCkge1xuICAgICAgICBfbG9jYWxRdWVyaWVzLmZvckVhY2gocmVzID0+IHtcbiAgICAgICAgICByZXMuJHJlZnJlc2goKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJlZnJlc2hUaW1lciA9IG51bGw7XG4gICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFNlcnZlciBxdWVyeSBsaXN0LiBUaGUgc2VydmVyIG1ha2VzIHN1cmUgd2Uga2VlcCBpbiBzeW5jXG4gICAgICogQHBhcmFtIHtbdHlwZV19IHFyeSAgICAgIFtkZXNjcmlwdGlvbl1cbiAgICAgKiBAcGFyYW0ge1t0eXBlXX0gbGltaXQgICAgW2Rlc2NyaXB0aW9uXVxuICAgICAqIEBwYXJhbSB7W3R5cGVdfSBSZXNvdXJjZSBbZGVzY3JpcHRpb25dXG4gICAgICovXG4gICAgZnVuY3Rpb24gU2VydmVyUXVlcnlMaXN0KHFyeTogYW55LCBsaW1pdDogbnVtYmVyLCBSZXNvdXJjZTogYW55KTogU2VydmVyUXVlcnk8TW9kZWw+IHtcbiAgICAgIC8vIEFsbG93IHFyeSB0byBiZSBhIHByb21pc2VcbiAgICAgIHFyeSA9IFByb21pc2UucmVzb2x2ZShxcnkpLnRoZW4obm9ybWFsaXplUXVlcnkpLnRoZW4oX3FyeSA9PiB7XG4gICAgICAgIGlmIChsaW1pdCkge1xuICAgICAgICAgIF9xcnkubGltaXQgPSBsaW1pdDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gX3FyeTtcbiAgICAgIH0pO1xuXG4gICAgICBsZXQgZW1pdFByb21pc2U6IFByb21pc2U8YW55PiA9IG51bGw7XG4gICAgICBjb25zdCByZXN1bHRzID0gbmV3IFNlcnZlclF1ZXJ5PE1vZGVsPigpO1xuICAgICAgbGV0IGN1cnJlbnRMaW1pdCA9IDA7XG4gICAgICBsZXQgY3VycmVudFNraXAgPSAwO1xuICAgICAgbGV0IGxhc3RCYXRjaFNpemUgPSAwO1xuICAgICAgbGV0IF9wYWdpbmdPcHRzOiBhbnkgPSB7fTtcblxuICAgICAgcmVzdWx0cy5sb2FkaW5nID0gdHJ1ZTtcblxuICAgICAgZnVuY3Rpb24gcXVlcnkoZGF0YTogYW55KSB7XG4gICAgICAgIC8vIFdlIG9ubHkgd2FudCB0byBkbyBvbmUgZW1pdCBhdCBhIHRpbWUgKG90aGVyd2lzZSB3ZSBjb3VsZCBnZXQgaW50byBhIGJhZCBzdGF0ZSlcbiAgICAgICAgaWYgKGlzRnVuY3Rpb24oZGF0YSkpIHtcbiAgICAgICAgICBkYXRhID0gZGF0YSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gU3RvcmUgb2ZmIHRoZSBxdWVyeSAtIG1ha2Ugc3VyZSBpdHMgYSBwcm9taXNlXG4gICAgICAgIHFyeSA9IFByb21pc2UucmVzb2x2ZShkYXRhKTtcblxuICAgICAgICByZXR1cm4gcXJ5LnRoZW4oKF9kYXRhOiBhbnkpID0+IHtcbiAgICAgICAgICAvLyBJZiB3ZSBoYXZlIGFuIGV4aXN0aW5nIGVtaXRQcm9taXNlIHRoZW4gd2FpdCBmb3IgaXQgdG8gcmVzb2x2ZSBiZWZvcmUgd2UgcnVuXG4gICAgICAgICAgbGV0IHByb21pc2U7XG4gICAgICAgICAgaWYgKGVtaXRQcm9taXNlKSB7XG4gICAgICAgICAgICBwcm9taXNlID0gZW1pdFByb21pc2UudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgIHJldHVybiBzb2NrLnF1ZXJ5KF9kYXRhKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBlbWl0UHJvbWlzZSA9IHByb21pc2UgPSBzb2NrLnF1ZXJ5KF9kYXRhKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gcHJvbWlzZTtcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGZ1bmN0aW9uIG5ld0RhdGEoX3FyeUlkOiBzdHJpbmcsIHJlc3BvbnNlOiBhbnksIGZvcmNlPzogYm9vbGVhbikge1xuICAgICAgICBpZiAoIXJlc3BvbnNlKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZGVmZXJyZWQgPSBuZXcgRGVmZXJyZWQoKTtcbiAgICAgICAgY29uc3QgaWRzOiBzdHJpbmdbXSA9IHJlc3BvbnNlLmlkcztcbiAgICAgICAgY29uc3QgcGFnaW5nT3B0cyA9IHJlc3BvbnNlLnBhZ2luZ09wdHM7XG5cbiAgICAgICAgLy8gU28gZmFyIHdlJ3ZlIG9ubHkgZ290IHRoZSBpZHMgb2YgdGhlIHFyeSByZXN1bHQgLSBnbyBhbmQgZmV0Y2ggdGhlIGFjdHVhbCBvYmplY3RzLlxuICAgICAgICAvLyBUaGlzIG1lY2hhbmlzbSBzYXZlcyBiYW5kd2lkdGggYnkgb25seSBnZXR0aW5nIHRoZSBvYmplY3QgZGF0YSBvbmNlIHRoZW4gbGlzdGVuaW5nXG4gICAgICAgIC8vIGZvciBjaGFuZ2VzIHRvIGl0XG4gICAgICAgIC8vXG4gICAgICAgIC8vIElmIHdlIGFyZSBmb3JjaW5nIHdlIHdhbnQgdG8gZ2V0IGJvdGggdGhlIG9sZCBhbmQgbmV3IGlkcyB0byBjaGVjayBmb3IgYW55IGNoYW5nZXNcbiAgICAgICAgLy8gZGVsZXRpb25zIGV0Yy4uXG4gICAgICAgIGxldCBnZXRJZHMgPSBpZHM7XG4gICAgICAgIGlmIChmb3JjZSkge1xuICAgICAgICAgIGNvbnN0IG9sZElkcyA9IG1hcChyZXN1bHRzLCAnX2lkJyk7XG4gICAgICAgICAgZ2V0SWRzID0gdW5pb24oaWRzLCBvbGRJZHMpO1xuICAgICAgICB9XG5cbiAgICAgICAgUmVzb3VyY2UuZ2V0KGdldElkcywgZm9yY2UpLiRwcm9taXNlLnRoZW4oKHJlc3M6IGFueVtdKSA9PiB7XG4gICAgICAgICAgY29uc3QgcmVzc21hcDogYW55ID0ge307XG4gICAgICAgICAgcmVzcy5mb3JFYWNoKHJlcyA9PiB7XG4gICAgICAgICAgICByZXNzbWFwW3Jlcy5faWRdID0gcmVzO1xuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgLy8gV2UgZG9uJ3QgYWxsb3cgcmVwZWF0ZWQgaWRzIHNvIGp1c3QgaXRlcmF0ZSBvdmVyIHRoZSByZXN1bHRzXG4gICAgICAgICAgY29uc3QgdG1wUmVzdWx0czogYW55W10gPSBbXTtcbiAgICAgICAgICBpZHMuZm9yRWFjaChpZCA9PiB7XG4gICAgICAgICAgICB0bXBSZXN1bHRzLnB1c2gocmVzc21hcFtpZF0pO1xuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgLy8gRG8gd2UgbmVlZCB0byBkbyBhIHRyYW5zZm9ybT9cbiAgICAgICAgICBsZXQgcnByb207XG4gICAgICAgICAgaWYgKGlzRnVuY3Rpb24ocmVzdWx0cy50cmFuc2Zvcm0pKSB7XG4gICAgICAgICAgICBycHJvbSA9IFByb21pc2UucmVzb2x2ZShyZXN1bHRzLnRyYW5zZm9ybSh0bXBSZXN1bHRzKSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJwcm9tID0gUHJvbWlzZS5yZXNvbHZlKHRtcFJlc3VsdHMpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBycHJvbS50aGVuKHRyYW5zZm9ybWVkID0+IHtcblxuICAgICAgICAgICAgcmVzdWx0cy5sZW5ndGggPSAwO1xuICAgICAgICAgICAgdHJhbnNmb3JtZWQuZm9yRWFjaCgocmVzOiBNb2RlbCkgPT4ge1xuICAgICAgICAgICAgICByZXN1bHRzLnB1c2gocmVzKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyBTaW5jZSB3ZSBub3cgaGF2ZSBkYXRhIGluIG91ciBhcnJheSBzdG9yZSBvZmYgbGltaXQgZGF0YVxuICAgICAgICAgICAgY3VycmVudExpbWl0ID0gdG1wUmVzdWx0cy5sZW5ndGg7XG4gICAgICAgICAgICByZXN1bHRzLiRza2lwID0gY3VycmVudFNraXAgPSAocXJ5ICYmIHFyeS5za2lwKSA/IHFyeS5za2lwIDogMDtcbiAgICAgICAgICAgIGxhc3RCYXRjaFNpemUgPSBsYXN0QmF0Y2hTaXplIHx8IHRtcFJlc3VsdHMubGVuZ3RoO1xuICAgICAgICAgICAgX3BhZ2luZ09wdHMgPSBwYWdpbmdPcHRzO1xuICAgICAgICAgICAgcmVzdWx0cy5oYXNOZXh0ID0gKHBhZ2luZ09wdHMubmV4dCAhPSBudWxsKTtcbiAgICAgICAgICAgIHJlc3VsdHMuaGFzUHJldiA9IChwYWdpbmdPcHRzLnByZXYgIT0gbnVsbCk7XG5cbiAgICAgICAgICAgIC8vIERhdGEgaGFzIGNvbWUgYmFja1xuICAgICAgICAgICAgcmVzdWx0cy5sb2FkaW5nID0gZmFsc2U7XG5cbiAgICAgICAgICAgIHJlc3VsdHMuJGVtaXR0ZXIuZW1pdCgndXBkYXRlJywgcmVzdWx0cyk7XG5cbiAgICAgICAgICAgIGRlZmVycmVkLnJlc29sdmUocmVzdWx0cyk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBkZWZlcnJlZC5wcm9taXNlO1xuICAgICAgfVxuXG4gICAgICBmdW5jdGlvbiByZWZyZXNoUXVlcnkoZm9yY2U/OiBib29sZWFuKTogUHJvbWlzZTxTZXJ2ZXJRdWVyeTxNb2RlbD4+IHtcbiAgICAgICAgY29uc3QgcmVxID0gcXVlcnkocXJ5KTtcbiAgICAgICAgY29uc3QgcHJvbWlzZSA9IHJlcS50aGVuKChyZXM6IGFueSkgPT4ge1xuXG4gICAgICAgICAgLy8gSWYgd2UgZ2V0IG5vIHJlc3BvbnNlICh0aGUgYXBwIGNvdWxkIGJlIG9mZmxpbmUpIHRoZW4ganVzdCByZXNvbHZlIHdpdGhcbiAgICAgICAgICAvLyB0aGUgZXhpc3RpbmcgcmVzdWx0c1xuICAgICAgICAgIGlmIChpc1VuZGVmaW5lZChyZXMpKSB7XG4gICAgICAgICAgICByZXN1bHRzLmxvYWRpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgIHJldHVybiByZXN1bHRzO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IF9xcnlJZCA9IHJlcy5xcnlJZDtcbiAgICAgICAgICBjb25zdCByZXNwb25zZSA9IHJlcy5kYXRhO1xuXG4gICAgICAgICAgcmV0dXJuIG5ld0RhdGEoX3FyeUlkLCByZXNwb25zZSwgZm9yY2UpO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIHByb21pc2U7XG4gICAgICB9XG5cbiAgICAgIGZ1bmN0aW9uIHJlcGxhY2UoX3FyeTogYW55KSB7XG4gICAgICAgIC8vIERvIHRoZSBxdWVyeSBidXQgcmVwbGFjZSB0aGUgZXhpc3RpbmcgcXVlcnlcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShfcXJ5KS50aGVuKG5vcm1hbGl6ZVF1ZXJ5KS50aGVuKG5vcm1RcnkgPT4ge1xuXG4gICAgICAgICAgLy8gV2UgYWxsb3cgYSBxdWVyeSB0byByZXNvbHZlIHRvIHNvbWV0aGluZyBmYWxzeSAtIGluIHdoaWNoIGNhc2Ugd2UganVzdFxuICAgICAgICAgIC8vIGRyb3AgaXRcbiAgICAgICAgICBpZiAoIW5vcm1RcnkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gcXJ5LnRoZW4oKG9sZHFyeTogYW55KSA9PiB7XG4gICAgICAgICAgICBpZiAoSlNPTi5zdHJpbmdpZnkob2xkcXJ5KSAhPT0gSlNPTi5zdHJpbmdpZnkobm9ybVFyeSkpIHtcbiAgICAgICAgICAgICAgLy8gcXVlcnkgaXMgZGlmZmVyZW50IC0gY29udGludWVcbiAgICAgICAgICAgICAgY29uc3QgcmVxID0gcXVlcnkobm9ybVFyeSk7XG5cbiAgICAgICAgICAgICAgY29uc3QgcHJvbWlzZSA9IHJlcS50aGVuKChyZXM6IGFueSkgPT4ge1xuICAgICAgICAgICAgICAgIC8vIElmIHdlIGdldCBubyByZXNwb25zZSAodGhlIGFwcCBjb3VsZCBiZSBvZmZsaW5lKSB0aGVuIGp1c3QgcmVzb2x2ZSB3aXRoXG4gICAgICAgICAgICAgICAgLy8gdGhlIGV4aXN0aW5nIHJlc3VsdHNcbiAgICAgICAgICAgICAgICBpZiAoaXNVbmRlZmluZWQocmVzKSkge1xuICAgICAgICAgICAgICAgICAgcmVzdWx0cy5sb2FkaW5nID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICByZXR1cm4gcmVzdWx0cztcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBXZSBkbyBoYXZlIGEgcmVzcG9uc2UuIENvbnRpbnVlXG4gICAgICAgICAgICAgICAgY29uc3QgX3FyeUlkID0gcmVzLnFyeUlkO1xuICAgICAgICAgICAgICAgIGNvbnN0IGRhdGEgPSByZXMuZGF0YTtcblxuICAgICAgICAgICAgICAgIHJldHVybiBuZXdEYXRhKF9xcnlJZCwgZGF0YSk7XG4gICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgIHJldHVybiBwcm9taXNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcblxuICAgICAgfVxuXG4gICAgICBmdW5jdGlvbiBleHRlbmRSZXN1bHRzKG9iajogYW55LCBub1Nhbml0aXplPzogYm9vbGVhbikge1xuXG4gICAgICAgIC8vIFNhbml0aXplIHRoZSBvYmplY3RcbiAgICAgICAgaWYgKCFub1Nhbml0aXplKSB7XG4gICAgICAgICAgaWYgKG9iai5fcSkge1xuICAgICAgICAgICAgb2JqID0gb2JqLl9xO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBvYmogPSB7ZmluZDogb2JqfTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcXJ5LnRoZW4oKHJlc29sdmVkOiBhbnkpID0+IHtcbiAgICAgICAgICBjb25zdCBfcXJ5ID0gZXh0ZW5kUXVlcnkocmVzb2x2ZWQsIG9iaik7XG4gICAgICAgICAgcmV0dXJuIHJlcGxhY2UoX3FyeSk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBmdW5jdGlvbiBuZXh0KG51bTogbnVtYmVyKSB7XG4gICAgICAgIGxldCBwcm9taXNlO1xuICAgICAgICBsZXQgZXh0ZW5kU2l6ZTtcbiAgICAgICAgaWYgKF9wYWdpbmdPcHRzLm5leHQpIHtcbiAgICAgICAgICBsYXN0QmF0Y2hTaXplID0gZXh0ZW5kU2l6ZSA9IG51bSB8fCBsYXN0QmF0Y2hTaXplO1xuICAgICAgICAgIGNvbnN0IGV4dGVuZE9iaiA9IHtcbiAgICAgICAgICAgIGxpbWl0OiBjdXJyZW50TGltaXQgKyBleHRlbmRTaXplLFxuICAgICAgICAgIH07XG4gICAgICAgICAgcHJvbWlzZSA9IGV4dGVuZFJlc3VsdHMoZXh0ZW5kT2JqLCB0cnVlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zdCBkZWZlcnJlZCA9IG5ldyBEZWZlcnJlZCgpO1xuICAgICAgICAgIGRlZmVycmVkLnJlc29sdmUoKTtcbiAgICAgICAgICBwcm9taXNlID0gZGVmZXJyZWQucHJvbWlzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBwcm9taXNlO1xuICAgICAgfVxuXG4gICAgICBmdW5jdGlvbiBwcmV2KG51bTogbnVtYmVyKSB7XG4gICAgICAgIGxldCBwcm9taXNlO1xuICAgICAgICBsZXQgZXh0ZW5kU2l6ZTtcbiAgICAgICAgaWYgKF9wYWdpbmdPcHRzLnByZXYpIHtcbiAgICAgICAgICBsYXN0QmF0Y2hTaXplID0gZXh0ZW5kU2l6ZSA9IG51bSB8fCBsYXN0QmF0Y2hTaXplO1xuICAgICAgICAgIGNvbnN0IGV4dGVuZE9iaiA9IHtcbiAgICAgICAgICAgIGxpbWl0OiBjdXJyZW50TGltaXQgKyBleHRlbmRTaXplLFxuICAgICAgICAgICAgc2tpcDogTWF0aC5tYXgoY3VycmVudFNraXAgLSBleHRlbmRTaXplLCAwKSxcbiAgICAgICAgICB9O1xuICAgICAgICAgIHByb21pc2UgPSBleHRlbmRSZXN1bHRzKGV4dGVuZE9iaiwgdHJ1ZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc3QgZGVmZXJyZWQgPSBuZXcgRGVmZXJyZWQoKTtcbiAgICAgICAgICBkZWZlcnJlZC5yZXNvbHZlKCk7XG4gICAgICAgICAgcHJvbWlzZSA9IGRlZmVycmVkLnByb21pc2U7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcHJvbWlzZTtcbiAgICAgIH1cblxuICAgICAgZnVuY3Rpb24gZ2V0KCkge1xuICAgICAgICByZXR1cm4gUmVzb3VyY2UuZ2V0LmFwcGx5KFJlc291cmNlLCBhcmd1bWVudHMpO1xuICAgICAgfVxuXG4gICAgICBmdW5jdGlvbiBjaGFpbihNb2RlbDogYW55LCBxcnlGbjogUXVlcnlGdW5jdGlvbikge1xuICAgICAgICByZXR1cm4gQ2hhaW4ocmVzdWx0cywgTW9kZWwsIHFyeUZuKTtcbiAgICAgIH1cblxuICAgICAgcmVzdWx0cy4kbmV3RGF0YSA9IG5ld0RhdGE7XG4gICAgICByZXN1bHRzLiRyZWZyZXNoID0gcmVmcmVzaFF1ZXJ5O1xuICAgICAgcmVzdWx0cy5leHRlbmQgPSBleHRlbmRSZXN1bHRzO1xuICAgICAgcmVzdWx0cy5yZXBsYWNlID0gcmVwbGFjZTtcbiAgICAgIHJlc3VsdHMuZ2V0ID0gZ2V0O1xuICAgICAgcmVzdWx0cy5uZXh0ID0gbmV4dDtcbiAgICAgIHJlc3VsdHMucHJldiA9IHByZXY7XG4gICAgICByZXN1bHRzLiRwcm9taXNlID0gcmVmcmVzaFF1ZXJ5KCkudGhlbihyZXMgPT4ge1xuICAgICAgICByZXN1bHRzLiRyZXNvbHZlZCA9IHRydWU7XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgICB9KTtcbiAgICAgIHJlc3VsdHMuJHJlc29sdmVkU3ViamVjdCA9IGNvbnZlcnRUb1Jlc29sdmVkU3ViamVjdChyZXN1bHRzLiRzdWJqZWN0LCByZXN1bHRzLiRwcm9taXNlKTtcbiAgICAgIHJlc3VsdHMuJHJlc29sdmVkID0gZmFsc2U7XG4gICAgICByZXN1bHRzLmNoYWluID0gY2hhaW47XG4gICAgICByZXN1bHRzLiRNb2RlbCA9IFJlc291cmNlO1xuICAgICAgcmVzdWx0cy4kc2tpcCA9IDA7XG5cbiAgICAgIC8vIFB1dCBjdXJyZW50U2tpcCBhbmQgY3VycmVudExpbWl0IG9udG8gdGhlIHJlc3VsdHNcbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShyZXN1bHRzLCAnY3VycmVudExpbWl0Jywge1xuICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICBnZXQ6ICgpID0+IHtcbiAgICAgICAgICByZXR1cm4gY3VycmVudExpbWl0O1xuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkocmVzdWx0cywgJ2N1cnJlbnRTa2lwJywge1xuICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICBnZXQ6ICgpID0+IHtcbiAgICAgICAgICByZXR1cm4gY3VycmVudFNraXA7XG4gICAgICAgIH0sXG4gICAgICB9KTtcblxuICAgICAgcmV0dXJuIHJlc3VsdHM7XG4gICAgfVxuXG4gICAgcmV0dXJuIGRiID8gTG9jYWxRdWVyeUxpc3QgOiBTZXJ2ZXJRdWVyeUxpc3Q7XG4gIH1cblxuICByZXR1cm4gUXVlcnlGYWN0b3J5O1xufVxuIl19