ineedthis
Version:
Stateful dependency management
440 lines • 50.2 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
// eslint-disable-next-line @typescript-eslint/no-var-requires
var _a = require('../package'), pkgName = _a.name, version = _a.version;
// Persist registry across multiple instances of this module. Terrible
// hack, but needed to support a truly 'global' registry in
// environments such as lerna or old npm verisons
var registrySym = Symbol.for("Global registry for " + pkgName + "@" + version);
if (!global[registrySym]) {
global[registrySym] = {};
}
var registry = global[registrySym];
function isFunction(o) {
return typeof o === 'function';
}
function isArray(o) {
return typeof o === 'object' && o instanceof Array;
}
function isService(o) {
return isFunction(o) && isFunction(o.start) && isFunction(o.stop) && isArray(o.dependencies);
}
function getPath(o, ks) {
if (ks === void 0) { ks = []; }
if (ks.length === 0) {
return o;
}
else {
return getPath(o[ks[0]], ks.slice(1));
}
}
function parsePackage(s) {
var parts = s.split('.');
return { path: parts.slice(1), package: parts[0], __isPackageSpec: true };
}
var notFound = Symbol('Package not found');
function tryRequire(p) {
if (typeof p === 'string') {
p = parsePackage(p);
}
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
var service = getPath(require(p.package), (p.path || []));
return service;
}
catch (e) {
return notFound;
}
}
function requireOrThrow(p) {
var required = tryRequire(p);
if (required === notFound) {
throw new Error("Couldn't resolve dependency: \"" + p + "\"");
}
else if (!isService(required)) {
throw new Error("Resolved \"" + p + "\" but expected a Service, not \"" + String(required) + "\"");
}
else {
return required;
}
}
function dependencyOrService(input) {
if (typeof input === 'string') {
return input;
}
else if (Object.prototype.hasOwnProperty.call(input, '__isPackageSpec')) {
return requireOrThrow(input).serviceName;
}
return input.serviceName;
}
function dangerouslyResetRegistry() {
for (var _i = 0, _a = Object.keys(registry); _i < _a.length; _i++) {
var serviceName = _a[_i];
delete registry[serviceName];
}
}
exports.dangerouslyResetRegistry = dangerouslyResetRegistry;
function cloneFn(fn) {
return function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return fn.apply(void 0, args);
};
}
/**
* Create a service named `name` with start, stop, etc as defined in
* `description`.
*
* Leave `name` undefined to create an anonymous service.
*/
function createService(name, description) {
var defaultedDescription = __assign({}, description);
if (!Array.isArray(defaultedDescription.dependencies)) {
defaultedDescription.dependencies = [];
}
if (!defaultedDescription.stop) {
defaultedDescription.stop = function () { return undefined; };
}
var start = cloneFn(defaultedDescription.start), service = Object.assign(start, {
dependencies: defaultedDescription.dependencies,
serviceName: name,
start: start,
stop: defaultedDescription.stop,
});
if (name) {
registry[name] = service;
}
return service;
}
exports.createService = createService;
function flatten(ll) {
var _a;
return (_a = []).concat.apply(_a, ll.map(function (it) { return Array.from(it); }));
}
/**
* Creates a service that, when used, is loaded from the given node
* packageName (eg @scope/some-cool-package/path/inside/package) and a
* lodash get-style path (eg "abc.0.hi" to get "x" from {abc:[{hi:"x"}]}).
*/
function fromPackage(packageName, path) {
return { path: path, package: packageName, __isPackageSpec: true };
}
exports.fromPackage = fromPackage;
// TODO: Can get rid of 'any' once Variadic Kinds lands (TS issue #5453)
function start(namesOrServices, overridesIn) {
if (overridesIn === void 0) { overridesIn = {}; }
return __awaiter(this, void 0, void 0, function () {
function resolve(serviceName) {
if (overrides && overrides[serviceName]) {
return overrides[serviceName];
}
else if (registry[serviceName]) {
return registry[serviceName];
}
else {
return requireOrThrow(serviceName);
}
}
function load(name) {
return __awaiter(this, void 0, void 0, function () {
var service;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, resolve(name)()(__assign({}, system))];
case 1:
service = _a.sent();
delete outstandingLoads[name];
Object.values(outstandingDeps).forEach(function (deps) { return deps.delete(name); });
// We duplicate the `system` object, so services can't mutate our
// master copy of the system. Thus, the possible race condition
// that eslint detects here is a false positive.
// eslint-disable-next-line require-atomic-updates
system[name] = service;
return [2 /*return*/, service];
}
});
});
}
var overrides, services, _i, services_1, s, outstandingDeps, toProcess, system, outstandingLoads, _a, _b, _c, name, deps;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
if (!Array.isArray(namesOrServices)) {
namesOrServices = [namesOrServices];
}
overrides = {};
Object.assign(overrides, overridesIn);
services = namesOrServices.map(function (nameOrService) {
if (typeof nameOrService === 'string') {
if (registry[nameOrService]) {
return registry[nameOrService];
}
else {
throw new Error("Couldn't find: \"" + nameOrService + "\"");
}
}
else if (Object.prototype.hasOwnProperty.call(nameOrService, '__isPackageSpec')) {
return requireOrThrow(nameOrService);
}
else {
return nameOrService;
}
});
for (_i = 0, services_1 = services; _i < services_1.length; _i++) {
s = services_1[_i];
if (!overrides[s.serviceName]) {
overrides[s.serviceName] = s;
}
}
outstandingDeps = {};
toProcess = new Set(services.map(function (s) { return s.serviceName; }));
do {
toProcess.forEach(function (s) {
outstandingDeps[s] = new Set(resolve(s).dependencies.map(dependencyOrService));
});
toProcess = new Set(flatten(Object.values(outstandingDeps)));
Object.keys(outstandingDeps).forEach(function (k) { return toProcess.delete(k); });
} while (toProcess.size > 0);
system = {};
outstandingLoads = {};
_d.label = 1;
case 1:
if (!(Object.keys(outstandingDeps).length > 0 ||
Object.keys(outstandingLoads).length > 0)) return [3 /*break*/, 3];
// Start loading any deps that are no longer waiting for another dep
for (_a = 0, _b = Object.entries(outstandingDeps); _a < _b.length; _a++) {
_c = _b[_a], name = _c[0], deps = _c[1];
if (deps.size === 0) {
outstandingLoads[name] = load(name);
delete outstandingDeps[name];
}
}
if (Object.keys(outstandingLoads).length === 0 &&
Object.keys(outstandingDeps).length > 0) {
throw new Error('Cycle detected');
}
// Wait for the next dep to finish starting
return [4 /*yield*/, Promise.race(Object.values(outstandingLoads))];
case 2:
// Wait for the next dep to finish starting
_d.sent();
return [3 /*break*/, 1];
case 3: return [2 /*return*/, system];
}
});
});
}
exports.start = start;
/**
* Stop system. If a spec of systems `partial` is supplied, stop only
* those systems and any "higher" systems that rely on them, but
* others will be left alone.
*/
function stop(system) {
return __awaiter(this, void 0, void 0, function () {
var countDependents, _i, _a, s, _b, _c, s, _d, _e, d, outstandingShutdowns, finishedShutdowns, _loop_1, _f, _g, _h, s, remainingDependents;
var _this = this;
return __generator(this, function (_j) {
switch (_j.label) {
case 0:
countDependents = {};
for (_i = 0, _a = Object.keys(system); _i < _a.length; _i++) {
s = _a[_i];
countDependents[s] = 0;
}
for (_b = 0, _c = Object.keys(system); _b < _c.length; _b++) {
s = _c[_b];
for (_d = 0, _e = registry[s].dependencies.map(dependencyOrService); _d < _e.length; _d++) {
d = _e[_d];
countDependents[d]++;
}
}
outstandingShutdowns = {}, finishedShutdowns = {};
_j.label = 1;
case 1:
_loop_1 = function (s, remainingDependents) {
if (remainingDependents === 0 &&
!outstandingShutdowns[s] &&
!finishedShutdowns[s]) {
outstandingShutdowns[s] = (function () { return __awaiter(_this, void 0, void 0, function () {
var service, _i, _a, d;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
service = registry[s];
return [4 /*yield*/, service.stop(system[s])];
case 1:
_b.sent();
finishedShutdowns[s] = true;
delete outstandingShutdowns[s];
for (_i = 0, _a = service.dependencies.map(dependencyOrService); _i < _a.length; _i++) {
d = _a[_i];
countDependents[d]--;
}
return [2 /*return*/];
}
});
}); })();
}
};
for (_f = 0, _g = Object.entries(countDependents); _f < _g.length; _f++) {
_h = _g[_f], s = _h[0], remainingDependents = _h[1];
_loop_1(s, remainingDependents);
}
return [4 /*yield*/, Promise.race(Object.values(outstandingShutdowns))];
case 2:
_j.sent();
_j.label = 3;
case 3:
if (Object.keys(finishedShutdowns).length < Object.keys(system).length) return [3 /*break*/, 1];
_j.label = 4;
case 4: return [2 /*return*/];
}
});
});
}
exports.stop = stop;
/**
* Stop system. If a spec of systems `partial` is supplied, stop only
* those systems and any "higher" systems that rely on them, but
* others will be left alone.
*
* Returns the list of services names that were shutdown
*/
function stopPartial(system, partial) {
return __awaiter(this, void 0, void 0, function () {
var dependents, _i, _a, s, _b, _c, s, _d, _e, d, toShutdown, toVisit, visited, visiting, _f, _g, s, partialSystem, output;
return __generator(this, function (_h) {
switch (_h.label) {
case 0:
dependents = {};
for (_i = 0, _a = Object.keys(system); _i < _a.length; _i++) {
s = _a[_i];
dependents[s] = [];
}
for (_b = 0, _c = Object.keys(system); _b < _c.length; _b++) {
s = _c[_b];
for (_d = 0, _e = registry[s].dependencies.map(dependencyOrService); _d < _e.length; _d++) {
d = _e[_d];
if (system[d]) {
dependents[d].push(s);
}
}
}
toShutdown = new Set(), toVisit = partial.slice(), visited = new Set();
while (visiting = toVisit.pop()) {
visited.add(visiting);
toShutdown.add(visiting);
for (_f = 0, _g = dependents[visiting]; _f < _g.length; _f++) {
s = _g[_f];
if (!visited.has(s)) {
toVisit.push(s);
}
}
}
partialSystem = {}, output = [];
toShutdown.forEach(function (s) {
partialSystem[s] = system[s];
output.push(s);
});
return [4 /*yield*/, stop(partialSystem)];
case 1:
_h.sent();
return [2 /*return*/, output];
}
});
});
}
exports.stopPartial = stopPartial;
var noopService = function (x) {
return createService(undefined, {
start: function () { return function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
return [2 /*return*/, x];
}); }); }; },
});
};
/**
* Restart services named in `partial` using the existing `system`
*/
function startPartial(system, partial) {
return __awaiter(this, void 0, void 0, function () {
var mocks, _i, _a, s, newServices, finalSystem, _b, _c, s;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
mocks = {};
for (_i = 0, _a = Object.keys(system); _i < _a.length; _i++) {
s = _a[_i];
if (!partial.includes(s)) {
mocks[s] = noopService(system[s]);
}
}
return [4 /*yield*/, start(partial, mocks)];
case 1:
newServices = _d.sent();
finalSystem = {};
for (_b = 0, _c = Object.keys(newServices); _b < _c.length; _b++) {
s = _c[_b];
if (Object.prototype.hasOwnProperty.call(mocks, s)) {
finalSystem[s] = system[s];
}
else {
finalSystem[s] = newServices[s];
}
}
return [2 /*return*/, finalSystem];
}
});
});
}
exports.startPartial = startPartial;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLDhEQUE4RDtBQUN4RCxJQUFBLDBCQUFpRixFQUFoRixpQkFBYSxFQUFFLG9CQUFpRSxDQUFDO0FBdUN4RixzRUFBc0U7QUFDdEUsMkRBQTJEO0FBQzNELGlEQUFpRDtBQUNqRCxJQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLHlCQUF1QixPQUFPLFNBQUksT0FBUyxDQUFDLENBQUM7QUFDNUUsSUFBSSxDQUFFLE1BQWMsQ0FBQyxXQUFXLENBQUMsRUFBRTtJQUNoQyxNQUFjLENBQUMsV0FBVyxDQUFDLEdBQUcsRUFBRSxDQUFDO0NBQ25DO0FBQ0QsSUFBTSxRQUFRLEdBQXFCLE1BQWMsQ0FBQyxXQUFXLENBQUMsQ0FBQztBQUUvRCxTQUFTLFVBQVUsQ0FBQyxDQUFNO0lBQ3hCLE9BQU8sT0FBTyxDQUFDLEtBQUssVUFBVSxDQUFDO0FBQ2pDLENBQUM7QUFFRCxTQUFTLE9BQU8sQ0FBQyxDQUFNO0lBQ3JCLE9BQU8sT0FBTyxDQUFDLEtBQUssUUFBUSxJQUFJLENBQUMsWUFBWSxLQUFLLENBQUM7QUFDckQsQ0FBQztBQUVELFNBQVMsU0FBUyxDQUFDLENBQU07SUFDdkIsT0FBTyxVQUFVLENBQUMsQ0FBQyxDQUFDLElBQUksVUFBVSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxVQUFVLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLE9BQU8sQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLENBQUM7QUFDL0YsQ0FBQztBQUVELFNBQVMsT0FBTyxDQUFDLENBQU0sRUFBRSxFQUE0QjtJQUE1QixtQkFBQSxFQUFBLE9BQTRCO0lBQ25ELElBQUksRUFBRSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7UUFD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VyxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQzt5QkFDNUI7NkJBQU07NEJBQ0wsV0FBVyxDQUFDLENBQUMsQ0FBQyxHQUFHLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQzt5QkFDakM7cUJBQ0Y7b0JBRUQsc0JBQU8sV0FBVyxFQUFDOzs7O0NBQ3BCO0FBNUJELG9DQTRCQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdmFyLXJlcXVpcmVzXG5jb25zdCB7bmFtZTogcGtnTmFtZSwgdmVyc2lvbn06IHtuYW1lOiBzdHJpbmc7IHZlcnNpb246IHN0cmluZ30gPSByZXF1aXJlKCcuLi9wYWNrYWdlJyk7XG5cbmV4cG9ydCB0eXBlIFN0YXJ0Rm5UPFQ+ID0gKCguLi5hcmdzOiBhbnlbXSkgPT4gKHBhcnRpYWxTeXN0ZW06IFN5c3RlbSkgPT4gUHJvbWlzZTxUPik7XG5cbmV4cG9ydCB0eXBlIFNlcnZpY2VOYW1lID0gc3RyaW5nO1xuZXhwb3J0IHR5cGUgQWxpYXNlZFNlcnZpY2VOYW1lID0ge3R5cGU6IHN0cmluZzsgYXM6IHN0cmluZ307XG5leHBvcnQgdHlwZSBTZXJ2aWNlPFQsIFN0YXJ0Rm4gZXh0ZW5kcyBTdGFydEZuVDxUPj4gPSB7XG4gICguLi5hcmdzOiBhbnlbXSk6IChwYXJ0aWFsU3lzdGVtOiBTeXN0ZW0pID0+IFByb21pc2U8VD47XG4gIC8vIERvbid0IGNvbmZsaWN0IHdpdGggRnVuY3Rpb24ucHJvdG90eXBlLm5hbWVcbiAgZGVwZW5kZW5jaWVzOiBTZXJ2aWNlTmFtZVtdO1xuICBzZXJ2aWNlTmFtZTogU2VydmljZU5hbWU7XG4gIHN0YXJ0OiBTdGFydEZuO1xuICBzdG9wOiAoKGluc3RhbmNlOiBUKSA9PiB2b2lkKTtcbiAgW2V4dHJhUHJvcHM6IHN0cmluZ106IGFueTtcbn07XG5leHBvcnQgdHlwZSBTZXJ2aWNlSW5zdGFuY2U8VCwgU3RhcnRGbiBleHRlbmRzIFN0YXJ0Rm5UPFQ+PiA9IHtcbiAgKC4uLmFyZ3M6IGFueVtdKTogKHBhcnRpYWxTeXN0ZW06IFN5c3RlbSkgPT4gUHJvbWlzZTxUPjtcbiAgLy8gRG9uJ3QgY29uZmxpY3Qgd2l0aCBGdW5jdGlvbi5wcm90b3R5cGUubmFtZVxuICBkZXBlbmRlbmNpZXM6IFNlcnZpY2VOYW1lW107XG4gIHNlcnZpY2VOYW1lOiBTZXJ2aWNlTmFtZTtcbiAgc3RhcnQ6IChwYXJ0aWFsU3lzdGVtOiBTeXN0ZW0pID0+IFByb21pc2U8VD47XG4gIHN0b3A6ICgoaW5zdGFuY2U6IFQpID0+IHZvaWQpO1xuICBbZXh0cmFQcm9wczogc3RyaW5nXTogYW55O1xufTtcblxuZXhwb3J0IHR5cGUgU3lzdGVtID0ge1trZXkgaW4gU2VydmljZU5hbWVdOiBhbnl9O1xuZXhwb3J0IHR5cGUgU3lzdGVtTWFwID0ge1trZXkgaW4gU2VydmljZU5hbWVdOiBTZXJ2aWNlSW5zdGFuY2U8YW55LCBhbnk+fTtcblxuZXhwb3J0IGludGVyZmFjZSBTZXJ2aWNlRGVzY3JpcHRpb248VCwgU3RhcnRGbiBleHRlbmRzIFN0YXJ0Rm5UPFQ+PiB7XG4gIGRlcGVuZGVuY2llcz86IChTZXJ2aWNlTmFtZSB8IEFsaWFzZWRTZXJ2aWNlTmFtZSB8IFNlcnZpY2U8YW55LCBhbnk+KVtdO1xuICBzdGFydDogU3RhcnRGbjtcbiAgc3RvcD86ICgoaW5zdGFuY2U6IFQpID0+IHZvaWQpO1xufVxuXG5leHBvcnQgdHlwZSBQYWNrYWdlU3BlYyA9IHtwYXRoPzogc3RyaW5nW107IHBhY2thZ2U6IHN0cmluZzsgX19pc1BhY2thZ2VTcGVjOiB0cnVlfTtcbnR5cGUgRnJpZW5kbHlQYWNrYWdlU3BlYyA9IHN0cmluZyB8IFBhY2thZ2VTcGVjIHwgU2VydmljZU5hbWUgfCBTZXJ2aWNlPGFueSwgYW55PjtcblxudHlwZSBTZXJ2aWNlUmVnaXN0cnkgPSB7W3NlcnZpY2UgaW4gU2VydmljZU5hbWVdOiBTZXJ2aWNlPGFueSwgYW55Pn07XG5cbi8vIFBlcnNpc3QgcmVnaXN0cnkgYWNyb3NzIG11bHRpcGxlIGluc3RhbmNlcyBvZiB0aGlzIG1vZHVsZS4gVGVycmlibGVcbi8vIGhhY2ssIGJ1dCBuZWVkZWQgdG8gc3VwcG9ydCBhIHRydWx5ICdnbG9iYWwnIHJlZ2lzdHJ5IGluXG4vLyBlbnZpcm9ubWVudHMgc3VjaCBhcyBsZXJuYSBvciBvbGQgbnBtIHZlcmlzb25zXG5jb25zdCByZWdpc3RyeVN5bSA9IFN5bWJvbC5mb3IoYEdsb2JhbCByZWdpc3RyeSBmb3IgJHtwa2dOYW1lfUAke3ZlcnNpb259YCk7XG5pZiAoIShnbG9iYWwgYXMgYW55KVtyZWdpc3RyeVN5bV0pIHtcbiAgKGdsb2JhbCBhcyBhbnkpW3JlZ2lzdHJ5U3ltXSA9IHt9O1xufVxuY29uc3QgcmVnaXN0cnk6IFNlcnZpY2VSZWdpc3RyeSA9IChnbG9iYWwgYXMgYW55KVtyZWdpc3RyeVN5bV07XG5cbmZ1bmN0aW9uIGlzRnVuY3Rpb24obzogYW55KTogYm9vbGVhbiB7XG4gIHJldHVybiB0eXBlb2YgbyA9PT0gJ2Z1bmN0aW9uJztcbn1cblxuZnVuY3Rpb24gaXNBcnJheShvOiBhbnkpOiBib29sZWFuIHtcbiAgcmV0dXJuIHR5cGVvZiBvID09PSAnb2JqZWN0JyAmJiBvIGluc3RhbmNlb2YgQXJyYXk7XG59XG5cbmZ1bmN0aW9uIGlzU2VydmljZShvOiBhbnkpOiBib29sZWFuIHtcbiAgcmV0dXJuIGlzRnVuY3Rpb24obykgJiYgaXNGdW5jdGlvbihvLnN0YXJ0KSAmJiBpc0Z1bmN0aW9uKG8uc3RvcCkgJiYgaXNBcnJheShvLmRlcGVuZGVuY2llcyk7XG59XG5cbmZ1bmN0aW9uIGdldFBhdGgobzogYW55LCBrczogKHN0cmluZyB8IG51bWJlcilbXSA9IFtdKTogYW55IHtcbiAgaWYgKGtzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBvO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiBnZXRQYXRoKG9ba3NbMF1dLCBrcy5zbGljZSgxKSk7XG4gIH1cbn1cblxuZnVuY3Rpb24gcGFyc2VQYWNrYWdlKHM6IHN0cmluZyk6IFBhY2thZ2VTcGVjIHtcbiAgY29uc3QgcGFydHMgPSBzLnNwbGl0KCcuJyk7XG4gIHJldHVybiB7cGF0aDogcGFydHMuc2xpY2UoMSksIHBhY2thZ2U6IHBhcnRzWzBdLCBfX2lzUGFja2FnZVNwZWM6IHRydWV9O1xufVxuXG5jb25zdCBub3RGb3VuZCA9IFN5bWJvbCgnUGFja2FnZSBub3QgZm91bmQnKTtcbmZ1bmN0aW9uIHRyeVJlcXVpcmUocDogc3RyaW5nIHwgUGFja2FnZVNwZWMpOiBTZXJ2aWNlPGFueSwgYW55PiB8IHN5bWJvbCB7XG4gIGlmICh0eXBlb2YgcCA9PT0gJ3N0cmluZycpIHtcbiAgICBwID0gcGFyc2VQYWNrYWdlKHApO1xuICB9XG5cbiAgdHJ5IHtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXZhci1yZXF1aXJlc1xuICAgIGNvbnN0IHNlcnZpY2UgPSBnZXRQYXRoKHJlcXVpcmUocC5wYWNrYWdlKSwgKHAucGF0aCB8fCBbXSkpO1xuICAgIHJldHVybiBzZXJ2aWNlO1xuICB9IGNhdGNoIChlKSB7XG4gICAgcmV0dXJuIG5vdEZvdW5kO1xuICB9XG59XG5cbmZ1bmN0aW9uIHJlcXVpcmVPclRocm93KHA6IHN0cmluZyB8IFBhY2thZ2VTcGVjKTogU2VydmljZTxhbnksIGFueT4ge1xuICBjb25zdCByZXF1aXJlZCA9IHRyeVJlcXVpcmUocCk7XG4gIGlmIChyZXF1aXJlZCA9PT0gbm90Rm91bmQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYENvdWxkbid0IHJlc29sdmUgZGVwZW5kZW5jeTogXCIke3B9XCJgKTtcbiAgfSBlbHNlIGlmICghaXNTZXJ2aWNlKHJlcXVpcmVkKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgUmVzb2x2ZWQgXCIke3B9XCIgYnV0IGV4cGVjdGVkIGEgU2VydmljZSwgbm90IFwiJHtTdHJpbmcocmVxdWlyZWQpfVwiYCk7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIChyZXF1aXJlZCBhcyBTZXJ2aWNlPGFueSwgYW55Pik7XG4gIH1cbn1cblxuZnVuY3Rpb24gZGVwZW5kZW5jeU9yU2VydmljZShpbnB1dDogRnJpZW5kbHlQYWNrYWdlU3BlYyk6IHN0cmluZyB8IGtleW9mIFBhY2thZ2VTcGVjIHtcbiAgaWYgKHR5cGVvZiBpbnB1dCA9PT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gaW5wdXQ7XG4gIH0gZWxzZSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGlucHV0LCAnX19pc1BhY2thZ2VTcGVjJykpIHtcbiAgICByZXR1cm4gcmVxdWlyZU9yVGhyb3coKGlucHV0IGFzIFBhY2thZ2VTcGVjKSkuc2VydmljZU5hbWU7XG4gIH1cbiAgcmV0dXJuIChpbnB1dCBhcyBTZXJ2aWNlPGFueSwgYW55Pikuc2VydmljZU5hbWU7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBkYW5nZXJvdXNseVJlc2V0UmVnaXN0cnkoKTogdm9pZCB7XG4gIGZvciAoY29uc3Qgc2VydmljZU5hbWUgb2YgT2JqZWN0LmtleXMocmVnaXN0cnkpKSB7XG4gICAgZGVsZXRlIHJlZ2lzdHJ5W3NlcnZpY2VOYW1lXTtcbiAgfVxufVxuXG5mdW5jdGlvbiBjbG9uZUZuPFQ+KGZuOiAoKC4uLmFyZ3M6IGFueVtdKSA9PiBUKSk6ICgoLi4uYXJnczogYW55W10pID0+IFQpIHtcbiAgcmV0dXJuICguLi5hcmdzOiBhbnlbXSk6IFQgPT4gZm4oLi4uYXJncyk7XG59XG5cbi8qKlxuICogQ3JlYXRlIGEgc2VydmljZSBuYW1lZCBgbmFtZWAgd2l0aCBzdGFydCwgc3RvcCwgZXRjIGFzIGRlZmluZWQgaW5cbiAqIGBkZXNjcmlwdGlvbmAuXG4gKlxuICogTGVhdmUgYG5hbWVgIHVuZGVmaW5lZCB0byBjcmVhdGUgYW4gYW5vbnltb3VzIHNlcnZpY2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVTZXJ2aWNlPFQsIFN0YXJ0Rm4gZXh0ZW5kcyBTdGFydEZuVDxUPj4oXG4gIG5hbWU6IFNlcnZpY2VOYW1lIHwgdW5kZWZpbmVkLFxuICBkZXNjcmlwdGlvbjogU2VydmljZURlc2NyaXB0aW9uPFQsIFN0YXJ0Rm4+LFxuKTogU2VydmljZTxULCBTdGFydEZuPiB7XG4gIGNvbnN0IGRlZmF1bHRlZERlc2NyaXB0aW9uID0gey4uLmRlc2NyaXB0aW9ufTtcbiAgaWYgKCFBcnJheS5pc0FycmF5KGRlZmF1bHRlZERlc2NyaXB0aW9uLmRlcGVuZGVuY2llcykpIHtcbiAgICBkZWZhdWx0ZWREZXNjcmlwdGlvbi5kZXBlbmRlbmNpZXMgPSBbXTtcbiAgfVxuXG4gIGlmICghZGVmYXVsdGVkRGVzY3JpcHRpb24uc3RvcCkge1xuICAgIGRlZmF1bHRlZERlc2NyaXB0aW9uLnN0b3AgPSAoKTogdm9pZCA9PiB1bmRlZmluZWQ7XG4gIH1cblxuICBjb25zdCBzdGFydDogU3RhcnRGbiA9IChjbG9uZUZuKGRlZmF1bHRlZERlc2NyaXB0aW9uLnN0YXJ0KSBhcyBhbnkpLFxuICAgIHNlcnZpY2U6IFNlcnZpY2U8VCwgU3RhcnRGbj4gPSAoT2JqZWN0LmFzc2lnbihzdGFydCwge1xuICAgICAgZGVwZW5kZW5jaWVzOiBkZWZhdWx0ZWREZXNjcmlwdGlvbi5kZXBlbmRlbmNpZXMsXG4gICAgICBzZXJ2aWNlTmFtZTogbmFtZSxcbiAgICAgIHN0YXJ0LFxuICAgICAgc3RvcDogZGVmYXVsdGVkRGVzY3JpcHRpb24uc3RvcCxcbiAgICB9KSBhcyBhbnkpO1xuXG4gIGlmIChuYW1lKSB7XG4gICAgcmVnaXN0cnlbbmFtZV0gPSBzZXJ2aWNlO1xuICB9XG4gIHJldHVybiBzZXJ2aWNlO1xufVxuXG5mdW5jdGlvbiBmbGF0dGVuPFQ+KGxsOiBJdGVyYWJsZTxUPltdKTogVFtdIHtcbiAgcmV0dXJuIChbXSBhcyBUW10pLmNvbmNhdCguLi5sbC5tYXAoaXQgPT4gQXJyYXkuZnJvbShpdCkpKTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgc2VydmljZSB0aGF0LCB3aGVuIHVzZWQsIGlzIGxvYWRlZCBmcm9tIHRoZSBnaXZlbiBub2RlXG4gKiBwYWNrYWdlTmFtZSAoZWcgQHNjb3BlL3NvbWUtY29vbC1wYWNrYWdlL3BhdGgvaW5zaWRlL3BhY2thZ2UpIGFuZCBhXG4gKiBsb2Rhc2ggZ2V0LXN0eWxlIHBhdGggKGVnIFwiYWJjLjAuaGlcIiB0byBnZXQgXCJ4XCIgZnJvbSB7YWJjOlt7aGk6XCJ4XCJ9XX0pLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZnJvbVBhY2thZ2UocGFja2FnZU5hbWU6IHN0cmluZywgcGF0aD86IHN0cmluZ1tdKTogUGFja2FnZVNwZWMge1xuICByZXR1cm4ge3BhdGgsIHBhY2thZ2U6IHBhY2thZ2VOYW1lLCBfX2lzUGFja2FnZVNwZWM6IHRydWV9O1xufVxuXG4vLyBUT0RPOiBDYW4gZ2V0IHJpZCBvZiAnYW55JyBvbmNlIFZhcmlhZGljIEtpbmRzIGxhbmRzIChUUyBpc3N1ZSAjNTQ1MylcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdGFydChcbiAgbmFtZXNPclNlcnZpY2VzOiAoU2VydmljZU5hbWUgfCBQYWNrYWdlU3BlYyB8IFNlcnZpY2U8YW55LCBhbnk+IHwgKFBhY2thZ2VTcGVjIHwgU2VydmljZTxhbnksIGFueT4gfCBTZXJ2aWNlTmFtZSlbXSksXG4gIG92ZXJyaWRlc0luOiBTeXN0ZW0gPSB7fSxcbik6IFByb21pc2U8U3lzdGVtPiB7XG4gIGlmICghQXJyYXkuaXNBcnJheShuYW1lc09yU2VydmljZXMpKSB7XG4gICAgbmFtZXNPclNlcnZpY2VzID0gW25hbWVzT3JTZXJ2aWNlc107XG4gIH1cblxuICAvLyBDbG9uZSwgc28gd2UgZG9uJ3Qgb3ZlcnJpZGUgdGhlIGlucHV0XG4gIGNvbnN0IG92ZXJyaWRlczogU3lzdGVtID0ge307XG4gIE9iamVjdC5hc3NpZ24ob3ZlcnJpZGVzLCBvdmVycmlkZXNJbik7XG5cbiAgZnVuY3Rpb24gcmVzb2x2ZShzZXJ2aWNlTmFtZTogU2VydmljZU5hbWUpOiBTZXJ2aWNlPGFueSwgYW55PiB7XG4gICAgaWYgKG92ZXJyaWRlcyAmJiBvdmVycmlkZXNbc2VydmljZU5hbWVdKSB7XG4gICAgICByZXR1cm4gb3ZlcnJpZGVzW3NlcnZpY2VOYW1lXTtcbiAgICB9IGVsc2UgaWYgKHJlZ2lzdHJ5W3NlcnZpY2VOYW1lXSkge1xuICAgICAgcmV0dXJuIHJlZ2lzdHJ5W3NlcnZpY2VOYW1lXTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHJlcXVpcmVPclRocm93KHNlcnZpY2VOYW1lKTtcbiAgICB9XG4gIH1cblxuICBjb25zdCBzZXJ2aWNlczogU2VydmljZTxhbnksIGFueT5bXSA9IG5hbWVzT3JTZXJ2aWNlcy5tYXAobmFtZU9yU2VydmljZSA9PiB7XG4gICAgaWYgKHR5cGVvZiBuYW1lT3JTZXJ2aWNlID09PSAnc3RyaW5nJykge1xuICAgICAgaWYgKHJlZ2lzdHJ5W25hbWVPclNlcnZpY2VdKSB7XG4gICAgICAgIHJldHVybiByZWdpc3RyeVtuYW1lT3JTZXJ2aWNlXTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQ291bGRuJ3QgZmluZDogXCIke25hbWVPclNlcnZpY2V9XCJgKTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChuYW1lT3JTZXJ2aWNlLCAnX19pc1BhY2thZ2VTcGVjJykpIHtcbiAgICAgIHJldHVybiByZXF1aXJlT3JUaHJvdyhuYW1lT3JTZXJ2aWNlIGFzIFBhY2thZ2VTcGVjKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIChuYW1lT3JTZXJ2aWNlIGFzIFNlcnZpY2U8YW55LCBhbnk+KTtcbiAgICB9XG4gIH0pO1xuXG4gIGZvciAoY29uc3QgcyBvZiBzZXJ2aWNlcykge1xuICAgIGlmICghb3ZlcnJpZGVzW3Muc2VydmljZU5hbWVdKSB7XG4gICAgICBvdmVycmlkZXNbcy5zZXJ2aWNlTmFtZV0gPSBzO1xuICAgIH1cbiAgfVxuXG4gIC8vIFJlc29sdmUgYWxsIHJlcXVpcmVkIGRlcGVuZGVuY2llcywgYnVpbGRpbmcgb2YgYSBtYXAgb2ZcbiAgLy8gc2VydmljZU5hbWVzIC0+IHN0aWxsIHJlcXVpcmVkIGRlcGVuZGVuY2llc1xuICBjb25zdCBvdXRzdGFuZGluZ0RlcHM6IHtbcyBpbiBTZXJ2aWNlTmFtZV06IFNldDxTZXJ2aWNlTmFtZT59ID0ge307XG4gIGxldCB0b1Byb2Nlc3MgPSBuZXcgU2V0KHNlcnZpY2VzLm1hcChzID0+IHMuc2VydmljZU5hbWUpKTtcbiAgZG8ge1xuICAgIHRvUHJvY2Vzcy5mb3JFYWNoKHMgPT4ge1xuICAgICAgb3V0c3RhbmRpbmdEZXBzW3NdID0gbmV3IFNldChyZXNvbHZlKHMpLmRlcGVuZGVuY2llcy5tYXAoZGVwZW5kZW5jeU9yU2VydmljZSkpO1xuICAgIH0pO1xuXG4gICAgdG9Qcm9jZXNzID0gbmV3IFNldChmbGF0dGVuKE9iamVjdC52YWx1ZXMob3V0c3RhbmRpbmdEZXBzKSkpO1xuICAgIE9iamVjdC5rZXlzKG91dHN0YW5kaW5nRGVwcykuZm9yRWFjaChrID0+IHRvUHJvY2Vzcy5kZWxldGUoaykpO1xuICB9IHdoaWxlICh0b1Byb2Nlc3Muc2l6ZSA+IDApO1xuXG4gIC8vIEZpbmFsIG91dHB1dCBzeXN0ZW0gd2UnbGwgYnVpbGQgdXBcbiAgY29uc3Qgc3lzdGVtOiB7W2tleSBpbiBTZXJ2aWNlTmFtZV06IGFueX0gPSB7fTtcblxuICBjb25zdCBvdXRzdGFuZGluZ0xvYWRzOiB7W25hbWUgaW4gU2VydmljZU5hbWVdOiBQcm9taXNlPFNlcnZpY2U8YW55LCBhbnk+Pn0gPSB7fTtcbiAgYXN5bmMgZnVuY3Rpb24gbG9hZChuYW1lOiBTZXJ2aWNlTmFtZSk6IFByb21pc2U8U2VydmljZTxhbnksIGFueT4+IHtcbiAgICBjb25zdCBzZXJ2aWNlID0gYXdhaXQgcmVzb2x2ZShuYW1lKSgpKHsuLi5zeXN0ZW19KTtcblxuICAgIGRlbGV0ZSBvdXRzdGFuZGluZ0xvYWRzW25hbWVdO1xuICAgIE9iamVjdC52YWx1ZXMob3V0c3RhbmRpbmdEZXBzKS5mb3JFYWNoKGRlcHMgPT4gZGVwcy5kZWxldGUobmFtZSkpO1xuXG4gICAgLy8gV2UgZHVwbGljYXRlIHRoZSBgc3lzdGVtYCBvYmplY3QsIHNvIHNlcnZpY2VzIGNhbid0IG11dGF0ZSBvdXJcbiAgICAvLyBtYXN0ZXIgY29weSBvZiB0aGUgc3lzdGVtLiBUaHVzLCB0aGUgcG9zc2libGUgcmFjZSBjb25kaXRpb25cbiAgICAvLyB0aGF0IGVzbGludCBkZXRlY3RzIGhlcmUgaXMgYSBmYWxzZSBwb3NpdGl2ZS5cbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcmVxdWlyZS1hdG9taWMtdXBkYXRlc1xuICAgIHN5c3RlbVtuYW1lXSA9IHNlcnZpY2U7XG5cbiAgICByZXR1cm4gc2VydmljZTtcbiAgfVxuXG4gIHdoaWxlIChPYmplY3Qua2V5cyhvdXRzdGFuZGluZ0RlcHMpLmxlbmd0aCA+IDAgfHxcbiAgICAgICAgT2JqZWN0LmtleXMob3V0c3RhbmRpbmdMb2FkcykubGVuZ3RoID4gMCkge1xuICAgIC8vIFN0YXJ0IGxvYWRpbmcgYW55IGRlcHMgdGhhdCBhcmUgbm8gbG9uZ2VyIHdhaXRpbmcgZm9yIGFub3RoZXIgZGVwXG4gICAgZm9yIChjb25zdCBbbmFtZSwgZGVwc10gb2YgT2JqZWN0LmVudHJpZXMob3V0c3RhbmRpbmdEZXBzKSkge1xuICAgICAgaWYgKGRlcHMuc2l6ZSA9PT0gMCkge1xuICAgICAgICBvdXRzdGFuZGluZ0xvYWRzW25hbWVdID0gbG9hZChuYW1lKTtcbiAgICAgICAgZGVsZXRlIG91dHN0YW5kaW5nRGVwc1tuYW1lXTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoT2JqZWN0LmtleXMob3V0c3RhbmRpbmdMb2FkcykubGVuZ3RoID09PSAwICYmXG4gICAgICAgIE9iamVjdC5rZXlzKG91dHN0YW5kaW5nRGVwcykubGVuZ3RoID4gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDeWNsZSBkZXRlY3RlZCcpO1xuICAgIH1cblxuICAgIC8vIFdhaXQgZm9yIHRoZSBuZXh0IGRlcCB0byBmaW5pc2ggc3RhcnRpbmdcbiAgICBhd2FpdCBQcm9taXNlLnJhY2UoT2JqZWN0LnZhbHVlcyhvdXRzdGFuZGluZ0xvYWRzKSk7XG4gIH1cblxuICByZXR1cm4gc3lzdGVtO1xufVxuXG4vKipcbiAqIFN0b3Agc3lzdGVtLiBJZiBhIHNwZWMgb2Ygc3lzdGVtcyBgcGFydGlhbGAgaXMgc3VwcGxpZWQsIHN0b3Agb25seVxuICogdGhvc2Ugc3lzdGVtcyBhbmQgYW55IFwiaGlnaGVyXCIgc3lzdGVtcyB0aGF0IHJlbHkgb24gdGhlbSwgYnV0XG4gKiBvdGhlcnMgd2lsbCBiZSBsZWZ0IGFsb25lLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RvcChcbiAgc3lzdGVtOiBTeXN0ZW0sXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgY291bnREZXBlbmRlbnRzOiB7W3MgaW4gU2VydmljZU5hbWVdOiBudW1iZXJ9ID0ge307XG4gIGZvciAoY29uc3QgcyBvZiBPYmplY3Qua2V5cyhzeXN0ZW0pKSB7XG4gICAgY291bnREZXBlbmRlbnRzW3NdID0gMDtcbiAgfVxuXG4gIGZvciAoY29uc3QgcyBvZiBPYmplY3Qua2V5cyhzeXN0ZW0pKSB7XG4gICAgZm9yIChjb25zdCBkIG9mIHJlZ2lzdHJ5W3NdLmRlcGVuZGVuY2llcy5tYXAoZGVwZW5kZW5jeU9yU2VydmljZSkpIHtcbiAgICAgIGNvdW50RGVwZW5kZW50c1tkXSsrO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IG91dHN0YW5kaW5nU2h1dGRvd25zOiB7W3MgaW4gU2VydmljZU5hbWVdOiBQcm9taXNlPHZvaWQ+fSA9IHt9LFxuICAgIGZpbmlzaGVkU2h1dGRvd25zOiB7W3MgaW4gU2VydmljZU5hbWVdOiBib29sZWFufSA9IHt9O1xuICBkbyB7XG4gICAgZm9yIChjb25zdCBbcywgcmVtYWluaW5nRGVwZW5kZW50c10gb2YgT2JqZWN0LmVudHJpZXMoY291bnREZXBlbmRlbnRzKSkge1xuICAgICAgaWYgKHJlbWFpbmluZ0RlcGVuZGVudHMgPT09IDAgJiZcbiAgICAgICAgICAhb3V0c3RhbmRpbmdTaHV0ZG93bnNbc10gJiZcbiAgICAgICAgICAhZmluaXNoZWRTaHV0ZG93bnNbc10pIHtcblxuICAgICAgICBvdXRzdGFuZGluZ1NodXRkb3duc1tzXSA9IChhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgICAgY29uc3Qgc2VydmljZSA9IHJlZ2lzdHJ5W3NdO1xuICAgICAgICAgIGF3YWl0IHNlcnZpY2Uuc3RvcChzeXN0ZW1bc10pO1xuICAgICAgICAgIGZpbmlzaGVkU2h1dGRvd25zW3NdID0gdHJ1ZTtcbiAgICAgICAgICBkZWxldGUgb3V0c3RhbmRpbmdTaHV0ZG93bnNbc107XG4gICAgICAgICAgZm9yIChjb25zdCBkIG9mIHNlcnZpY2UuZGVwZW5kZW5jaWVzLm1hcChkZXBlbmRlbmN5T3JTZXJ2aWNlKSkge1xuICAgICAgICAgICAgY291bnREZXBlbmRlbnRzW2RdLS07XG4gICAgICAgICAgfVxuICAgICAgICB9KSgpO1xuXG4gICAgICB9XG4gICAgfVxuXG4gICAgYXdhaXQgUHJvbWlzZS5yYWNlKE9iamVjdC52YWx1ZXMob3V0c3RhbmRpbmdTaHV0ZG93bnMpKTtcbiAgfSB3aGlsZSAoT2JqZWN0LmtleXMoZmluaXNoZWRTaHV0ZG93bnMpLmxlbmd0aCA8IE9iamVjdC5rZXlzKHN5c3RlbSkubGVuZ3RoKTtcbn1cblxuLyoqXG4gKiBTdG9wIHN5c3RlbS4gSWYgYSBzcGVjIG9mIHN5c3RlbXMgYHBhcnRpYWxgIGlzIHN1cHBsaWVkLCBzdG9wIG9ubHlcbiAqIHRob3NlIHN5c3RlbXMgYW5kIGFueSBcImhpZ2hlclwiIHN5c3RlbXMgdGhhdCByZWx5IG9uIHRoZW0sIGJ1dFxuICogb3RoZXJzIHdpbGwgYmUgbGVmdCBhbG9uZS5cbiAqXG4gKiBSZXR1cm5zIHRoZSBsaXN0IG9mIHNlcnZpY2VzIG5hbWVzIHRoYXQgd2VyZSBzaHV0ZG93blxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RvcFBhcnRpYWwoXG4gIHN5c3RlbTogU3lzdGVtLFxuICBwYXJ0aWFsOiBTZXJ2aWNlTmFtZVtdLFxuKTogUHJvbWlzZTxTZXJ2aWNlTmFtZVtdPiB7XG4gIC8vIFJldmVyc2UgdGhlIHNlcnZpY2UgZ3JhcGggdG8gZ2V0IGEgbWFwIG9mIGRlcGVuZGVudHMsIGluc3RlYWQgb2ZcbiAgLy8gZGVwZW5kZW5jaWVzXG4gIGNvbnN0IGRlcGVuZGVudHM6IHtbcyBpbiBTZXJ2aWNlTmFtZV06IFNlcnZpY2VOYW1lW119ID0ge307XG4gIGZvciAoY29uc3QgcyBvZiBPYmplY3Qua2V5cyhzeXN0ZW0pKSB7XG4gICAgZGVwZW5kZW50c1tzXSA9IFtdO1xuICB9XG4gIGZvciAoY29uc3QgcyBvZiBPYmplY3Qua2V5cyhzeXN0ZW0pKSB7XG4gICAgZm9yIChjb25zdCBkIG9mIHJlZ2lzdHJ5W3NdLmRlcGVuZGVuY2llcy5tYXAoZGVwZW5kZW5jeU9yU2VydmljZSkpIHtcbiAgICAgIGlmIChzeXN0ZW1bZF0pIHtcbiAgICAgICAgZGVwZW5kZW50c1tkXS5wdXNoKHMpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIEZvbGxvdyBhbGwgZGVwZW5kZW50IHJlbGF0aW9uc2hpcHMgZnJvbSB0aGUgdGFyZ2V0IFwicGFydGlhbFwiXG4gIC8vIHN1YmdyYXBoIHRvIGJlIHNodXRkb3duXG4gIGNvbnN0IHRvU2h1dGRvd24gPSBuZXcgU2V0PHN0cmluZz4oKSxcbiAgICB0b1Zpc2l0ID0gcGFydGlhbC5zbGljZSgpLFxuICAgIHZpc2l0ZWQgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgbGV0IHZpc2l0aW5nO1xuICB3aGlsZSAodmlzaXRpbmcgPSB0b1Zpc2l0LnBvcCgpKSB7XG4gICAgdmlzaXRlZC5hZGQodmlzaXRpbmcpO1xuICAgIHRvU2h1dGRvd24uYWRkKHZpc2l0aW5nKTtcblxuICAgIGZvciAoY29uc3QgcyBvZiBkZXBlbmRlbnRzW3Zpc2l0aW5nXSkge1xuICAgICAgaWYgKCF2aXNpdGVkLmhhcyhzKSkge1xuICAgICAgICB0b1Zpc2l0LnB1c2gocyk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgY29uc3QgcGFydGlhbFN5c3RlbTogU3lzdGVtID0ge30sXG4gICAgb3V0cHV0OiBzdHJpbmdbXSA9IFtdO1xuICB0b1NodXRkb3duLmZvckVhY2gocyA9PiB7XG4gICAgcGFydGlhbFN5c3RlbVtzXSA9IHN5c3RlbVtzXTtcbiAgICBvdXRwdXQucHVzaChzKTtcbiAgfSk7XG5cbiAgYXdhaXQgc3RvcChwYXJ0aWFsU3lzdGVtKTtcblxuICByZXR1cm4gb3V0cHV0O1xufVxuXG5jb25zdCBub29wU2VydmljZTogKCh4OiBhbnkpID0+IFNlcnZpY2VEZXNjcmlwdGlvbjxhbnksIGFueT4pID0geCA9PlxuICBjcmVhdGVTZXJ2aWNlKFxuICAgIHVuZGVmaW5lZCwge1xuICAgICAgc3RhcnQ6ICgpID0+IGFzeW5jICgpOiBQcm9taXNlPGFueT4gPT4geCxcbiAgICB9LFxuICApO1xuXG4vKipcbiAqIFJlc3RhcnQgc2VydmljZXMgbmFtZWQgaW4gYHBhcnRpYWxgIHVzaW5nIHRoZSBleGlzdGluZyBgc3lzdGVtYFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhcnRQYXJ0aWFsKFxuICBzeXN0ZW06IFN5c3RlbSxcbiAgcGFydGlhbDogU2VydmljZU5hbWVbXSxcbik6IFByb21pc2U8U3lzdGVtPiB7XG4gIC8vIE1vY2sgb3V0IGV4aXN0aW5nIHNlcnZpY2VzIHdpdGggYG5vb3BTZXJ2aWNlYCwgdGhlbiByZWxhdW5jaCB0aGVcbiAgLy8gZnVsbCBzeXN0ZW0gd2l0aCB0aG9zZSBtb2NrcyB0byByZWNyZWF0ZSB0aGUgc2VydmljZXMgcmVxdWVzdGVkXG4gIC8vIGluIGBwYXJ0aWFsYCwgYW5kIGZpbmFsbHkgbWVyZ2UgdGhvc2UgbmV3bHkgbGF1bmNoZWQgc2VydmljZXNcbiAgLy8gYmFjayBpbnRvIHRoZSBleGlzdGluZyBzeXN0ZW0uXG5cbiAgY29uc3QgbW9ja3M6IFN5c3RlbSA9IHt9O1xuICBmb3IgKGNvbnN0IHMgb2YgT2JqZWN0LmtleXMoc3lzdGVtKSkge1xuICAgIGlmICghcGFydGlhbC5pbmNsdWRlcyhzKSkge1xuICAgICAgbW9ja3Nbc10gPSBub29wU2VydmljZShzeXN0ZW1bc10pO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IG5ld1NlcnZpY2VzID0gYXdhaXQgc3RhcnQocGFydGlhbCwgbW9ja3MpO1xuXG4gIGNvbnN0IGZpbmFsU3lzdGVtOiBTeXN0ZW0gPSB7fTtcbiAgZm9yIChjb25zdCBzIG9mIE9iamVjdC5rZXlzKG5ld1NlcnZpY2VzKSkge1xuICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3