firebase-bolt
Version:
Firebase Bolt Security and Modeling Language Compiler
306 lines (304 loc) • 37.1 kB
JavaScript
"use strict";
exports.__esModule = true;
/*
* Firebase Rules test simulator.
*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var chai_1 = require("chai");
var rest = require("./firebase-rest");
var util = require("./util");
var fileIO = require("./file-io");
var bolt = require("./bolt");
var generate = util.lift(bolt.generate);
var readFile = util.liftArgs(fileIO.readFile);
var MAX_TEST_MS = 60000;
;
function rulesSuite(suiteName, fnSuite) {
new RulesSuite(suiteName, fnSuite).run();
}
exports.rulesSuite = rulesSuite;
var RulesSuite = /** @class */ (function () {
function RulesSuite(suiteName, fnSuite) {
this.suiteName = suiteName;
this.fnSuite = fnSuite;
this.debug = false;
this.users = {};
this.tests = [];
}
RulesSuite.prototype.setDebug = function (debug) {
if (debug === void 0) { debug = true; }
this.debug = debug;
return this;
};
RulesSuite.prototype.run = function () {
var self = this;
// Run Mocha Test Suite - serialize with any other mocha test suites.
suite("Firebase Rules Simulator: " + self.suiteName, function () {
this.timeout(MAX_TEST_MS);
suiteSetup(function () {
var rulesPath = new Promise(function (resolve) {
self.rulesPathResolve = resolve;
});
var database = new Promise(function (resolve) {
self.databaseReady = resolve;
});
var rulesJSON = generate(util.getProp(readFile(rulesPath), 'content'));
self.ready = Promise.all([rulesJSON, database])
.then(self.onRulesReady.bind(self));
// Execute initialization and get test definitions (in client code).
self.fnSuite(self.getInterface());
return self.ready;
});
test("Initialization.", function () {
// pass
});
test("Rules test.", function () {
return self.runTests();
});
});
};
RulesSuite.prototype.getInterface = function () {
var test = this.test.bind(this);
test.rules = this.rules.bind(this);
test.database = this.database.bind(this);
test.uid = this.uid.bind(this);
test.TIMESTAMP = rest.TIMESTAMP;
return test;
};
// Called when rules are generated and test database is known.
RulesSuite.prototype.onRulesReady = function (prereq) {
var rulesJSON = prereq[0];
return this.adminClient.put(rest.RULES_LOCATION, rulesJSON);
};
RulesSuite.prototype.runTests = function () {
var p = Promise.resolve();
function next(prev, test) {
return prev.then(function () {
return test.run();
});
}
for (var i = 0; i < this.tests.length; i++) {
p = next(p, this.tests[i]);
}
return p;
};
RulesSuite.prototype.test = function (testName, fnTest) {
this.tests.push(new RulesTest(testName, this, fnTest));
};
RulesSuite.prototype.rules = function (rulesPath) {
if (this.rulesPath) {
throw new Error("Only expect a single call to the test.rules function.");
}
this.rulesPath = rulesPath;
this.rulesPathResolve(util.ensureExtension(rulesPath, bolt.FILE_EXTENSION));
};
RulesSuite.prototype.database = function (appName, appSecret) {
if (this.adminClient) {
throw new Error("Only expect a single call to the test.database function.");
}
this.appName = appName;
this.appSecret = appSecret;
this.adminClient = this.ensureUser('admin');
this.databaseReady();
};
RulesSuite.prototype.uid = function (username) {
return this.ensureUser(username).uid;
};
RulesSuite.prototype.ensureUser = function (username) {
if (!(username in this.users)) {
if (username === 'anon') {
this.users[username] = new rest.Client(this.appName);
}
else {
var tokenInfo = rest.generateUidAuthToken(this.appSecret, { debug: true,
admin: username === 'admin' });
this.users[username] = new rest.Client(this.appName, tokenInfo.token, tokenInfo.uid);
}
}
return this.users[username];
};
return RulesSuite;
}());
exports.RulesSuite = RulesSuite;
var RulesTest = /** @class */ (function () {
function RulesTest(testName, suite, fnTest) {
this.testName = testName;
this.suite = suite;
this.fnTest = fnTest;
this.steps = [];
this.failed = false;
}
RulesTest.prototype.run = function () {
var _this = this;
this.debug(false);
this.as('admin');
this.at('/');
this.write(null);
this.succeeds("initialization");
this.at(undefined);
this.as('anon');
this.fnTest(this);
this.debug(false);
return this.executeQueue()
.then(function () {
_this.log("Finished");
})["catch"](function (error) {
_this.log("Failed: " + error);
throw error;
});
};
// Queue a function to be called in sequence after previous step
// in test is (successfully) completed.
RulesTest.prototype.queue = function (op, args, fn) {
if (this.failed) {
return;
}
var argsT = util.copyArray(args).map(function (x) {
return util.prettyJSON(x);
});
var label = op + '(' + argsT.join(', ') + ')';
this.steps.push({ label: label, fn: fn });
};
RulesTest.prototype.executeQueue = function () {
var self = this;
this.log("Executing (" + this.steps.length + " steps)");
var p = Promise.resolve(true);
function next(prev, step) {
return prev.then(function () {
self.log(step.label);
return step.fn();
});
}
for (var i = 0; i < this.steps.length; i++) {
p = next(p, this.steps[i]);
}
return p;
};
RulesTest.prototype.debug = function (debug) {
var _this = this;
this.suite.setDebug(debug);
this.queue('debug', arguments, function () {
_this.suite.setDebug(debug);
return Promise.resolve();
});
return this;
};
RulesTest.prototype.as = function (username) {
var _this = this;
var client = this.suite.ensureUser(username);
this.queue('as', arguments, function () {
client.setDebug(_this.suite.debug);
_this.client = client;
return Promise.resolve();
});
return this;
};
RulesTest.prototype.at = function (opPath) {
var _this = this;
this.queue('at', arguments, function () {
_this.path = opPath;
return Promise.resolve();
});
return this;
};
RulesTest.prototype.write = function (obj) {
var _this = this;
this.queue('write', arguments, function () {
if (_this.path === undefined) {
return Promise.reject(new Error("Use at() function to set path to write."));
}
return _this.client.put(_this.path, obj)
.then(function () {
_this.status = true;
})["catch"](function (error) {
_this.status = false;
_this.lastError = error;
});
});
return this;
};
RulesTest.prototype.push = function (obj) {
var _this = this;
this.queue('write', arguments, function () {
if (_this.path === undefined) {
return Promise.reject(new Error("Use at() function to set path to push."));
}
var path = _this.path;
if (path.slice(-1)[0] !== '/') {
path += '/';
}
path += rest.generatePushID();
return _this.client.put(path, obj)
.then(function () {
_this.status = true;
})["catch"](function (error) {
_this.status = false;
_this.lastError = error;
});
});
return this;
};
RulesTest.prototype.read = function () {
var _this = this;
this.queue('read', arguments, function () {
if (_this.path === undefined) {
return Promise.reject(new Error("Use at() function to set path to read."));
}
return _this.client.get(_this.path)
.then(function () {
_this.status = true;
})["catch"](function (error) {
_this.status = false;
_this.lastError = error;
});
});
return this;
};
RulesTest.prototype.succeeds = function (message) {
var _this = this;
this.queue('succeeds', arguments, function () {
chai_1.assert(_this.status === true, _this.messageFormat(message + " (should have succeed)\n" + _this.lastError));
_this.good(message);
_this.status = undefined;
return Promise.resolve();
});
return this;
};
RulesTest.prototype.fails = function (message) {
var _this = this;
this.queue('fails', arguments, function () {
chai_1.assert(_this.status === false, _this.messageFormat(message + " (should have failed)"));
_this.good(message);
_this.status = undefined;
return Promise.resolve();
});
return this;
};
RulesTest.prototype.good = function (message) {
this.log(message + " (Correct)");
};
RulesTest.prototype.log = function (message) {
if (this.suite.debug) {
console.log(this.messageFormat(message));
}
};
RulesTest.prototype.messageFormat = function (message) {
return this.suite.suiteName + "." + this.testName + " " + message;
};
return RulesTest;
}());
exports.RulesTest = RulesTest;
//# sourceMappingURL=data:application/json;charset=utf8;base64,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QUFaLFVBQWEsT0FBZTtRQUMxQixJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sR0FBRyxZQUFZLENBQUMsQ0FBQztJQUNuQyxDQUFDO0lBRU8sdUJBQUcsR0FBWCxVQUFZLE9BQWU7UUFDekIsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRTtZQUNwQixPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztTQUMxQztJQUNILENBQUM7SUFFRCxpQ0FBYSxHQUFiLFVBQWMsT0FBZTtRQUMzQixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxHQUFHLEdBQUcsR0FBRyxJQUFJLENBQUMsUUFBUSxHQUFHLEdBQUcsR0FBRyxPQUFPLENBQUM7SUFDcEUsQ0FBQztJQUNILGdCQUFDO0FBQUQsQ0EzTEEsQUEyTEMsSUFBQTtBQTNMWSw4QkFBUyIsImZpbGUiOiJzaW11bGF0b3IuanMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogRmlyZWJhc2UgUnVsZXMgdGVzdCBzaW11bGF0b3IuXG4gKlxuICogQ29weXJpZ2h0IDIwMTUgR29vZ2xlIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKi9cbmltcG9ydCB7YXNzZXJ0fSBmcm9tICdjaGFpJztcbmltcG9ydCAqIGFzIHJlc3QgZnJvbSAnLi9maXJlYmFzZS1yZXN0JztcbmltcG9ydCAqIGFzIHV0aWwgZnJvbSAnLi91dGlsJztcbmltcG9ydCAqIGFzIGZpbGVJTyBmcm9tICcuL2ZpbGUtaW8nO1xuaW1wb3J0ICogYXMgYm9sdCBmcm9tICcuL2JvbHQnO1xuXG5sZXQgZ2VuZXJhdGUgPSB1dGlsLmxpZnQoYm9sdC5nZW5lcmF0ZSk7XG5sZXQgcmVhZEZpbGUgPSB1dGlsLmxpZnRBcmdzKGZpbGVJTy5yZWFkRmlsZSk7XG5cbnZhciBNQVhfVEVTVF9NUyA9IDYwMDAwO1xuXG5leHBvcnQgdHlwZSBTdWl0ZUZ1bmN0aW9uID0gKGZuOiBUZXN0RnVuY3Rpb24pID0+IHZvaWQ7XG5cbi8vIEludGVyZmFjZSBmb3IgJ3Rlc3QnIGZ1bmN0aW9uIHBhc3NlZCBiYWNrIHRvIHJ1bGVzU3VpdGUgY2FsbGJhY2suXG4vLyB0ZXN0IGlzIGEgZnVuY3Rpb24gYXMgd2VsbCBhcyBhIG5hbWVzcGFjZSBmb3Igc29tZSBzdGF0aWMgbWV0aG9kc1xuLy8gYW5kIGNvbnN0YW50cy5cbmV4cG9ydCBpbnRlcmZhY2UgVGVzdEZ1bmN0aW9uIHtcbiAgKG5hbWU6IHN0cmluZywgZm5UZXN0OiAocnVsZXM6IFJ1bGVzVGVzdCkgPT4gdm9pZCk6IHZvaWQ7XG4gIHJ1bGVzOiAocGF0aDogc3RyaW5nKSA9PiB2b2lkO1xuICBkYXRhYmFzZTogKGFwcE5hbWU6IHN0cmluZywgc2VjcmV0OiBzdHJpbmcpID0+IHZvaWQ7XG4gIHVpZDogKHVzZXJuYW1lOiBzdHJpbmcpID0+IHN0cmluZztcbiAgVElNRVNUQU1QOiBPYmplY3Q7XG59O1xuXG5leHBvcnQgZnVuY3Rpb24gcnVsZXNTdWl0ZShzdWl0ZU5hbWU6IHN0cmluZywgZm5TdWl0ZTogU3VpdGVGdW5jdGlvbikge1xuICBuZXcgUnVsZXNTdWl0ZShzdWl0ZU5hbWUsIGZuU3VpdGUpLnJ1bigpO1xufVxuXG5leHBvcnQgY2xhc3MgUnVsZXNTdWl0ZSB7XG4gIHB1YmxpYyAgZGVidWcgPSBmYWxzZTtcbiAgcHJpdmF0ZSB1c2VycyA9IDx7W25hbWU6IHN0cmluZ106IHJlc3QuQ2xpZW50fT57fTtcbiAgcHJpdmF0ZSB0ZXN0cyA9IDxSdWxlc1Rlc3RbXT5bXTtcbiAgcHJpdmF0ZSBydWxlc1BhdGg6IHN0cmluZztcbiAgcHJpdmF0ZSBydWxlc1BhdGhSZXNvbHZlOiAocGF0aDogc3RyaW5nKSA9PiB2b2lkO1xuICBwcml2YXRlIGRhdGFiYXNlUmVhZHk6ICgpID0+IHZvaWQ7XG4gIHByaXZhdGUgcmVhZHk6IFByb21pc2U8YW55PjtcbiAgcHJpdmF0ZSBhZG1pbkNsaWVudDogcmVzdC5DbGllbnQ7XG4gIHByaXZhdGUgYXBwTmFtZTogc3RyaW5nO1xuICBwcml2YXRlIGFwcFNlY3JldDogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKHB1YmxpYyBzdWl0ZU5hbWU6IHN0cmluZyxcbiAgICAgICAgICAgICAgcHJpdmF0ZSBmblN1aXRlOiBTdWl0ZUZ1bmN0aW9uKSB7fVxuXG4gIHNldERlYnVnKGRlYnVnID0gdHJ1ZSkge1xuICAgIHRoaXMuZGVidWcgPSBkZWJ1ZztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHJ1bigpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgICAvLyBSdW4gTW9jaGEgVGVzdCBTdWl0ZSAtIHNlcmlhbGl6ZSB3aXRoIGFueSBvdGhlciBtb2NoYSB0ZXN0IHN1aXRlcy5cbiAgICBzdWl0ZShcIkZpcmViYXNlIFJ1bGVzIFNpbXVsYXRvcjogXCIgKyBzZWxmLnN1aXRlTmFtZSwgZnVuY3Rpb24oKSB7XG4gICAgICB0aGlzLnRpbWVvdXQoTUFYX1RFU1RfTVMpO1xuICAgICAgc3VpdGVTZXR1cChmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIHJ1bGVzUGF0aCA9IG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUpIHtcbiAgICAgICAgICBzZWxmLnJ1bGVzUGF0aFJlc29sdmUgPSByZXNvbHZlO1xuICAgICAgICB9KTtcblxuICAgICAgICB2YXIgZGF0YWJhc2UgPSBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlKSB7XG4gICAgICAgICAgc2VsZi5kYXRhYmFzZVJlYWR5ID0gcmVzb2x2ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdmFyIHJ1bGVzSlNPTiA9IGdlbmVyYXRlKHV0aWwuZ2V0UHJvcChyZWFkRmlsZShydWxlc1BhdGgpLCAnY29udGVudCcpKTtcblxuICAgICAgICBzZWxmLnJlYWR5ID0gUHJvbWlzZS5hbGwoW3J1bGVzSlNPTiwgZGF0YWJhc2VdKVxuICAgICAgICAgIC50aGVuKHNlbGYub25SdWxlc1JlYWR5LmJpbmQoc2VsZikpO1xuXG4gICAgICAgIC8vIEV4ZWN1dGUgaW5pdGlhbGl6YXRpb24gYW5kIGdldCB0ZXN0IGRlZmluaXRpb25zIChpbiBjbGllbnQgY29kZSkuXG4gICAgICAgIHNlbGYuZm5TdWl0ZShzZWxmLmdldEludGVyZmFjZSgpKTtcblxuICAgICAgICByZXR1cm4gc2VsZi5yZWFkeTtcbiAgICAgIH0pO1xuXG4gICAgICB0ZXN0KFwiSW5pdGlhbGl6YXRpb24uXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAvLyBwYXNzXG4gICAgICB9KTtcblxuICAgICAgdGVzdChcIlJ1bGVzIHRlc3QuXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gc2VsZi5ydW5UZXN0cygpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICBnZXRJbnRlcmZhY2UoKSB7XG4gICAgdmFyIHRlc3QgPSB0aGlzLnRlc3QuYmluZCh0aGlzKTtcbiAgICB0ZXN0LnJ1bGVzID0gdGhpcy5ydWxlcy5iaW5kKHRoaXMpO1xuICAgIHRlc3QuZGF0YWJhc2UgPSB0aGlzLmRhdGFiYXNlLmJpbmQodGhpcyk7XG4gICAgdGVzdC51aWQgPSB0aGlzLnVpZC5iaW5kKHRoaXMpO1xuICAgIHRlc3QuVElNRVNUQU1QID0gcmVzdC5USU1FU1RBTVA7XG4gICAgcmV0dXJuIHRlc3Q7XG4gIH1cblxuICAvLyBDYWxsZWQgd2hlbiBydWxlcyBhcmUgZ2VuZXJhdGVkIGFuZCB0ZXN0IGRhdGFiYXNlIGlzIGtub3duLlxuICBvblJ1bGVzUmVhZHkocHJlcmVxOiBbT2JqZWN0LCBhbnldKSB7XG4gICAgbGV0IHJ1bGVzSlNPTiA9IHByZXJlcVswXTtcbiAgICByZXR1cm4gdGhpcy5hZG1pbkNsaWVudC5wdXQocmVzdC5SVUxFU19MT0NBVElPTiwgcnVsZXNKU09OKTtcbiAgfVxuXG4gIHJ1blRlc3RzKCkge1xuICAgIHZhciBwID0gUHJvbWlzZS5yZXNvbHZlKCk7XG5cbiAgICBmdW5jdGlvbiBuZXh0KHByZXY6IFByb21pc2U8YW55PiwgdGVzdDogUnVsZXNUZXN0KTogUHJvbWlzZTxhbnk+IHtcbiAgICAgIHJldHVybiBwcmV2LnRoZW4oZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiB0ZXN0LnJ1bigpO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnRlc3RzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBwID0gbmV4dChwLCB0aGlzLnRlc3RzW2ldKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcDtcbiAgfVxuXG4gIHRlc3QodGVzdE5hbWU6IHN0cmluZywgZm5UZXN0OiAocnVsZXM6IFJ1bGVzVGVzdCkgPT4gdm9pZCk6IHZvaWQge1xuICAgIHRoaXMudGVzdHMucHVzaChuZXcgUnVsZXNUZXN0KHRlc3ROYW1lLCB0aGlzLCBmblRlc3QpKTtcbiAgfVxuXG4gIHJ1bGVzKHJ1bGVzUGF0aDogc3RyaW5nKTogdm9pZCB7XG4gICAgaWYgKHRoaXMucnVsZXNQYXRoKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJPbmx5IGV4cGVjdCBhIHNpbmdsZSBjYWxsIHRvIHRoZSB0ZXN0LnJ1bGVzIGZ1bmN0aW9uLlwiKTtcbiAgICB9XG4gICAgdGhpcy5ydWxlc1BhdGggPSBydWxlc1BhdGg7XG4gICAgdGhpcy5ydWxlc1BhdGhSZXNvbHZlKHV0aWwuZW5zdXJlRXh0ZW5zaW9uKHJ1bGVzUGF0aCwgYm9sdC5GSUxFX0VYVEVOU0lPTikpO1xuICB9XG5cbiAgZGF0YWJhc2UoYXBwTmFtZTogc3RyaW5nLCBhcHBTZWNyZXQ6IHN0cmluZykge1xuICAgIGlmICh0aGlzLmFkbWluQ2xpZW50KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJPbmx5IGV4cGVjdCBhIHNpbmdsZSBjYWxsIHRvIHRoZSB0ZXN0LmRhdGFiYXNlIGZ1bmN0aW9uLlwiKTtcbiAgICB9XG4gICAgdGhpcy5hcHBOYW1lID0gYXBwTmFtZTtcbiAgICB0aGlzLmFwcFNlY3JldCA9IGFwcFNlY3JldDtcbiAgICB0aGlzLmFkbWluQ2xpZW50ID0gdGhpcy5lbnN1cmVVc2VyKCdhZG1pbicpO1xuICAgIHRoaXMuZGF0YWJhc2VSZWFkeSgpO1xuICB9XG5cbiAgdWlkKHVzZXJuYW1lOiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVVzZXIodXNlcm5hbWUpLnVpZDtcbiAgfVxuXG4gIGVuc3VyZVVzZXIodXNlcm5hbWU6IHN0cmluZyk6IHJlc3QuQ2xpZW50IHtcbiAgICBpZiAoISh1c2VybmFtZSBpbiB0aGlzLnVzZXJzKSkge1xuICAgICAgaWYgKHVzZXJuYW1lID09PSAnYW5vbicpIHtcbiAgICAgICAgdGhpcy51c2Vyc1t1c2VybmFtZV0gPSBuZXcgcmVzdC5DbGllbnQodGhpcy5hcHBOYW1lKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxldCB0b2tlbkluZm8gPSByZXN0LmdlbmVyYXRlVWlkQXV0aFRva2VuKFxuICAgICAgICAgIHRoaXMuYXBwU2VjcmV0LFxuICAgICAgICAgIHsgZGVidWc6IHRydWUsXG4gICAgICAgICAgICBhZG1pbjogdXNlcm5hbWUgPT09ICdhZG1pbicgfSk7XG4gICAgICAgIHRoaXMudXNlcnNbdXNlcm5hbWVdID0gbmV3IHJlc3QuQ2xpZW50KHRoaXMuYXBwTmFtZSwgdG9rZW5JbmZvLnRva2VuLCB0b2tlbkluZm8udWlkKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy51c2Vyc1t1c2VybmFtZV07XG4gIH1cbn1cblxuaW50ZXJmYWNlIFN0ZXAge1xuICBsYWJlbDogc3RyaW5nO1xuICBmbjogKCkgPT4gUHJvbWlzZTxhbnk+O1xufVxuXG5leHBvcnQgY2xhc3MgUnVsZXNUZXN0IHtcbiAgcHJpdmF0ZSBsYXN0RXJyb3I6IHN0cmluZztcbiAgcHJpdmF0ZSBzdGVwczogU3RlcFtdID0gW107XG4gIHByaXZhdGUgZmFpbGVkID0gZmFsc2U7XG4gIHByaXZhdGUgcGF0aDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIGNsaWVudDogcmVzdC5DbGllbnQ7XG4gIHByaXZhdGUgc3RhdHVzOiBib29sZWFuIHwgdW5kZWZpbmVkO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgdGVzdE5hbWU6IHN0cmluZyxcbiAgICAgICAgICAgICAgcHJpdmF0ZSBzdWl0ZTogUnVsZXNTdWl0ZSxcbiAgICAgICAgICAgICAgcHJpdmF0ZSBmblRlc3Q6IChydWxlczogUnVsZXNUZXN0KSA9PiB2b2lkKSB7fVxuXG4gIHJ1bigpIHtcbiAgICB0aGlzLmRlYnVnKGZhbHNlKTtcbiAgICB0aGlzLmFzKCdhZG1pbicpO1xuICAgIHRoaXMuYXQoJy8nKTtcbiAgICB0aGlzLndyaXRlKG51bGwpO1xuICAgIHRoaXMuc3VjY2VlZHMoXCJpbml0aWFsaXphdGlvblwiKTtcblxuICAgIHRoaXMuYXQodW5kZWZpbmVkKTtcbiAgICB0aGlzLmFzKCdhbm9uJyk7XG5cbiAgICB0aGlzLmZuVGVzdCh0aGlzKTtcblxuICAgIHRoaXMuZGVidWcoZmFsc2UpO1xuXG4gICAgcmV0dXJuIHRoaXMuZXhlY3V0ZVF1ZXVlKClcbiAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgdGhpcy5sb2coXCJGaW5pc2hlZFwiKTtcbiAgICAgIH0pXG4gICAgICAuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgICAgIHRoaXMubG9nKFwiRmFpbGVkOiBcIiArIGVycm9yKTtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9KTtcbiAgfVxuXG4gIC8vIFF1ZXVlIGEgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIGluIHNlcXVlbmNlIGFmdGVyIHByZXZpb3VzIHN0ZXBcbiAgLy8gaW4gdGVzdCBpcyAoc3VjY2Vzc2Z1bGx5KSBjb21wbGV0ZWQuXG4gIHF1ZXVlKG9wOiBzdHJpbmcsIGFyZ3M6IEFycmF5TGlrZTxhbnk+LCBmbjogKCkgPT4gUHJvbWlzZTxhbnk+KSB7XG4gICAgaWYgKHRoaXMuZmFpbGVkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGxldCBhcmdzVCA9IHV0aWwuY29weUFycmF5KGFyZ3MpLm1hcChmdW5jdGlvbih4KSB7XG4gICAgICByZXR1cm4gdXRpbC5wcmV0dHlKU09OKHgpO1xuICAgIH0pO1xuICAgIHZhciBsYWJlbCA9IG9wICsgJygnICsgYXJnc1Quam9pbignLCAnKSArICcpJztcbiAgICB0aGlzLnN0ZXBzLnB1c2goe2xhYmVsOiBsYWJlbCwgZm46IGZufSk7XG4gIH1cblxuICBleGVjdXRlUXVldWUoKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgdGhpcy5sb2coXCJFeGVjdXRpbmcgKFwiICsgdGhpcy5zdGVwcy5sZW5ndGggKyBcIiBzdGVwcylcIik7XG4gICAgdmFyIHAgPSBQcm9taXNlLnJlc29sdmUodHJ1ZSk7XG5cbiAgICBmdW5jdGlvbiBuZXh0KHByZXY6IFByb21pc2U8YW55Piwgc3RlcDogU3RlcCk6IFByb21pc2U8YW55PiB7XG4gICAgICByZXR1cm4gcHJldi50aGVuKGZ1bmN0aW9uKCkge1xuICAgICAgICBzZWxmLmxvZyhzdGVwLmxhYmVsKTtcbiAgICAgICAgcmV0dXJuIHN0ZXAuZm4oKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5zdGVwcy5sZW5ndGg7IGkrKykge1xuICAgICAgcCA9IG5leHQocCwgdGhpcy5zdGVwc1tpXSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHA7XG4gIH1cblxuICBkZWJ1ZyhkZWJ1Zz86IGJvb2xlYW4pOiBSdWxlc1Rlc3Qge1xuICAgIHRoaXMuc3VpdGUuc2V0RGVidWcoZGVidWcpO1xuICAgIHRoaXMucXVldWUoJ2RlYnVnJywgYXJndW1lbnRzLCAoKSA9PiB7XG4gICAgICB0aGlzLnN1aXRlLnNldERlYnVnKGRlYnVnKTtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGFzKHVzZXJuYW1lOiBzdHJpbmcpOiBSdWxlc1Rlc3Qge1xuICAgIHZhciBjbGllbnQgPSB0aGlzLnN1aXRlLmVuc3VyZVVzZXIodXNlcm5hbWUpO1xuICAgIHRoaXMucXVldWUoJ2FzJywgYXJndW1lbnRzLCAoKSA9PiB7XG4gICAgICBjbGllbnQuc2V0RGVidWcodGhpcy5zdWl0ZS5kZWJ1Zyk7XG4gICAgICB0aGlzLmNsaWVudCA9IGNsaWVudDtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGF0KG9wUGF0aDogc3RyaW5nIHwgdW5kZWZpbmVkKTogUnVsZXNUZXN0IHtcbiAgICB0aGlzLnF1ZXVlKCdhdCcsIGFyZ3VtZW50cywgKCkgPT4ge1xuICAgICAgdGhpcy5wYXRoID0gb3BQYXRoO1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgIH0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgd3JpdGUob2JqOiBhbnkpOiBSdWxlc1Rlc3Qge1xuICAgIHRoaXMucXVldWUoJ3dyaXRlJywgYXJndW1lbnRzLCAoKSA9PiB7XG4gICAgICBpZiAodGhpcy5wYXRoID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KG5ldyBFcnJvcihcIlVzZSBhdCgpIGZ1bmN0aW9uIHRvIHNldCBwYXRoIHRvIHdyaXRlLlwiKSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gdGhpcy5jbGllbnQucHV0KHRoaXMucGF0aCwgb2JqKVxuICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgdGhpcy5zdGF0dXMgPSB0cnVlO1xuICAgICAgICB9KVxuICAgICAgICAuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgICAgICAgdGhpcy5zdGF0dXMgPSBmYWxzZTtcbiAgICAgICAgICB0aGlzLmxhc3RFcnJvciA9IGVycm9yO1xuICAgICAgICB9KTtcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHB1c2gob2JqOiBhbnkpOiBSdWxlc1Rlc3Qge1xuICAgIHRoaXMucXVldWUoJ3dyaXRlJywgYXJndW1lbnRzLCAoKSA9PiB7XG4gICAgICBpZiAodGhpcy5wYXRoID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KG5ldyBFcnJvcihcIlVzZSBhdCgpIGZ1bmN0aW9uIHRvIHNldCBwYXRoIHRvIHB1c2guXCIpKTtcbiAgICAgIH1cbiAgICAgIGxldCBwYXRoID0gdGhpcy5wYXRoO1xuICAgICAgaWYgKHBhdGguc2xpY2UoLTEpWzBdICE9PSAnLycpIHtcbiAgICAgICAgcGF0aCArPSAnLyc7XG4gICAgICB9XG4gICAgICBwYXRoICs9IHJlc3QuZ2VuZXJhdGVQdXNoSUQoKTtcbiAgICAgIHJldHVybiB0aGlzLmNsaWVudC5wdXQocGF0aCwgb2JqKVxuICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgdGhpcy5zdGF0dXMgPSB0cnVlO1xuICAgICAgICB9KVxuICAgICAgICAuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgICAgICAgdGhpcy5zdGF0dXMgPSBmYWxzZTtcbiAgICAgICAgICB0aGlzLmxhc3RFcnJvciA9IGVycm9yO1xuICAgICAgICB9KTtcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHJlYWQoKTogUnVsZXNUZXN0IHtcbiAgICB0aGlzLnF1ZXVlKCdyZWFkJywgYXJndW1lbnRzLCAoKSA9PiB7XG4gICAgICBpZiAodGhpcy5wYXRoID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KG5ldyBFcnJvcihcIlVzZSBhdCgpIGZ1bmN0aW9uIHRvIHNldCBwYXRoIHRvIHJlYWQuXCIpKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzLmNsaWVudC5nZXQodGhpcy5wYXRoKVxuICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgdGhpcy5zdGF0dXMgPSB0cnVlO1xuICAgICAgICB9KVxuICAgICAgICAuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgICAgICAgdGhpcy5zdGF0dXMgPSBmYWxzZTtcbiAgICAgICAgICB0aGlzLmxhc3RFcnJvciA9IGVycm9yO1xuICAgICAgICB9KTtcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHN1Y2NlZWRzKG1lc3NhZ2U6IHN0cmluZyk6IFJ1bGVzVGVzdCB7XG4gICAgdGhpcy5xdWV1ZSgnc3VjY2VlZHMnLCBhcmd1bWVudHMsICgpID0+IHtcbiAgICAgIGFzc2VydCh0aGlzLnN0YXR1cyA9PT0gdHJ1ZSxcbiAgICAgICAgICAgICB0aGlzLm1lc3NhZ2VGb3JtYXQobWVzc2FnZSArIFwiIChzaG91bGQgaGF2ZSBzdWNjZWVkKVxcblwiICsgdGhpcy5sYXN0RXJyb3IpKTtcbiAgICAgIHRoaXMuZ29vZChtZXNzYWdlKTtcbiAgICAgIHRoaXMuc3RhdHVzID0gdW5kZWZpbmVkO1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgIH0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZmFpbHMobWVzc2FnZTogc3RyaW5nKTogUnVsZXNUZXN0IHtcbiAgICB0aGlzLnF1ZXVlKCdmYWlscycsIGFyZ3VtZW50cywgKCkgPT4ge1xuICAgICAgYXNzZXJ0KHRoaXMuc3RhdHVzID09PSBmYWxzZSxcbiAgICAgICAgICAgICB0aGlzLm1lc3NhZ2VGb3JtYXQobWVzc2FnZSArIFwiIChzaG91bGQgaGF2ZSBmYWlsZWQpXCIpKTtcbiAgICAgIHRoaXMuZ29vZChtZXNzYWdlKTtcbiAgICAgIHRoaXMuc3RhdHVzID0gdW5kZWZpbmVkO1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgIH0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgcHJpdmF0ZSBnb29kKG1lc3NhZ2U6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMubG9nKG1lc3NhZ2UgKyBcIiAoQ29ycmVjdClcIik7XG4gIH1cblxuICBwcml2YXRlIGxvZyhtZXNzYWdlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5zdWl0ZS5kZWJ1Zykge1xuICAgICAgY29uc29sZS5sb2codGhpcy5tZXNzYWdlRm9ybWF0KG1lc3NhZ2UpKTtcbiAgICB9XG4gIH1cblxuICBtZXNzYWdlRm9ybWF0KG1lc3NhZ2U6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuc3VpdGUuc3VpdGVOYW1lICsgXCIuXCIgKyB0aGlzLnRlc3ROYW1lICsgXCIgXCIgKyBtZXNzYWdlO1xuICB9XG59XG4iXX0=