diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..967a087a --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +dist/* binary \ No newline at end of file diff --git a/.gitignore b/.gitignore index fa5e5267..e6a257b2 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ pids !.bowerrc !.gitignore !.jscsrc +!.gitattributes # sass .sass-cache/ @@ -49,3 +50,5 @@ dist/epicenter-edge-instrumented.js coverage/ .DS_Store **/.DS_Store + +*.orig diff --git a/bower.json b/bower.json index c6028c03..24e2773d 100644 --- a/bower.json +++ b/bower.json @@ -16,7 +16,7 @@ "tests" ], "dependencies": { - "jquery": "~2.1.1", + "jquery": "~3.1.0", "cometd-jquery": "2.9.0" }, "devDependencies": {} diff --git a/dist/components/assignment/assignment.js b/dist/components/assignment/assignment.js index ddf61fed..3ca45965 100644 --- a/dist/components/assignment/assignment.js +++ b/dist/components/assignment/assignment.js @@ -176,7 +176,7 @@ Assignment.prototype = { this._showUpdating(); var maxUsers = +this.$('#max-users').val(); return this.worlds.autoAssignAll({ maxUsers: maxUsers }) - .done(this._hideUpdating) + .then(this._hideUpdating) .fail(this._hideUpdating) .then(function () { this.worlds.joinUsers(); @@ -850,7 +850,7 @@ module.exports = classFrom(Base, { .then(function (users) { users = _.map(users, function (u) { return _.extend(u, { groupId: groupId }); }); _this.set(users); - dtd.resolve(users, _this); + dtd.resolve(users); }); return dtd.promise(); @@ -1231,4 +1231,4 @@ module.exports = function (base, props, staticProps) { }; },{}]},{},[6]) -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2Fzc2lnbm1lbnQtcm93LmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9hc3NpZ25tZW50LmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9iYXNlLWNvbGxlY3Rpb24uanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2Jhc2UtbW9kZWwuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2RlZmF1bHRzLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9pbmRleC5qcyIsInNyYy9jb21wb25lbnRzL2Fzc2lnbm1lbnQvanMvcHJvamVjdC1tb2RlbC5qcyIsInNyYy9jb21wb25lbnRzL2Fzc2lnbm1lbnQvanMvc2VydmljZS1sb2NhdG9yLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy90ZW1wbGF0ZXMuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3VzZXItbW9kZWwuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3VzZXJzLWNvbGxlY3Rpb24uanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3dvcmxkLW1vZGVsLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy93b3JsZHMtY29sbGVjdGlvbi5qcyIsInNyYy91dGlsL2FqYXgtcXVldWUuanMiLCJzcmMvdXRpbC9pbmhlcml0LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25IQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1BBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIndXNlIHN0cmljdCc7XG5cbnZhciB0ZW1wbGF0ZXMgPSByZXF1aXJlKCcuL3RlbXBsYXRlcycpO1xuXG52YXIgQXNzaWdubWVudFJvdyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdGhpcy4kZWwgPSAkKCc8dHI+Jyk7XG4gICAgdGhpcy5lbCA9IHRoaXMuJGVsWzBdO1xuICAgIHRoaXMuJCA9IF8ucGFydGlhbFJpZ2h0KCQsIHRoaXMuJGVsKTtcblxuICAgIHRoaXMubW9kZWwgPSBvcHRpb25zLm1vZGVsO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy53b3JsZHMgPSBvcHRpb25zLndvcmxkcztcbiAgICB0aGlzLnByb2plY3QgPSBvcHRpb25zLnByb2plY3Q7XG5cbiAgICBfLmJpbmRBbGwodGhpcywgWydzZXRFZGl0TW9kZScsICdyZW1vdmVFZGl0TW9kZScsICdzYXZlRWRpdCcsICdjYW5jZWxFZGl0JywgJ3VwZGF0ZURhdGEnXSk7XG5cbiAgICB0aGlzLmJpbmRFdmVudHMoKTtcblxufTtcblxuXy5leHRlbmQoQXNzaWdubWVudFJvdy5wcm90b3R5cGUsIHtcblxuICAgIHRlbXBsYXRlOiB0ZW1wbGF0ZXNbJ3VzZXItcm93J10sXG5cbiAgICBlZGl0VGVtcGxhdGU6IHRlbXBsYXRlc1snZWRpdC11c2VyLXJvdyddLFxuXG4gICAgYmluZEV2ZW50czogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiRlbC5vbignY2xpY2snLCAnYnV0dG9uLmVkaXQnLCB0aGlzLnNldEVkaXRNb2RlKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJ2J1dHRvbi5zYXZlJywgdGhpcy5zYXZlRWRpdCk7XG4gICAgICAgIHRoaXMuJGVsLm9uKCdjbGljaycsICdidXR0b24uY2FuY2VsJywgdGhpcy5jYW5jZWxFZGl0KTtcbiAgICB9LFxuXG4gICAgcmVtb3ZlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLm9mZignY2xpY2snLCBudWxsLCBudWxsKTtcbiAgICAgICAgLy8gdGhpcyBvbmx5IGdpdmVzIGEgZGVsYXkgdG8gcmVtb3ZlIHRoZSB0clxuICAgICAgICAvLyBhbmltYXRpb24gb2YgaGVpZ2h0IG9mIHRoZSB0ciBkb2VzIG5vdCB3b3JrXG4gICAgICAgIHRoaXMuJCgnOmNoZWNrYm94JykuYXR0cignY2hlY2tlZCcsIGZhbHNlKTtcbiAgICAgICAgdGhpcy4kZWxcbiAgICAgICAgICAgIC5jc3MoeyBvcGFjaXR5OiAwLjMgfSlcbiAgICAgICAgICAgIC5hbmltYXRlKHsgaGVpZ2h0OiAwIH0sIHtcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogMzAwLFxuICAgICAgICAgICAgICAgIGNvbXBsZXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIG1ha2VJbmFjdGl2ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tb2RlbC5tYWtlSW5hY3RpdmUoKTtcbiAgICB9LFxuXG4gICAgc2V0RWRpdE1vZGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5tb2RlbC5zZXQoJ2VkaXQtbW9kZScsIHRydWUpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0sXG5cbiAgICByZW1vdmVFZGl0TW9kZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLm1vZGVsLnNldCgnZWRpdC1tb2RlJywgZmFsc2UpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0sXG5cbiAgICBzYXZlRWRpdDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB0aGlzLnVwZGF0ZURhdGEoKTtcbiAgICAgICAgdGhpcy53b3JsZHNcbiAgICAgICAgICAgIC51cGRhdGVVc2VyKHRoaXMubW9kZWwpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgX3RoaXMucmVtb3ZlRWRpdE1vZGUoKTtcbiAgICAgICAgICAgICAgICBfdGhpcy4kZWwudHJpZ2dlcigndXBkYXRlJywgX3RoaXMpO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGNhbmNlbEVkaXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5yZW1vdmVFZGl0TW9kZSgpO1xuICAgIH0sXG5cbiAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHRlbXBsID0gdGhpcy5tb2RlbC5nZXQoJ2VkaXQtbW9kZScpID8gdGhpcy5lZGl0VGVtcGxhdGUgOiB0aGlzLnRlbXBsYXRlO1xuICAgICAgICB2YXIgdm0gPSBfLmV4dGVuZCh7XG4gICAgICAgICAgICByb2xlczogdGhpcy5wcm9qZWN0LmdldCgncm9sZXMnKSxcbiAgICAgICAgICAgIG9wdGlvbmFsUm9sZXM6IHRoaXMucHJvamVjdC5nZXQoJ29wdGlvbmFsUm9sZXMnKSxcbiAgICAgICAgICAgIHdvcmxkczogdGhpcy53b3JsZHMuZ2V0V29ybGROYW1lcygpLFxuICAgICAgICAgICAgbmV3V29ybGQ6IHRoaXMud29ybGRzLmdldE5leHRXb3JsZE5hbWUoKVxuICAgICAgICB9LCB0aGlzLm1vZGVsLnRvSlNPTigpKTtcblxuICAgICAgICB0aGlzLiRlbC5odG1sKHRlbXBsKHZtKSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIHVwZGF0ZURhdGE6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdGhpcy4kKCdbZGF0YS1maWVsZF0nKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBlbCA9ICQodGhpcyk7XG4gICAgICAgICAgICB2YXIgZmllbGQgPSBlbC5kYXRhKCdmaWVsZCcpO1xuICAgICAgICAgICAgdmFyIHZhbCA9IGVsLnZhbCgpO1xuXG4gICAgICAgICAgICBfdGhpcy5tb2RlbC5zZXQoZmllbGQsIHZhbCk7XG4gICAgICAgIH0pO1xuICAgIH1cbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQXNzaWdubWVudFJvdzsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBVc2Vyc0NvbGxlY3Rpb24gPSByZXF1aXJlKCcuL3VzZXJzLWNvbGxlY3Rpb24nKTtcbnZhciBXb3JsZHNDb2xsZWN0aW9uID0gcmVxdWlyZSgnLi93b3JsZHMtY29sbGVjdGlvbicpO1xudmFyIFByb2plY3RNb2RlbCA9IHJlcXVpcmUoJy4vcHJvamVjdC1tb2RlbCcpO1xudmFyIEFzc2lnbmVtbnRSb3cgPSByZXF1aXJlKCcuL2Fzc2lnbm1lbnQtcm93Jyk7XG52YXIgZW52ID0gcmVxdWlyZSgnLi9kZWZhdWx0cycpO1xudmFyIEFqYXhRdWV1ZSA9IHJlcXVpcmUoJy4uLy4uLy4uL3V0aWwvYWpheC1xdWV1ZScpO1xuXG5mdW5jdGlvbiBzZXRFbnZpcm9ubWVudChvcHRpb25zKSB7XG4gICAgZW52LnNldChfLm9taXQob3B0aW9ucywgJ2VsJykpO1xufVxuXG52YXIgQXNzaWdubWVudCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgc2V0RW52aXJvbm1lbnQob3B0aW9ucyk7XG4gICAgdGhpcy5pbml0aWFsaXplKG9wdGlvbnMpO1xufTtcblxuQXNzaWdubWVudC5wcm90b3R5cGUgPSB7XG5cbiAgICBpbml0aWFsaXplOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB0aGlzLmVsID0gdHlwZW9mIG9wdGlvbnMuZWwgPT09ICdzdHJpbmcnID8gJChvcHRpb25zLmVsKVswXSA6IG9wdGlvbnMuZWw7XG4gICAgICAgIHRoaXMuJGVsID0gJCh0aGlzLmVsKTtcbiAgICAgICAgdGhpcy4kID0gXy5wYXJ0aWFsUmlnaHQoJCwgdGhpcy5lbCk7XG5cbiAgICAgICAgdGhpcy51c2VycyA9IG5ldyBVc2Vyc0NvbGxlY3Rpb24oKTtcbiAgICAgICAgdGhpcy53b3JsZHMgPSBuZXcgV29ybGRzQ29sbGVjdGlvbigpO1xuICAgICAgICB0aGlzLnByb2plY3QgPSBuZXcgUHJvamVjdE1vZGVsKCk7XG5cbiAgICAgICAgXy5iaW5kQWxsKHRoaXMsIFsncmVuZGVyJywgJ3JlbmRlclRhYmxlJywgJ3RvZ2dsZUNvbnRyb2xscycsICdzYXZlRWRpdCcsICdzZWxlY3RBbGwnLCAndXNhc3NpZ25TZWxlY3RlZCcsICdfc2hvd1VwZGF0aW5nJywgJ19oaWRlVXBkYXRpbmcnLCAnYXV0b0Fzc2lnbkFsbCcsICdtYWtlVXNlckluYWN0aXZlJ10pO1xuXG4gICAgICAgIHRoaXMuYmluZEV2ZW50cygpO1xuICAgIH0sXG5cbiAgICBiaW5kRXZlbnRzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLm9uKCd1cGRhdGUnLCAndHInLCB0aGlzLnNhdmVFZGl0KTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJ2lucHV0OmNoZWNrYm94Om5vdCgjc2VsZWN0LWFsbCknLCB0aGlzLnRvZ2dsZUNvbnRyb2xscyk7XG4gICAgICAgIHRoaXMuJGVsLm9uKCdjbGljaycsICcjc2VsZWN0LWFsbCcsIHRoaXMuc2VsZWN0QWxsKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJy51bmFzc2lnbi11c2VyJywgdGhpcy51c2Fzc2lnblNlbGVjdGVkKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJy5hdXRvLWFzc2lnbi1hbGwnLCB0aGlzLmF1dG9Bc3NpZ25BbGwpO1xuICAgICAgICB0aGlzLiRlbC5vbignY2xpY2snLCAnLm1ha2UtdXNlci1pbmFjdGl2ZScsIHRoaXMubWFrZVVzZXJJbmFjdGl2ZSk7XG4gICAgfSxcblxuICAgIGxvYWQ6IGZ1bmN0aW9uICgpIHtcblxuICAgICAgICB2YXIgam9pbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHRoaXMud29ybGRzLnNldFVzZXJzQ29sbGVjdGlvbih0aGlzLnVzZXJzKTtcbiAgICAgICAgICAgIHRoaXMud29ybGRzLmpvaW5Vc2VycygpO1xuICAgICAgICAgICAgdGhpcy5yZW5kZXIoKTtcbiAgICAgICAgfS5iaW5kKHRoaXMpO1xuXG4gICAgICAgIHJldHVybiAkLndoZW4oXG4gICAgICAgICAgICB0aGlzLndvcmxkcy5mZXRjaCgpLFxuICAgICAgICAgICAgdGhpcy51c2Vycy5mZXRjaCgpLFxuICAgICAgICAgICAgdGhpcy5wcm9qZWN0LmZldGNoKClcbiAgICAgICAgKS50aGVuKGpvaW4pO1xuXG4gICAgfSxcblxuICAgIHNhdmVFZGl0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMud29ybGRzLmZldGNoKClcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlQ29udHJvbHMoKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGF1dG9Bc3NpZ25BbGw6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5fc2hvd1VwZGF0aW5nKCk7XG4gICAgICAgIHZhciBtYXhVc2VycyA9ICt0aGlzLiQoJyNtYXgtdXNlcnMnKS52YWwoKTtcbiAgICAgICAgcmV0dXJuIHRoaXMud29ybGRzLmF1dG9Bc3NpZ25BbGwoeyBtYXhVc2VyczogbWF4VXNlcnMgfSlcbiAgICAgICAgICAgIC5kb25lKHRoaXMuX2hpZGVVcGRhdGluZylcbiAgICAgICAgICAgIC5mYWlsKHRoaXMuX2hpZGVVcGRhdGluZylcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICB9LFxuXG4gICAgZ2V0U2VsZWN0ZWRJZHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuJCgndGJvZHkgOmNoZWNrYm94OmNoZWNrZWQnKS5tYXAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuICQodGhpcykuZGF0YSgnaWQnKTtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGZpbmRSb3dWaWV3czogZnVuY3Rpb24gKGlkcykge1xuICAgICAgICByZXR1cm4gXy5tYXAoaWRzLCBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJvd1ZpZXdzW2lkXTtcbiAgICAgICAgfSwgdGhpcyk7XG4gICAgfSxcblxuICAgIHVuYXNzaWduVXNlcnM6IGZ1bmN0aW9uIChpZHMpIHtcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIGRvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIGZvciBub3cgd2UgbmVlZCB0byBzZXF1ZW5jZSB0aGUgY2FsbHMgdG8gdW5hc3NpZ24gdXNlcnMgZnJvbSB3b3JsZHNcbiAgICAgICAgdmFyIHF1ZXVlID0gbmV3IEFqYXhRdWV1ZSgpO1xuXG4gICAgICAgIF8uZWFjaChpZHMsIGZ1bmN0aW9uICh1c2VySWQpIHtcbiAgICAgICAgICAgIHZhciB1c2VyID0gdGhpcy51c2Vycy5nZXRCeUlkKHVzZXJJZCk7XG4gICAgICAgICAgICB1c2VyLnNldCgnd29ybGQnLCAnJyk7XG4gICAgICAgICAgICB1c2VyLnNldCgncm9sZScsICcnKTtcbiAgICAgICAgICAgIHF1ZXVlLmFkZChfLnBhcnRpYWwoXy5iaW5kKHRoaXMud29ybGRzLnVwZGF0ZVVzZXIsIHRoaXMud29ybGRzKSwgdXNlcikpO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICBxdWV1ZS5leGVjdXRlKHRoaXMpLnRoZW4oZG9uZSk7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIHVzYXNzaWduU2VsZWN0ZWQ6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgICB2YXIgaWRzID0gdGhpcy5nZXRTZWxlY3RlZElkcygpO1xuXG4gICAgICAgIHZhciBkb25lID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdGhpcy53b3JsZHMuZmV0Y2goKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9oaWRlVXBkYXRpbmcoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuXG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdGhpcy5fc2hvd1VwZGF0aW5nKCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMudW5hc3NpZ25Vc2VycyhpZHMpLnRoZW4oZG9uZSk7XG4gICAgfSxcblxuICAgIG1ha2VVc2VySW5hY3RpdmU6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgdmFyIGlkcyA9IHRoaXMuZ2V0U2VsZWN0ZWRJZHMoKTtcbiAgICAgICAgdmFyIGRvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2xscygpO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdmFyIG1ha2VVc2Vyc0luYWN0aXZlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJvd3MgPSB0aGlzLmZpbmRSb3dWaWV3cyhpZHMpO1xuICAgICAgICAgICAgLy8gZm9yIG5vdyB3ZSBuZWVkIHRvIHNlcXVlbmNlIHRoZSBjYWxscyB0byBwYXRjaCB0aGUgdXNlcnNcbiAgICAgICAgICAgIC8vIHNpbmNlIHRoZSBBUEkgY2FuIG9ubHkgb3BlcmF0ZSBvbiBvbmUgY2FsbCBwZXIgZ3JvdXAgYXQgYSB0aW1lXG4gICAgICAgICAgICB2YXIgcXVldWUgPSBuZXcgQWpheFF1ZXVlKCk7XG4gICAgICAgICAgICBfLmVhY2gocm93cywgZnVuY3Rpb24gKHZpZXcpIHtcbiAgICAgICAgICAgICAgICB2YXIgdXNlciA9IHZpZXcubW9kZWw7XG4gICAgICAgICAgICAgICAgcXVldWUuYWRkKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHZpZXcubWFrZUluYWN0aXZlKClcbiAgICAgICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VyLnJlbW92ZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZXcucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgICAgICBxdWV1ZS5leGVjdXRlKHRoaXMpLnRoZW4oZG9uZSk7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gdGhpcy51bmFzc2lnblVzZXJzKGlkcylcbiAgICAgICAgICAgIC50aGVuKG1ha2VVc2Vyc0luYWN0aXZlKTtcblxuXG4gICAgfSxcblxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiQoJ3RhYmxlIHRib2R5JykuZW1wdHkoKTtcbiAgICAgICAgdGhpcy5yZW5kZXJUYWJsZSgpO1xuICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2xscygpO1xuICAgIH0sXG5cbiAgICByZW5kZXJUYWJsZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLnJvd1ZpZXdzID0ge307XG4gICAgICAgIHZhciByb3dzID0gW107XG4gICAgICAgIHRoaXMudXNlcnMuZWFjaChmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgdmFyIHZpZXcgPSBuZXcgQXNzaWduZW1udFJvdyh7IG1vZGVsOiB1LCB3b3JsZHM6IHRoaXMud29ybGRzLCBwcm9qZWN0OiB0aGlzLnByb2plY3QgfSk7XG4gICAgICAgICAgICB0aGlzLnJvd1ZpZXdzW3UuZ2V0KCdpZCcpXSA9IHZpZXc7XG4gICAgICAgICAgICByb3dzLnB1c2godmlldy5yZW5kZXIoKS5lbCk7XG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHRoaXMuJCgndGFibGUgdGJvZHknKS5hcHBlbmQocm93cyk7XG4gICAgfSxcblxuXG4gICAgdXBkYXRlQ29udHJvbHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9sc0ZvclNlbGVjdGlvbigpO1xuICAgICAgICB0aGlzLnVwZGF0ZUF1dG9Bc3NpZ25CdXR0b24oKTtcbiAgICAgICAgdGhpcy51cGRhdGVTdGF0dXMoKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlU3RhdHVzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBpbmNvbHBsZXRlV29ybGRzID0gdGhpcy53b3JsZHMuZ2V0SW5jb21wbGV0ZVdvcmxkc0NvdW50KCk7XG4gICAgICAgIHZhciB1bmFzc2lnbmVkVXNlcnMgPSB0aGlzLnVzZXJzLmdldFVuYXNzaWduZWRVc2Vyc0NvdW50KCk7XG4gICAgICAgIHZhciB0b3RhbFdvcmxkcyA9IHRoaXMud29ybGRzLnNpemUoKTtcblxuICAgICAgICB2YXIgdXNlcnNUZXh0ID0gdW5hc3NpZ25lZFVzZXJzID8gdW5hc3NpZ25lZFVzZXJzID09PSAxID8gJzEgdXNlciBuZWVkcyBhc3NpZ25tZW50LicgOiB1bmFzc2lnbmVkVXNlcnMgKyAnIHVzZXJzIG5lZWQgYXNzaWdubWVudC4nIDogJ0FsbCB1c2VycyBoYXZlIGJlZW4gYXNzaWduZWQuJztcbiAgICAgICAgdmFyIHdvcmxkc1RleHQgPSAhdG90YWxXb3JsZHMgPyAnTm8gd29ybGRzIGhhdmUgYmVlbiBjcmVhdGVkLicgOiAhaW5jb2xwbGV0ZVdvcmxkcyA/ICdBbGwgd29ybGRzIGFyZSBjb21wbGV0ZS4nIDogaW5jb2xwbGV0ZVdvcmxkcyA9PT0gMSA/ICcxIGluY29tcGxldGUgd29ybGQgbmVlZHMgYXR0ZW50aW9uLicgOiBpbmNvbHBsZXRlV29ybGRzICsgJyBpbmNvbXBsZXRlIHdvcmxkcyBuZWVkIGF0dGVudGlvbi4nO1xuXG4gICAgICAgIHRoaXMuJCgnI3VzZXJzLXN0YXR1cyAudGV4dCcpLnRleHQodXNlcnNUZXh0KTtcbiAgICAgICAgdGhpcy4kKCcjd29ybGRzLXN0YXR1cyAudGV4dCcpLnRleHQod29ybGRzVGV4dCk7XG5cbiAgICAgICAgaWYgKHVuYXNzaWduZWRVc2Vycykge1xuICAgICAgICAgICAgdGhpcy4kKCcjdXNlcnMtc3RhdHVzJykuYWRkQ2xhc3MoJ2luY29tcGxldGUnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuJCgnI3VzZXJzLXN0YXR1cycpLnJlbW92ZUNsYXNzKCdpbmNvbXBsZXRlJyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaW5jb2xwbGV0ZVdvcmxkcyB8fCAhdG90YWxXb3JsZHMpIHtcbiAgICAgICAgICAgIHRoaXMuJCgnI3dvcmxkcy1zdGF0dXMnKS5hZGRDbGFzcygnaW5jb21wbGV0ZScpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy4kKCcjd29ybGRzLXN0YXR1cycpLnJlbW92ZUNsYXNzKCdpbmNvbXBsZXRlJyk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLiQoJy5zdGF0dXMtd2lkZ2V0JykuYWRkQ2xhc3MoJ3Zpc2libGUnKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlQ29udHJvbHNGb3JTZWxlY3Rpb246IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG51bVNlbGVjdGVkID0gdGhpcy4kKCd0Ym9keSA6Y2hlY2tib3g6Y2hlY2tlZCcpLmxlbmd0aDtcbiAgICAgICAgdGhpcy4kKCcuY29tcG9uZW50LmNvbnRyb2xzJylbbnVtU2VsZWN0ZWQgPyAnYWRkQ2xhc3MnIDogJ3JlbW92ZUNsYXNzJ10oJ3Zpc2libGUnKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlQXV0b0Fzc2lnbkJ1dHRvbjogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgIGlmICh0aGlzLnByb2plY3QuaXNEeW5hbWljQXNzaWdubWVudCgpKSB7XG4gICAgICAgICAgICB2YXIgaGFzUm9sZXMgPSB0aGlzLnByb2plY3QuaGFzUm9sZXMoKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5zaW5nbGUnKS5oaWRlKCk7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scyAuZHluYW1pYycpLnNob3coKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5keW5hbWljLW5vLXJvbGVzLXRleHQnKVtoYXNSb2xlcyA/ICdoaWRlJyA6ICdzaG93J10oKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5uby1yb2xlcycpW2hhc1JvbGVzID8gJ2hpZGUnIDogJ3Nob3cnXSgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy4kKCcudGFibGUtY29udHJvbHMgLmR5bmFtaWMnKS5oaWRlKCk7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scyAuZHluYW1pYy1uby1yb2xlcy10ZXh0JykuaGlkZSgpO1xuICAgICAgICAgICAgdGhpcy4kKCcudGFibGUtY29udHJvbHMgLnNpbmdsZScpLnNob3coKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5uby1yb2xlcycpLnNob3coKTtcblxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMudXNlcnMuYWxsVXNlcnNBc3NpZ25lZCgpKSB7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scycpLnJlbW92ZUNsYXNzKCd2aXNpYmxlJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scycpLmFkZENsYXNzKCd2aXNpYmxlJyk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgc2VsZWN0QWxsOiBmdW5jdGlvbiAoZSkge1xuICAgICAgICB0aGlzLiQoJ3Rib2R5IDpjaGVja2JveCcpLnByb3AoJ2NoZWNrZWQnLCBlLnRhcmdldC5jaGVja2VkKTtcbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9scygpO1xuICAgIH0sXG5cbiAgICB0b2dnbGVDb250cm9sbHM6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIHZhciB0b3RhbCA9IHRoaXMuJCgndGJvZHkgOmNoZWNrYm94Jyk7XG4gICAgICAgIHZhciBjaGVja2VkID0gdGhpcy4kKCd0Ym9keSA6Y2hlY2tib3g6Y2hlY2tlZCcpO1xuXG4gICAgICAgIGlmICh0b3RhbC5sZW5ndGggPT09IGNoZWNrZWQubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aGlzLiQoJyNzZWxlY3QtYWxsJykuYXR0cignY2hlY2tlZCcsICdjaGVja2VkJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLiQoJyNzZWxlY3QtYWxsJykucmVtb3ZlQXR0cignY2hlY2tlZCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9scygpO1xuICAgIH0sXG5cbiAgICBfc2hvd1VwZGF0aW5nOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLmNzcyh7IG9wYWNpdHk6IDAuNCB9KTtcbiAgICB9LFxuXG4gICAgX2hpZGVVcGRhdGluZzogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiRlbC5jc3MoeyBvcGFjaXR5OiAxIH0pO1xuICAgIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBBc3NpZ25tZW50OyIsIid1c2Ugc3RyaWN0JztcblxudmFyIEJhc2VDb2xsZWN0aW9uID0gZnVuY3Rpb24gKG1vZGVscywgb3B0aW9ucykge1xuICAgIHRoaXMuX21vZGVscyA9IFtdO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5fLmV4dGVuZChCYXNlQ29sbGVjdGlvbi5wcm90b3R5cGUsIHtcbiAgICBpZEF0dHJpYnV0ZTogJ2lkJyxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uIChtb2RlbHMsIG9wdGlvbnMpIHtcbiAgICB9LFxuXG4gICAgY3JlYXRlOiBmdW5jdGlvbiAoYXR0ciwgb3B0aW9ucykge1xuICAgICAgICB2YXIgbSA9IG5ldyB0aGlzLm1vZGVsKGF0dHIsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLnNldChtKTtcbiAgICAgICAgcmV0dXJuIG07XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAobW9kZWxzLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMuX21vZGVscy5sZW5ndGggPSAwO1xuICAgICAgICB0aGlzLnNldChtb2RlbHMpO1xuICAgIH0sXG5cbiAgICByZW1vdmU6IGZ1bmN0aW9uIChtb2RlbCkge1xuICAgICAgICBfLnJlbW92ZSh0aGlzLl9tb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbSA9PT0gbW9kZWw7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGRlbGV0ZSBtb2RlbC5jb2xsZWN0aW9uO1xuXG4gICAgICAgIHJldHVybiBtb2RlbDtcbiAgICB9LFxuXG4gICAgc2V0OiBmdW5jdGlvbiAobW9kZWxzKSB7XG4gICAgICAgIGlmICghbW9kZWxzKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBtb2RlbHMgPSBbXS5jb25jYXQobW9kZWxzKTtcblxuICAgICAgICBpZiAoIW1vZGVscy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIF8uZWFjaChtb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICBpZiAoIShtIGluc3RhbmNlb2YgdGhpcy5tb2RlbCkpIHtcbiAgICAgICAgICAgICAgICBtID0gbmV3IHRoaXMubW9kZWwobSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG0uY29sbGVjdGlvbiA9IHRoaXM7XG5cbiAgICAgICAgICAgIHRoaXMuX21vZGVscy5wdXNoKG0pO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICB0aGlzLnNvcnQuY2FsbCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gbW9kZWxzO1xuICAgIH0sXG5cbiAgICBzb3J0Rm46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHJldHVybiBiLl9kYXRhW3RoaXMuaWRBdHRyaWJ1dGVdIC0gYS5fZGF0YVt0aGlzLmlkQXR0cmlidXRlXTtcbiAgICB9LFxuXG4gICAgc29ydDogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLl9tb2RlbHMgPSB0aGlzLl9tb2RlbHMuc29ydCh0aGlzLnNvcnRGbi5iaW5kKHRoaXMpKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWxzO1xuICAgIH0sXG5cbiAgICBnZXRCeUlkOiBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgcmV0dXJuIF8uZmluZCh0aGlzLl9tb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbS5nZXQodGhpcy5pZEF0dHJpYnV0ZSkgPT09IGlkO1xuICAgICAgICB9LCB0aGlzKTtcbiAgICB9LFxuXG4gICAgZWFjaDogZnVuY3Rpb24gKGNiLCBjdHgpIHtcbiAgICAgICAgcmV0dXJuIF8uZWFjaCh0aGlzLl9tb2RlbHMsIGNiLCBjdHggfHwgdGhpcyk7XG4gICAgfSxcblxuICAgIGFsbDogZnVuY3Rpb24gKGNiLCBjdHgpIHtcbiAgICAgICAgcmV0dXJuIF8uYWxsKHRoaXMuX21vZGVscywgY2IsIGN0eCB8fCB0aGlzKTtcbiAgICB9LFxuXG4gICAgdG9KU09OOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBfLmludm9rZSh0aGlzLl9tb2RlbHMsICd0b0pTT04nKTtcbiAgICB9LFxuXG4gICAgZmluZDogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiBfLmZpbmQodGhpcy5fbW9kZWxzLCBmbik7XG4gICAgfSxcblxuICAgIGZpbHRlcjogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiBfLmZpbHRlcih0aGlzLl9tb2RlbHMsIGZuKTtcbiAgICB9LFxuXG4gICAgc2l6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWxzLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgbWFwOiBmdW5jdGlvbiAoZm4sIGN0eCkge1xuICAgICAgICByZXR1cm4gXy5tYXAodGhpcy5fbW9kZWxzLCBmdW5jdGlvbiAobW9kZWwpIHtcbiAgICAgICAgICAgIHJldHVybiBmbi5jYWxsKGN0eCwgbW9kZWwudG9KU09OKCkpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgcGx1Y2s6IGZ1bmN0aW9uIChmaWVsZCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tYXAoZnVuY3Rpb24gKG0pIHtcbiAgICAgICAgICAgIHJldHVybiBtW2ZpZWxkXTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBCYXNlQ29sbGVjdGlvbjsiLCIndXNlIHN0cmljdCc7XG5cblxudmFyIEJhc2VNb2RlbCA9IGZ1bmN0aW9uIChhdHRyLCBvcHRpb25zKSB7XG4gICAgYXR0ciA9IF8uZGVmYXVsdHMoe30sIGF0dHIsIF8ucmVzdWx0KHRoaXMsICdkZWZhdWx0cycpKTtcbiAgICB0aGlzLl9kYXRhID0ge307XG4gICAgdGhpcy5zZXQoYXR0ciwgb3B0aW9ucyk7XG4gICAgdGhpcy5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5fLmV4dGVuZChCYXNlTW9kZWwucHJvdG90eXBlLCB7XG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24gKGF0dHIsIG9wdGlvbnMpIHtcblxuICAgIH0sXG5cbiAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbCwgb3B0aW9ucykge1xuXG4gICAgICAgIGlmIChrZXkgPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgYXR0cnMgPSBrZXk7XG4gICAgICAgICAgICBvcHRpb25zID0gdmFsO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWw7XG4gICAgICAgIH1cblxuICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICBfLmV4dGVuZCh0aGlzLl9kYXRhLCBhdHRycyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIGdldDogZnVuY3Rpb24gKGtleSwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5fZGF0YVtrZXldO1xuICAgIH0sXG5cbiAgICByZW1vdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHRoaXMuY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhpcy5jb2xsZWN0aW9uLnJlbW92ZSh0aGlzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICB0b0pTT046IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2RhdGE7XG4gICAgfSxcblxuICAgIHBpY2s6IGZ1bmN0aW9uIChrZXlzKSB7XG4gICAgICAgIHJldHVybiBfLnBpY2sodGhpcy5fZGF0YSwga2V5cyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBCYXNlTW9kZWw7IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgZW52ID0ge1xuICAgIGFjY291bnQ6ICcnLFxuICAgIHByb2plY3Q6ICcnLFxuICAgIGdyb3VwOiAnJyxcbiAgICBncm91cElkOiAnJyxcbiAgICB0b2tlbjogJycsXG4gICAgc2VydmVyOiB7XG4gICAgICAgIGhvc3Q6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgcHJvdG9jb2w6ICdodHRwcydcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBzZXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGVudiA9IF8ubWVyZ2UoZW52LCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBlbnY7XG4gICAgfVxufTsiLCIoZnVuY3Rpb24gKCkge1xuICAgICd1c2Ugc3RyaWN0JztcbiAgICB2YXIgQXBwID0gcmVxdWlyZSgnLi9hc3NpZ25tZW50LmpzJyk7XG5cbiAgICB3aW5kb3cuZm9yaW8gPSB3aW5kb3cuZm9yaW8gfHwge307XG4gICAgd2luZG93LmZvcmlvLk11bHRpcGxheWVyQXNzaWdubWVudENvbXBvbmVudCA9IEFwcDtcbn0pKCk7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBzZXJ2aWNlTG9jYXRvciA9IHJlcXVpcmUoJy4vc2VydmljZS1sb2NhdG9yJyk7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG4vLyB2YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG5cbiAgICBpc0R5bmFtaWNBc3NpZ25tZW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldCgnd29ybGRzJykgPT09ICdkeW5hbWljJztcbiAgICB9LFxuXG4gICAgaGFzUm9sZXM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHJvbGVzID0gdGhpcy5nZXQoJ3JvbGVzJyk7XG4gICAgICAgIHJldHVybiByb2xlcyAmJiAhIXJvbGVzLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgZmV0Y2g6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGFwaSA9IHNlcnZpY2VMb2NhdG9yLndvcmxkQXBpKCk7XG5cbiAgICAgICAgcmV0dXJuIGFwaS5nZXRQcm9qZWN0U2V0dGluZ3MoKS50aGVuKGZ1bmN0aW9uIChzZXR0aW5ncykge1xuICAgICAgICAgICAgdGhpcy5zZXQoc2V0dGluZ3MpO1xuICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cbn0pOyIsIid1c2Ugc3RyaWN0JztcblxudmFyIGVudiA9IHJlcXVpcmUoJy4vZGVmYXVsdHMuanMnKTtcblxudmFyIGNhY2hlID0ge307XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIHdvcmxkQXBpOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICghY2FjaGUud29ybGRBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLndvcmxkQXBpID0gbmV3IEYuc2VydmljZS5Xb3JsZChlbnYuZ2V0KCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlLndvcmxkQXBpO1xuICAgIH0sXG5cbiAgICBtZW1iZXJBcGk6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKCFjYWNoZS5tZW1iZXJBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLm1lbWJlckFwaSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKF8ucGljayhlbnYuZ2V0KCksIFsnZ3JvdXBJZCcsICdzZXJ2ZXInXSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlLm1lbWJlckFwaTtcbiAgICB9LFxuXG4gICAgdXNlckFwaTogZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoIWNhY2hlLnVzZXJBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLnVzZXJBcGkgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoXy5waWNrKGVudi5nZXQoKSwgWydhY2NvdW50JywgJ3NlcnZlciddKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gY2FjaGUudXNlckFwaTtcbiAgICB9XG59OyIsImV4cG9ydHNbXCJlZGl0LXVzZXItcm93XCJdID0gZnVuY3Rpb24ob2JqKSB7XG5vYmogfHwgKG9iaiA9IHt9KTtcbnZhciBfX3QsIF9fcCA9ICcnLCBfX2UgPSBfLmVzY2FwZSwgX19qID0gQXJyYXkucHJvdG90eXBlLmpvaW47XG5mdW5jdGlvbiBwcmludCgpIHsgX19wICs9IF9fai5jYWxsKGFyZ3VtZW50cywgJycpIH1cbndpdGggKG9iaikge1xuX19wICs9ICc8dGQ+PGlucHV0IHR5cGU9XCJjaGVja2JveFwiIGNsYXNzPVwic2VsZWN0XCIgZGF0YS1pZD1cIicgK1xuKChfX3QgPSAoIGlkICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiPC90ZD5cXG48dGQ+PC90ZD5cXG48dGQ+XFxuICAgIDxzZWxlY3QgbmFtZT1cIndvcmxkc1wiIGNsYXNzPVwiZm9ybS1jb250cm9sXCIgZGF0YS1maWVsZD1cIndvcmxkXCI+XFxuXFxuICAgICc7XG4gXy5lYWNoKHdvcmxkcywgZnVuY3Rpb24gKHcpIHsgO1xuX19wICs9ICdcXG4gICAgICAgIDxvcHRpb24gdmFsdWU9XCInICtcbigoX190ID0gKCB3ICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiICcgK1xuKChfX3QgPSAoIHcgPT09IHdvcmxkID8gJ3NlbGVjdGVkJyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJz4nICtcbigoX190ID0gKCB3ICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvb3B0aW9uPlxcbiAgICAnO1xuIH0pOyA7XG5fX3AgKz0gJ1xcbiAgICAgICAgPG9wdGlvbiB2YWx1ZT1cIicgK1xuKChfX3QgPSAoIG5ld1dvcmxkICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiIGNsYXNzPVwibmV3LXdvcmxkLXRleHRcIj48aT4nICtcbigoX190ID0gKCBuZXdXb3JsZCApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbicgLSBOZXcgLTwvaT48L29wdGlvbj5cXG4gICAgPC9zZWxlY3Q+XFxuPC90ZD5cXG48dGQ+XFxuICAgIDxzZWxlY3QgbmFtZT1cInJvbGVzXCIgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIiBkYXRhLWZpZWxkPVwicm9sZVwiPlxcbiAgICAnO1xuIF8uZWFjaChyb2xlcywgZnVuY3Rpb24gKHIpIHsgO1xuX19wICs9ICdcXG4gICAgICAgIDxvcHRpb24gdmFsdWU9XCInICtcbigoX190ID0gKCByICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiICcgK1xuKChfX3QgPSAoIHIgPT09IHJvbGUgPyAnc2VsZWN0ZWQnIDogJycgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPicgK1xuKChfX3QgPSAoIHIgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC9vcHRpb24+XFxuICAgICc7XG4gfSk7IDtcbl9fcCArPSAnXFxuXFxuICAgICc7XG4gXy5lYWNoKG9wdGlvbmFsUm9sZXMsIGZ1bmN0aW9uIChyKSB7IDtcbl9fcCArPSAnXFxuICAgICAgICA8b3B0aW9uIHZhbHVlPVwiJyArXG4oKF9fdCA9ICggciApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbidcIiAnICtcbigoX190ID0gKCByID09PSByb2xlID8gJ3NlbGVjdGVkJyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJz4nICtcbigoX190ID0gKCByICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJyA8aT4oT3B0aW9uYWwpPC9pPjwvb3B0aW9uPlxcbiAgICAnO1xuIH0pOyA7XG5fX3AgKz0gJ1xcbiAgICA8L3NlbGVjdD5cXG48L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCBsYXN0TmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCB1c2VyTmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCAhd29ybGQgPyAnPGVtIGNsYXNzPVwiZi1pY29uIGYtd2FybmluZ1wiPjwvZW0+JyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvdGQ+XFxuPHRkIGNsYXNzPVwiYWN0aW9uc1wiPlxcbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi1wcmltYXJ5IGJ0bi10b29scyBidG4tc2F2ZSBzYXZlXCI+U2F2ZTwvYnV0dG9uPlxcbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi10b29scyBidG4tY2FuY2VsIGNhbmNlbFwiPkNhbmNlbDwvYnV0dG9uPlxcbjwvdGQ+JztcblxufVxucmV0dXJuIF9fcFxufTtcbmV4cG9ydHNbXCJ1c2VyLXJvd1wiXSA9IGZ1bmN0aW9uKG9iaikge1xub2JqIHx8IChvYmogPSB7fSk7XG52YXIgX190LCBfX3AgPSAnJywgX19lID0gXy5lc2NhcGU7XG53aXRoIChvYmopIHtcbl9fcCArPSAnPHRkPjxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBjbGFzcz1cInNlbGVjdFwiIGRhdGEtaWQ9XCInICtcbigoX190ID0gKCBpZCkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggIWlzV29ybGRDb21wbGV0ZSA/ICc8ZW0gY2xhc3M9XCJmLWljb24gZi13YXJuaW5nXCI+PC9lbT4nIDogJycgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggd29ybGQgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggcm9sZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCBsYXN0TmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCB1c2VyTmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCAhd29ybGQgPyAnPGVtIGNsYXNzPVwiZi1pY29uIGYtd2FybmluZ1wiPjwvZW0+JyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvdGQ+XFxuPHRkIGNsYXNzPVwiYWN0aW9uc1wiPjxidXR0b24gY2xhc3M9XCJidG4gZWRpdCBidG4tZWRpdCBidG4tdG9vbHMgYXV0by1oaWRlXCI+RWRpdDwvYnV0dG9uPjwvdGQ+JztcblxufVxucmV0dXJuIF9fcFxufTsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG52YXIgc2VydmljZUxvY2F0b3IgPSByZXF1aXJlKCcuL3NlcnZpY2UtbG9jYXRvcicpO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBkZWZhdWx0czoge1xuICAgICAgICB3b3JsZDogJycsXG4gICAgICAgIHJvbGU6ICcnLFxuICAgICAgICBhY3RpdmU6IHRydWUsXG4gICAgICAgIGlzV29ybGRDb21wbGV0ZTogdHJ1ZSxcbiAgICAgICAgZmlyc3ROYW1lOiAnJyxcbiAgICAgICAgbGFzdE5hbWU6ICcnXG4gICAgfSxcblxuICAgIG1ha2VBY3RpdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG1lbWJlckFwaSA9IHNlcnZpY2VMb2NhdG9yLm1lbWJlckFwaSgpO1xuICAgICAgICB2YXIgcGFyYW1zID0ge1xuICAgICAgICAgICAgdXNlcklkOiB0aGlzLmdldCgnaWQnKSxcbiAgICAgICAgICAgIGdyb3VwSWQ6IHRoaXMuZ2V0KCdncm91cElkJylcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLmdldCgnYWN0aXZlJyk7XG4gICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCB0cnVlKTtcblxuICAgICAgICByZXR1cm4gbWVtYmVyQXBpLm1ha2VVc2VyQWN0aXZlKHBhcmFtcylcbiAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyByZXZlcnQgdGhlIGNoYW5nZVxuICAgICAgICAgICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBvcmlnaW5hbCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBtYWtlSW5hY3RpdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG1lbWJlckFwaSA9IHNlcnZpY2VMb2NhdG9yLm1lbWJlckFwaSgpO1xuICAgICAgICB2YXIgcGFyYW1zID0ge1xuICAgICAgICAgICAgdXNlcklkOiB0aGlzLmdldCgnaWQnKSxcbiAgICAgICAgICAgIGdyb3VwSWQ6IHRoaXMuZ2V0KCdncm91cElkJylcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLmdldCgnYWN0aXZlJyk7XG4gICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBmYWxzZSk7XG5cbiAgICAgICAgcmV0dXJuIG1lbWJlckFwaS5tYWtlVXNlckluYWN0aXZlKHBhcmFtcylcbiAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyByZXZlcnQgdGhlIGNoYW5nZVxuICAgICAgICAgICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBvcmlnaW5hbCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cblxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcblxudmFyIE1vZGVsID0gcmVxdWlyZSgnLi91c2VyLW1vZGVsJyk7XG52YXIgQmFzZSA9IHJlcXVpcmUoJy4vYmFzZS1jb2xsZWN0aW9uJyk7XG52YXIgZW52ID0gcmVxdWlyZSgnLi9kZWZhdWx0cycpO1xudmFyIHNlcnZpY2VMb2NhdG9yID0gcmVxdWlyZSgnLi9zZXJ2aWNlLWxvY2F0b3InKTtcblxuXG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBtb2RlbDogTW9kZWwsXG5cbiAgICBzb3J0Rm46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHZhciBhdyA9IGEuZ2V0KCd3b3JsZCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIHZhciBidyA9IGIuZ2V0KCd3b3JsZCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIGlmIChhdyAhPT0gYncpIHtcbiAgICAgICAgICAgIHJldHVybiBhdyA8IGJ3ID8gLTEgOiAxO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGIuZ2V0KCd1c2VyTmFtZScpID4gYS5nZXQoJ3VzZXJOYW1lJykgPyAtMSA6IDE7XG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgJC5hamF4U2V0dXAoe1xuICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgIEF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIGVudi5nZXQoKS50b2tlblxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgYWxsVXNlcnNBc3NpZ25lZDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5hbGwoZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgIHJldHVybiAhIXUuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0VW5hc3NpZ25lZFVzZXJzQ291bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmlsdGVyKGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICByZXR1cm4gIXUuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB9KS5sZW5ndGg7XG4gICAgfSxcblxuICAgIGZldGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBncm91cElkID0gZW52LmdldCgpLmdyb3VwSWQ7XG5cbiAgICAgICAgdmFyIGdldEdyb3VwVXNlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgbWVtYmVyQXBpID0gc2VydmljZUxvY2F0b3IubWVtYmVyQXBpKCk7XG4gICAgICAgICAgICB2YXIgdXNlckFwaSA9IHNlcnZpY2VMb2NhdG9yLnVzZXJBcGkoKTtcblxuICAgICAgICAgICAgdmFyIGxvYWRHcm91cE1lbWJlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1lbWJlckFwaS5nZXRHcm91cERldGFpbHMoKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBsb2FkVXNlcnNJbmZvID0gZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgdmFyIG5vbkZhY0FuZEFjdGl2ZSA9IGZ1bmN0aW9uICh1KSB7IHJldHVybiB1LmFjdGl2ZSAmJiB1LnJvbGUgIT09ICdmYWNpbGl0YXRvcic7IH07XG4gICAgICAgICAgICAgICAgdmFyIHVzZXJzID0gXy5wbHVjayhfLmZpbHRlcihncm91cC5tZW1iZXJzLCBub25GYWNBbmRBY3RpdmUpLCAndXNlcklkJyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVzZXJBcGkuZ2V0KHsgaWQ6IHVzZXJzIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgcmV0dXJuIGxvYWRHcm91cE1lbWJlcnMoKVxuICAgICAgICAgICAgICAgIC50aGVuKGxvYWRVc2Vyc0luZm8pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgZ2V0R3JvdXBVc2VycygpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAodXNlcnMpIHtcbiAgICAgICAgICAgICAgICB1c2VycyA9IF8ubWFwKHVzZXJzLCBmdW5jdGlvbiAodSkgeyByZXR1cm4gXy5leHRlbmQodSwgeyBncm91cElkOiBncm91cElkIH0pOyB9KTtcbiAgICAgICAgICAgICAgICBfdGhpcy5zZXQodXNlcnMpO1xuICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHVzZXJzLCBfdGhpcyk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICB9XG5cbn0pO1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIHNlcnZpY2VMb2NhdG9yID0gcmVxdWlyZSgnLi9zZXJ2aWNlLWxvY2F0b3InKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG52YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG5cbiAgICBkZWZhdWx0czoge1xuICAgICAgICB1c2VyczogbnVsbCxcbiAgICAgICAgbW9kZWw6ICdtb2RlbC5lcW4nXG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgX19zdXBlci5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICAgICAgdGhpcy5fZGF0YS51c2VycyA9IHRoaXMuX2RhdGEudXNlcnMgfHwgW107XG5cbiAgICAgICAgdGhpcy5fd29ybGRBcGkgPSBzZXJ2aWNlTG9jYXRvci53b3JsZEFwaSgpO1xuXG4gICAgICAgIHZhciBpZCA9IHRoaXMuZ2V0KCdpZCcpO1xuICAgICAgICBpZiAoaWQpIHtcbiAgICAgICAgICAgIHRoaXMuX3dvcmxkQXBpLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgYWRkVXNlcjogZnVuY3Rpb24gKHVzZXIpIHtcbiAgICAgICAgdmFyIHVzZXJzID0gdGhpcy5nZXQoJ3VzZXJzJyk7XG4gICAgICAgIHVzZXJzLnB1c2godXNlcik7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuc2F2ZSgpO1xuICAgIH0sXG5cbiAgICByZW1vdmVVc2VyOiBmdW5jdGlvbiAodXNlcikge1xuICAgICAgICB2YXIgaWQgPSB0aGlzLmdldCgnaWQnKTtcbiAgICAgICAgdmFyIGNoZWNrV29ybGQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuZ2V0KCd1c2VycycpLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3dvcmxkQXBpLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSkuZGVsZXRlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICBfLnJlbW92ZSh0aGlzLmdldCgndXNlcnMnKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgIHJldHVybiB1LmdldCgnaWQnKSA9PT0gdXNlci5nZXQoJ2lkJyk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiB0aGlzLl93b3JsZEFwaVxuICAgICAgICAgICAgLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogaWQgfSlcbiAgICAgICAgICAgIC5yZW1vdmVVc2VyKHsgdXNlcklkOiB1c2VyLmdldCgnaWQnKSB9KVxuICAgICAgICAgICAgLnRoZW4oY2hlY2tXb3JsZCk7XG4gICAgfSxcblxuICAgIHNhdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIG1hcFVzZXJzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIF8ubWFwKHRoaXMuZ2V0KCd1c2VycycpLCBmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgICAgIHZhciByZXMgPSB7IHVzZXJJZDogdS5nZXQoJ2lkJykgfTtcbiAgICAgICAgICAgICAgICB2YXIgcm9sZSA9IHUuZ2V0KCdyb2xlJyk7XG5cbiAgICAgICAgICAgICAgICBpZiAocm9sZSkge1xuICAgICAgICAgICAgICAgICAgICByZXMucm9sZSA9IHJvbGU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdmFyIGNyZWF0ZVdvcmxkID0gXy5wYXJ0aWFsKHRoaXMuX3dvcmxkQXBpLmNyZWF0ZSwgdGhpcy5waWNrKFsnbW9kZWwnLCAnbmFtZScsICdtaW5Vc2VycyddKSk7XG4gICAgICAgIHZhciBhZGRVc2VycyA9IF8ucGFydGlhbChfdGhpcy5fd29ybGRBcGkuYWRkVXNlcnMsIG1hcFVzZXJzKCksIHsgZmlsdGVyOiBfdGhpcy5nZXQoJ2lkJykgfSk7XG4gICAgICAgIHZhciBzYXZlZFVzZXJzID0gdGhpcy5nZXQoJ3VzZXJzJyk7XG4gICAgICAgIGlmICh0aGlzLmlzTmV3KCkpIHtcbiAgICAgICAgICAgIC8vIHdlIG5lZWQgdG8gY3JlYXRlIHRoZSB3b3JsZCBpbiB0aGUgQVBJIGFuZCB0aGVuIGFkZCB0aGUgdXNlcnNcbiAgICAgICAgICAgIHJldHVybiBjcmVhdGVXb3JsZCgpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLnNldCh3b3JsZCk7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLl93b3JsZEFwaS51cGRhdGVDb25maWcoeyBmaWx0ZXI6IHdvcmxkLmlkIH0pO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oYWRkVXNlcnMpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHVzZXJzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHNpbmNlIHdlIHJlLXNldCB0aGUgd29ybGQsIHJlLXNldCB0aGUgdXNlcnNcbiAgICAgICAgICAgICAgICAgICAgX3RoaXMuc2V0KCd1c2VycycsIHNhdmVkVXNlcnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gdGhlIHdvcmxkIGlzIGFscmVhZHkgY3JlYXRlZCBqdXN0IGFkZCB0aGUgdXNlcnNcbiAgICAgICAgICAgIHJldHVybiBhZGRVc2VycygpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIGlzTmV3OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiAhdGhpcy5nZXQoJ2xhc3RNb2RpZmllZCcpO1xuICAgIH1cblxufSk7IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgTW9kZWwgPSByZXF1aXJlKCcuL3dvcmxkLW1vZGVsJyk7XG52YXIgVXNlck1vZGVsID0gcmVxdWlyZSgnLi91c2VyLW1vZGVsJyk7XG52YXIgc2VydmljZUxvY2F0b3IgPSByZXF1aXJlKCcuL3NlcnZpY2UtbG9jYXRvcicpO1xuXG52YXIgQmFzZSA9IHJlcXVpcmUoJy4vYmFzZS1jb2xsZWN0aW9uJyk7XG52YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG52YXIgZG9uZUZuID0gZnVuY3Rpb24gKGR0ZCwgYWZ0ZXIpIHtcbiAgICByZXR1cm4gXy5hZnRlcihhZnRlciwgZHRkLnJlc29sdmUpO1xufTtcblxudmFyIHdvcmxkQXBpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgbW9kZWw6IE1vZGVsLFxuXG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICBfX3N1cGVyLmluaXRpYWxpemUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgd29ybGRBcGkgPSBzZXJ2aWNlTG9jYXRvci53b3JsZEFwaSgpO1xuICAgIH0sXG5cbiAgICBhdXRvQXNzaWduQWxsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gd29ybGRBcGkuYXV0b0Fzc2lnbihvcHRpb25zKVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkcykge1xuICAgICAgICAgICAgICAgIHRoaXMucmVzZXQodGhpcy5wYXJzZSh3b3JsZHMpKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGdldEluY29tcGxldGVXb3JsZHNDb3VudDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5maWx0ZXIoZnVuY3Rpb24gKHcpIHtcbiAgICAgICAgICAgIHJldHVybiAhdy5nZXQoJ2NvbXBsZXRlJyk7XG4gICAgICAgIH0pLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgdXBkYXRlVXNlcjogZnVuY3Rpb24gKHVzZXIpIHtcbiAgICAgICAgdmFyIHdvcmxkTmFtZSA9IHVzZXIuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgcHJldldvcmxkID0gdGhpcy5nZXRXb3JsZEJ5VXNlcih1c2VyKTtcbiAgICAgICAgdmFyIGN1cldvcmxkID0gdGhpcy5nZXRPckNyZWF0ZVdvcmxkKHdvcmxkTmFtZSk7XG4gICAgICAgIHZhciBkb25lID0gZG9uZUZuKGR0ZCwgMSk7XG5cbiAgICAgICAgLy8gY2hlY2sgaWYgdGhlcmUncyBhbnl0aGluZyB0byBkb1xuICAgICAgICBpZiAoIXByZXZXb3JsZCAmJiAhY3VyV29ybGQpIHtcbiAgICAgICAgICAgIHJldHVybiBkdGQucmVzb2x2ZSgpLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwcmV2V29ybGQpIHtcbiAgICAgICAgICAgIHByZXZXb3JsZC5yZW1vdmVVc2VyKHVzZXIpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoY3VyV29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjdXJXb3JsZC5hZGRVc2VyKHVzZXIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAudGhlbihkb25lKTtcbiAgICAgICAgfSBlbHNlIGlmIChjdXJXb3JsZCkge1xuICAgICAgICAgICAgY3VyV29ybGQuYWRkVXNlcih1c2VyKVxuICAgICAgICAgICAgICAgIC50aGVuKGRvbmUpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldE9yQ3JlYXRlV29ybGQ6IGZ1bmN0aW9uICh3b3JsZE5hbWUpIHtcbiAgICAgICAgaWYgKCF3b3JsZE5hbWUpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciB3b3JsZCA9IHRoaXMuZ2V0V29yZEJ5TmFtZSh3b3JsZE5hbWUpO1xuXG4gICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgIHdvcmxkID0gdGhpcy5jcmVhdGUoeyBuYW1lOiB3b3JsZE5hbWUgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gd29ybGQ7XG4gICAgfSxcblxuICAgIGdldFdvcmRCeU5hbWU6IGZ1bmN0aW9uICh3b3JsZE5hbWUpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmluZChmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgIHJldHVybiB3b3JsZC5nZXQoJ25hbWUnKSA9PT0gd29ybGROYW1lO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0V29ybGRCeVVzZXI6IGZ1bmN0aW9uICh1c2VyKSB7XG4gICAgICAgIGlmICghdXNlci5nZXQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZ2V0V29ybGRCeVVzZXIgZXhwZWN0ZXMgYSBtb2RlbCAoJyArIHVzZXIgKyAnKScpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGlkID0gdXNlci5nZXQoJ2lkJyk7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFdvcmxkQnlVc2VySWQoaWQpO1xuICAgIH0sXG5cbiAgICBnZXRXb3JsZEJ5VXNlcklkOiBmdW5jdGlvbiAodXNlcklkKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmZpbmQoZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICByZXR1cm4gXy5maW5kKHdvcmxkLmdldCgndXNlcnMnKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdS5nZXQoJ2lkJykgPT09IHVzZXJJZDtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0V29ybGROYW1lczogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5wbHVjaygnbmFtZScpO1xuICAgIH0sXG5cbiAgICBnZXROZXh0V29ybGROYW1lOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBwYWQgPSBmdW5jdGlvbiAobnVtLCBwbGFjZXMpIHtcbiAgICAgICAgICAgIHZhciB6ZXJvcyA9ICcwMDAwMDAwMDAwMDAwMDAwMDAnO1xuICAgICAgICAgICAgdmFyIGRpZ2l0cyA9IG51bS50b1N0cmluZygpLmxlbmd0aDtcbiAgICAgICAgICAgIHZhciBuZWVkZWQgPSBwbGFjZXMgLSBkaWdpdHM7XG4gICAgICAgICAgICByZXR1cm4gemVyb3Muc3Vic3RyKDAsIG5lZWRlZCkgKyBudW07XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHdvcmxkcyA9IHRoaXMuZ2V0V29ybGROYW1lcygpO1xuXG4gICAgICAgIGlmICghd29ybGRzLmxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuICdXb3JsZDAwMSc7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgcHJvcGVyTmFtZXMgPSBfLmZpbHRlcih3b3JsZHMsIGZ1bmN0aW9uICh3KSB7IHJldHVybiAvV29ybGRcXGRcXGRcXGQvLnRlc3Qodyk7IH0pLnNvcnQoKTtcbiAgICAgICAgdmFyIGxhc3RXb3JsZCA9IHByb3Blck5hbWVzW3Byb3Blck5hbWVzLmxlbmd0aCAtIDFdO1xuICAgICAgICB2YXIgbnVtV29ybGQgPSArbGFzdFdvcmxkLm1hdGNoKC9Xb3JsZChcXGRcXGRcXGQpLylbMV07XG4gICAgICAgIHJldHVybiAnV29ybGQnICsgcGFkKG51bVdvcmxkICsgMSwgMyk7XG4gICAgfSxcblxuICAgIHNldFVzZXJzQ29sbGVjdGlvbjogZnVuY3Rpb24gKHVzZXJzQ29sbGVjdGlvbikge1xuICAgICAgICB0aGlzLnVzZXJzQ29sbGVjdGlvbiA9IHVzZXJzQ29sbGVjdGlvbjtcbiAgICB9LFxuXG4gICAgam9pblVzZXJzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1c2Vyc0hhc2ggPSB7fTtcbiAgICAgICAgdmFyIHVzZXJzQ29sbGVjdGlvbiA9IHRoaXMudXNlcnNDb2xsZWN0aW9uO1xuICAgICAgICB1c2Vyc0NvbGxlY3Rpb24uZWFjaChmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgdS5zZXQoeyBpc1dvcmxkQ29tcGxldGU6IHRydWUgfSk7XG4gICAgICAgICAgICByZXR1cm4gKHVzZXJzSGFzaFt1LmdldCgnaWQnKV0gPSB1KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5lYWNoKGZ1bmN0aW9uICh3LCBpKSB7XG4gICAgICAgICAgICB2YXIgbmFtZSA9IHcuZ2V0KCduYW1lJyk7XG4gICAgICAgICAgICB2YXIgaXNDb21wbGV0ZSA9IHcuZ2V0KCdjb21wbGV0ZScpO1xuICAgICAgICAgICAgdy5zZXQoeyBpbmRleDogaSwgbmFtZTogbmFtZSB8fCAoaSArIDEpICsgJycgfSk7XG4gICAgICAgICAgICBfLmVhY2gody5nZXQoJ3VzZXJzJyksIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgaWYgKHVzZXJzSGFzaFt1LmdldCgndXNlcklkJyldKSB7XG4gICAgICAgICAgICAgICAgICAgIHVzZXJzSGFzaFt1LmdldCgndXNlcklkJyldLnNldCh7IHdvcmxkOiBuYW1lLCByb2xlOiB1LmdldCgncm9sZScpLCBpc1dvcmxkQ29tcGxldGU6IGlzQ29tcGxldGUgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHVzZXJzQ29sbGVjdGlvbi5zb3J0KCk7XG4gICAgfSxcblxuICAgIGZldGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB3b3JsZEFwaS5saXN0KClcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICh3b3JsZHMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlc2V0KHRoaXMucGFyc2Uod29ybGRzKSk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBwYXJzZTogZnVuY3Rpb24gKHdvcmxkcykge1xuICAgICAgICBpZiAod29ybGRzLmxlbmd0aCkge1xuICAgICAgICAgICAgd29ybGRzID0gXy5tYXAod29ybGRzLCBmdW5jdGlvbiAodykge1xuICAgICAgICAgICAgICAgIHZhciB1c2VycyA9IF8ubWFwKHcudXNlcnMsIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGluIHRoZSB3b3JsZCBhcGkgdXNlcnMgSWRzIGNvbWVzIGFzIHVzZXJJZFxuICAgICAgICAgICAgICAgICAgICAvLyBtYWtlIHN1cmUgd2UgYWRkIGl0IGFzIGlkIHNvIHdlIGNhbiB1c2UgdGhlXG4gICAgICAgICAgICAgICAgICAgIC8vIHNhbWUgY29kZSB0byBhY2Nlc3MgbW9kZWxzIHRoYXQgY29tZSBmcm9tIHRoZVxuICAgICAgICAgICAgICAgICAgICAvLyBtZW1iZXIvbG9jYWwgYXBpIGFzIHdpdGggdGhlIHdvcmxkIGFwaVxuICAgICAgICAgICAgICAgICAgICB1LmlkID0gdS51c2VySWQ7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBuZXcgVXNlck1vZGVsKHUpO1xuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgdy51c2VycyA9IHVzZXJzO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHc7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB3b3JsZHM7XG4gICAgfVxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuKiBVdGlsaXR5IGNsYXNzIHRvIG1ha2UgYWpheCBjYWxscyBzZXF1ZW5jaWFsXG4qL1xuZnVuY3Rpb24gQWpheFF1ZXVlICgpIHtcbiAgICB0aGlzLnF1ZXVlID0gW107XG59XG5cbiQuZXh0ZW5kKEFqYXhRdWV1ZS5wcm90b3R5cGUsIHtcbiAgICBhZGQ6IGZ1bmN0aW9uIChmbikge1xuICAgICAgICByZXR1cm4gdGhpcy5xdWV1ZS5wdXNoKGZuKTtcbiAgICB9LFxuXG4gICAgZXhlY3V0ZTogZnVuY3Rpb24gKGNvbnRleHQpIHtcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgY29udGV4dCA9IGNvbnRleHQgfHwgdGhpcztcblxuICAgICAgICBmdW5jdGlvbiBuZXh0KCkge1xuICAgICAgICAgICAgaWYgKF90aGlzLnF1ZXVlLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHZhciBmbiA9IF90aGlzLnF1ZXVlLnNoaWZ0KCk7XG5cbiAgICAgICAgICAgICAgICBmbi5jYWxsKGNvbnRleHQpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKG5leHQpXG4gICAgICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgbmV4dCgpO1xuXG4gICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgIH1cbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQWpheFF1ZXVlOyIsIi8qKlxuLyogSW5oZXJpdCBmcm9tIGEgY2xhc3MgKHVzaW5nIHByb3RvdHlwZSBib3Jyb3dpbmcpXG4qL1xuJ3VzZSBzdHJpY3QnO1xuXG5mdW5jdGlvbiBpbmhlcml0KEMsIFApIHtcbiAgICB2YXIgRiA9IGZ1bmN0aW9uICgpIHt9O1xuICAgIEYucHJvdG90eXBlID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUgPSBuZXcgRigpO1xuICAgIEMuX19zdXBlciA9IFAucHJvdG90eXBlO1xuICAgIEMucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQztcbn1cblxuLyoqXG4qIFNoYWxsb3cgY29weSBvZiBhbiBvYmplY3RcbiovXG52YXIgZXh0ZW5kID0gZnVuY3Rpb24gKGRlc3QgLyosIHZhcl9hcmdzKi8pIHtcbiAgICB2YXIgb2JqID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICB2YXIgY3VycmVudDtcbiAgICBmb3IgKHZhciBqID0gMDsgajxvYmoubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKCEoY3VycmVudCA9IG9ialtqXSkpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZG8gbm90IHdyYXAgaW5uZXIgaW4gZGVzdC5oYXNPd25Qcm9wZXJ0eSBvciBiYWQgdGhpbmdzIHdpbGwgaGFwcGVuXG4gICAgICAgIC8qanNoaW50IC1XMDg5ICovXG4gICAgICAgIGZvciAodmFyIGtleSBpbiBjdXJyZW50KSB7XG4gICAgICAgICAgICBkZXN0W2tleV0gPSBjdXJyZW50W2tleV07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZGVzdDtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGJhc2UsIHByb3BzLCBzdGF0aWNQcm9wcykge1xuICAgIHZhciBwYXJlbnQgPSBiYXNlO1xuICAgIHZhciBjaGlsZDtcblxuICAgIGNoaWxkID0gcHJvcHMgJiYgcHJvcHMuaGFzT3duUHJvcGVydHkoJ2NvbnN0cnVjdG9yJykgPyBwcm9wcy5jb25zdHJ1Y3RvciA6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHBhcmVudC5hcHBseSh0aGlzLCBhcmd1bWVudHMpOyB9O1xuXG4gICAgLy8gYWRkIHN0YXRpYyBwcm9wZXJ0aWVzIHRvIHRoZSBjaGlsZCBjb25zdHJ1Y3RvciBmdW5jdGlvblxuICAgIGV4dGVuZChjaGlsZCwgcGFyZW50LCBzdGF0aWNQcm9wcyk7XG5cbiAgICAvLyBhc3NvY2lhdGUgcHJvdG90eXBlIGNoYWluXG4gICAgaW5oZXJpdChjaGlsZCwgcGFyZW50KTtcblxuICAgIC8vIGFkZCBpbnN0YW5jZSBwcm9wZXJ0aWVzXG4gICAgaWYgKHByb3BzKSB7XG4gICAgICAgIGV4dGVuZChjaGlsZC5wcm90b3R5cGUsIHByb3BzKTtcbiAgICB9XG5cbiAgICAvLyBkb25lXG4gICAgcmV0dXJuIGNoaWxkO1xufTtcbiJdfQ== +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2Fzc2lnbm1lbnQtcm93LmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9hc3NpZ25tZW50LmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9iYXNlLWNvbGxlY3Rpb24uanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2Jhc2UtbW9kZWwuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL2RlZmF1bHRzLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy9pbmRleC5qcyIsInNyYy9jb21wb25lbnRzL2Fzc2lnbm1lbnQvanMvcHJvamVjdC1tb2RlbC5qcyIsInNyYy9jb21wb25lbnRzL2Fzc2lnbm1lbnQvanMvc2VydmljZS1sb2NhdG9yLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy90ZW1wbGF0ZXMuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3VzZXItbW9kZWwuanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3VzZXJzLWNvbGxlY3Rpb24uanMiLCJzcmMvY29tcG9uZW50cy9hc3NpZ25tZW50L2pzL3dvcmxkLW1vZGVsLmpzIiwic3JjL2NvbXBvbmVudHMvYXNzaWdubWVudC9qcy93b3JsZHMtY29sbGVjdGlvbi5qcyIsInNyYy91dGlsL2FqYXgtcXVldWUuanMiLCJzcmMvdXRpbC9pbmhlcml0LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25IQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1BBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIndXNlIHN0cmljdCc7XG5cbnZhciB0ZW1wbGF0ZXMgPSByZXF1aXJlKCcuL3RlbXBsYXRlcycpO1xuXG52YXIgQXNzaWdubWVudFJvdyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdGhpcy4kZWwgPSAkKCc8dHI+Jyk7XG4gICAgdGhpcy5lbCA9IHRoaXMuJGVsWzBdO1xuICAgIHRoaXMuJCA9IF8ucGFydGlhbFJpZ2h0KCQsIHRoaXMuJGVsKTtcblxuICAgIHRoaXMubW9kZWwgPSBvcHRpb25zLm1vZGVsO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy53b3JsZHMgPSBvcHRpb25zLndvcmxkcztcbiAgICB0aGlzLnByb2plY3QgPSBvcHRpb25zLnByb2plY3Q7XG5cbiAgICBfLmJpbmRBbGwodGhpcywgWydzZXRFZGl0TW9kZScsICdyZW1vdmVFZGl0TW9kZScsICdzYXZlRWRpdCcsICdjYW5jZWxFZGl0JywgJ3VwZGF0ZURhdGEnXSk7XG5cbiAgICB0aGlzLmJpbmRFdmVudHMoKTtcblxufTtcblxuXy5leHRlbmQoQXNzaWdubWVudFJvdy5wcm90b3R5cGUsIHtcblxuICAgIHRlbXBsYXRlOiB0ZW1wbGF0ZXNbJ3VzZXItcm93J10sXG5cbiAgICBlZGl0VGVtcGxhdGU6IHRlbXBsYXRlc1snZWRpdC11c2VyLXJvdyddLFxuXG4gICAgYmluZEV2ZW50czogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiRlbC5vbignY2xpY2snLCAnYnV0dG9uLmVkaXQnLCB0aGlzLnNldEVkaXRNb2RlKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJ2J1dHRvbi5zYXZlJywgdGhpcy5zYXZlRWRpdCk7XG4gICAgICAgIHRoaXMuJGVsLm9uKCdjbGljaycsICdidXR0b24uY2FuY2VsJywgdGhpcy5jYW5jZWxFZGl0KTtcbiAgICB9LFxuXG4gICAgcmVtb3ZlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLm9mZignY2xpY2snLCBudWxsLCBudWxsKTtcbiAgICAgICAgLy8gdGhpcyBvbmx5IGdpdmVzIGEgZGVsYXkgdG8gcmVtb3ZlIHRoZSB0clxuICAgICAgICAvLyBhbmltYXRpb24gb2YgaGVpZ2h0IG9mIHRoZSB0ciBkb2VzIG5vdCB3b3JrXG4gICAgICAgIHRoaXMuJCgnOmNoZWNrYm94JykuYXR0cignY2hlY2tlZCcsIGZhbHNlKTtcbiAgICAgICAgdGhpcy4kZWxcbiAgICAgICAgICAgIC5jc3MoeyBvcGFjaXR5OiAwLjMgfSlcbiAgICAgICAgICAgIC5hbmltYXRlKHsgaGVpZ2h0OiAwIH0sIHtcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogMzAwLFxuICAgICAgICAgICAgICAgIGNvbXBsZXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIG1ha2VJbmFjdGl2ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tb2RlbC5tYWtlSW5hY3RpdmUoKTtcbiAgICB9LFxuXG4gICAgc2V0RWRpdE1vZGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5tb2RlbC5zZXQoJ2VkaXQtbW9kZScsIHRydWUpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0sXG5cbiAgICByZW1vdmVFZGl0TW9kZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLm1vZGVsLnNldCgnZWRpdC1tb2RlJywgZmFsc2UpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0sXG5cbiAgICBzYXZlRWRpdDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB0aGlzLnVwZGF0ZURhdGEoKTtcbiAgICAgICAgdGhpcy53b3JsZHNcbiAgICAgICAgICAgIC51cGRhdGVVc2VyKHRoaXMubW9kZWwpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgX3RoaXMucmVtb3ZlRWRpdE1vZGUoKTtcbiAgICAgICAgICAgICAgICBfdGhpcy4kZWwudHJpZ2dlcigndXBkYXRlJywgX3RoaXMpO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGNhbmNlbEVkaXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5yZW1vdmVFZGl0TW9kZSgpO1xuICAgIH0sXG5cbiAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHRlbXBsID0gdGhpcy5tb2RlbC5nZXQoJ2VkaXQtbW9kZScpID8gdGhpcy5lZGl0VGVtcGxhdGUgOiB0aGlzLnRlbXBsYXRlO1xuICAgICAgICB2YXIgdm0gPSBfLmV4dGVuZCh7XG4gICAgICAgICAgICByb2xlczogdGhpcy5wcm9qZWN0LmdldCgncm9sZXMnKSxcbiAgICAgICAgICAgIG9wdGlvbmFsUm9sZXM6IHRoaXMucHJvamVjdC5nZXQoJ29wdGlvbmFsUm9sZXMnKSxcbiAgICAgICAgICAgIHdvcmxkczogdGhpcy53b3JsZHMuZ2V0V29ybGROYW1lcygpLFxuICAgICAgICAgICAgbmV3V29ybGQ6IHRoaXMud29ybGRzLmdldE5leHRXb3JsZE5hbWUoKVxuICAgICAgICB9LCB0aGlzLm1vZGVsLnRvSlNPTigpKTtcblxuICAgICAgICB0aGlzLiRlbC5odG1sKHRlbXBsKHZtKSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIHVwZGF0ZURhdGE6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdGhpcy4kKCdbZGF0YS1maWVsZF0nKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBlbCA9ICQodGhpcyk7XG4gICAgICAgICAgICB2YXIgZmllbGQgPSBlbC5kYXRhKCdmaWVsZCcpO1xuICAgICAgICAgICAgdmFyIHZhbCA9IGVsLnZhbCgpO1xuXG4gICAgICAgICAgICBfdGhpcy5tb2RlbC5zZXQoZmllbGQsIHZhbCk7XG4gICAgICAgIH0pO1xuICAgIH1cbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQXNzaWdubWVudFJvdzsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBVc2Vyc0NvbGxlY3Rpb24gPSByZXF1aXJlKCcuL3VzZXJzLWNvbGxlY3Rpb24nKTtcbnZhciBXb3JsZHNDb2xsZWN0aW9uID0gcmVxdWlyZSgnLi93b3JsZHMtY29sbGVjdGlvbicpO1xudmFyIFByb2plY3RNb2RlbCA9IHJlcXVpcmUoJy4vcHJvamVjdC1tb2RlbCcpO1xudmFyIEFzc2lnbmVtbnRSb3cgPSByZXF1aXJlKCcuL2Fzc2lnbm1lbnQtcm93Jyk7XG52YXIgZW52ID0gcmVxdWlyZSgnLi9kZWZhdWx0cycpO1xudmFyIEFqYXhRdWV1ZSA9IHJlcXVpcmUoJy4uLy4uLy4uL3V0aWwvYWpheC1xdWV1ZScpO1xuXG5mdW5jdGlvbiBzZXRFbnZpcm9ubWVudChvcHRpb25zKSB7XG4gICAgZW52LnNldChfLm9taXQob3B0aW9ucywgJ2VsJykpO1xufVxuXG52YXIgQXNzaWdubWVudCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgc2V0RW52aXJvbm1lbnQob3B0aW9ucyk7XG4gICAgdGhpcy5pbml0aWFsaXplKG9wdGlvbnMpO1xufTtcblxuQXNzaWdubWVudC5wcm90b3R5cGUgPSB7XG5cbiAgICBpbml0aWFsaXplOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB0aGlzLmVsID0gdHlwZW9mIG9wdGlvbnMuZWwgPT09ICdzdHJpbmcnID8gJChvcHRpb25zLmVsKVswXSA6IG9wdGlvbnMuZWw7XG4gICAgICAgIHRoaXMuJGVsID0gJCh0aGlzLmVsKTtcbiAgICAgICAgdGhpcy4kID0gXy5wYXJ0aWFsUmlnaHQoJCwgdGhpcy5lbCk7XG5cbiAgICAgICAgdGhpcy51c2VycyA9IG5ldyBVc2Vyc0NvbGxlY3Rpb24oKTtcbiAgICAgICAgdGhpcy53b3JsZHMgPSBuZXcgV29ybGRzQ29sbGVjdGlvbigpO1xuICAgICAgICB0aGlzLnByb2plY3QgPSBuZXcgUHJvamVjdE1vZGVsKCk7XG5cbiAgICAgICAgXy5iaW5kQWxsKHRoaXMsIFsncmVuZGVyJywgJ3JlbmRlclRhYmxlJywgJ3RvZ2dsZUNvbnRyb2xscycsICdzYXZlRWRpdCcsICdzZWxlY3RBbGwnLCAndXNhc3NpZ25TZWxlY3RlZCcsICdfc2hvd1VwZGF0aW5nJywgJ19oaWRlVXBkYXRpbmcnLCAnYXV0b0Fzc2lnbkFsbCcsICdtYWtlVXNlckluYWN0aXZlJ10pO1xuXG4gICAgICAgIHRoaXMuYmluZEV2ZW50cygpO1xuICAgIH0sXG5cbiAgICBiaW5kRXZlbnRzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLm9uKCd1cGRhdGUnLCAndHInLCB0aGlzLnNhdmVFZGl0KTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJ2lucHV0OmNoZWNrYm94Om5vdCgjc2VsZWN0LWFsbCknLCB0aGlzLnRvZ2dsZUNvbnRyb2xscyk7XG4gICAgICAgIHRoaXMuJGVsLm9uKCdjbGljaycsICcjc2VsZWN0LWFsbCcsIHRoaXMuc2VsZWN0QWxsKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJy51bmFzc2lnbi11c2VyJywgdGhpcy51c2Fzc2lnblNlbGVjdGVkKTtcbiAgICAgICAgdGhpcy4kZWwub24oJ2NsaWNrJywgJy5hdXRvLWFzc2lnbi1hbGwnLCB0aGlzLmF1dG9Bc3NpZ25BbGwpO1xuICAgICAgICB0aGlzLiRlbC5vbignY2xpY2snLCAnLm1ha2UtdXNlci1pbmFjdGl2ZScsIHRoaXMubWFrZVVzZXJJbmFjdGl2ZSk7XG4gICAgfSxcblxuICAgIGxvYWQ6IGZ1bmN0aW9uICgpIHtcblxuICAgICAgICB2YXIgam9pbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHRoaXMud29ybGRzLnNldFVzZXJzQ29sbGVjdGlvbih0aGlzLnVzZXJzKTtcbiAgICAgICAgICAgIHRoaXMud29ybGRzLmpvaW5Vc2VycygpO1xuICAgICAgICAgICAgdGhpcy5yZW5kZXIoKTtcbiAgICAgICAgfS5iaW5kKHRoaXMpO1xuXG4gICAgICAgIHJldHVybiAkLndoZW4oXG4gICAgICAgICAgICB0aGlzLndvcmxkcy5mZXRjaCgpLFxuICAgICAgICAgICAgdGhpcy51c2Vycy5mZXRjaCgpLFxuICAgICAgICAgICAgdGhpcy5wcm9qZWN0LmZldGNoKClcbiAgICAgICAgKS50aGVuKGpvaW4pO1xuXG4gICAgfSxcblxuICAgIHNhdmVFZGl0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMud29ybGRzLmZldGNoKClcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlQ29udHJvbHMoKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIGF1dG9Bc3NpZ25BbGw6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5fc2hvd1VwZGF0aW5nKCk7XG4gICAgICAgIHZhciBtYXhVc2VycyA9ICt0aGlzLiQoJyNtYXgtdXNlcnMnKS52YWwoKTtcbiAgICAgICAgcmV0dXJuIHRoaXMud29ybGRzLmF1dG9Bc3NpZ25BbGwoeyBtYXhVc2VyczogbWF4VXNlcnMgfSlcbiAgICAgICAgICAgIC50aGVuKHRoaXMuX2hpZGVVcGRhdGluZylcbiAgICAgICAgICAgIC5mYWlsKHRoaXMuX2hpZGVVcGRhdGluZylcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICB9LFxuXG4gICAgZ2V0U2VsZWN0ZWRJZHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuJCgndGJvZHkgOmNoZWNrYm94OmNoZWNrZWQnKS5tYXAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuICQodGhpcykuZGF0YSgnaWQnKTtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGZpbmRSb3dWaWV3czogZnVuY3Rpb24gKGlkcykge1xuICAgICAgICByZXR1cm4gXy5tYXAoaWRzLCBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJvd1ZpZXdzW2lkXTtcbiAgICAgICAgfSwgdGhpcyk7XG4gICAgfSxcblxuICAgIHVuYXNzaWduVXNlcnM6IGZ1bmN0aW9uIChpZHMpIHtcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIGRvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBkdGQucmVzb2x2ZSgpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIGZvciBub3cgd2UgbmVlZCB0byBzZXF1ZW5jZSB0aGUgY2FsbHMgdG8gdW5hc3NpZ24gdXNlcnMgZnJvbSB3b3JsZHNcbiAgICAgICAgdmFyIHF1ZXVlID0gbmV3IEFqYXhRdWV1ZSgpO1xuXG4gICAgICAgIF8uZWFjaChpZHMsIGZ1bmN0aW9uICh1c2VySWQpIHtcbiAgICAgICAgICAgIHZhciB1c2VyID0gdGhpcy51c2Vycy5nZXRCeUlkKHVzZXJJZCk7XG4gICAgICAgICAgICB1c2VyLnNldCgnd29ybGQnLCAnJyk7XG4gICAgICAgICAgICB1c2VyLnNldCgncm9sZScsICcnKTtcbiAgICAgICAgICAgIHF1ZXVlLmFkZChfLnBhcnRpYWwoXy5iaW5kKHRoaXMud29ybGRzLnVwZGF0ZVVzZXIsIHRoaXMud29ybGRzKSwgdXNlcikpO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICBxdWV1ZS5leGVjdXRlKHRoaXMpLnRoZW4oZG9uZSk7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIHVzYXNzaWduU2VsZWN0ZWQ6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgICB2YXIgaWRzID0gdGhpcy5nZXRTZWxlY3RlZElkcygpO1xuXG4gICAgICAgIHZhciBkb25lID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdGhpcy53b3JsZHMuZmV0Y2goKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkcy5qb2luVXNlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9oaWRlVXBkYXRpbmcoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuXG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdGhpcy5fc2hvd1VwZGF0aW5nKCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMudW5hc3NpZ25Vc2VycyhpZHMpLnRoZW4oZG9uZSk7XG4gICAgfSxcblxuICAgIG1ha2VVc2VySW5hY3RpdmU6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgdmFyIGlkcyA9IHRoaXMuZ2V0U2VsZWN0ZWRJZHMoKTtcbiAgICAgICAgdmFyIGRvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2xscygpO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgdmFyIG1ha2VVc2Vyc0luYWN0aXZlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJvd3MgPSB0aGlzLmZpbmRSb3dWaWV3cyhpZHMpO1xuICAgICAgICAgICAgLy8gZm9yIG5vdyB3ZSBuZWVkIHRvIHNlcXVlbmNlIHRoZSBjYWxscyB0byBwYXRjaCB0aGUgdXNlcnNcbiAgICAgICAgICAgIC8vIHNpbmNlIHRoZSBBUEkgY2FuIG9ubHkgb3BlcmF0ZSBvbiBvbmUgY2FsbCBwZXIgZ3JvdXAgYXQgYSB0aW1lXG4gICAgICAgICAgICB2YXIgcXVldWUgPSBuZXcgQWpheFF1ZXVlKCk7XG4gICAgICAgICAgICBfLmVhY2gocm93cywgZnVuY3Rpb24gKHZpZXcpIHtcbiAgICAgICAgICAgICAgICB2YXIgdXNlciA9IHZpZXcubW9kZWw7XG4gICAgICAgICAgICAgICAgcXVldWUuYWRkKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHZpZXcubWFrZUluYWN0aXZlKClcbiAgICAgICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VyLnJlbW92ZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZXcucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgICAgICBxdWV1ZS5leGVjdXRlKHRoaXMpLnRoZW4oZG9uZSk7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gdGhpcy51bmFzc2lnblVzZXJzKGlkcylcbiAgICAgICAgICAgIC50aGVuKG1ha2VVc2Vyc0luYWN0aXZlKTtcblxuXG4gICAgfSxcblxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiQoJ3RhYmxlIHRib2R5JykuZW1wdHkoKTtcbiAgICAgICAgdGhpcy5yZW5kZXJUYWJsZSgpO1xuICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2xscygpO1xuICAgIH0sXG5cbiAgICByZW5kZXJUYWJsZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLnJvd1ZpZXdzID0ge307XG4gICAgICAgIHZhciByb3dzID0gW107XG4gICAgICAgIHRoaXMudXNlcnMuZWFjaChmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgdmFyIHZpZXcgPSBuZXcgQXNzaWduZW1udFJvdyh7IG1vZGVsOiB1LCB3b3JsZHM6IHRoaXMud29ybGRzLCBwcm9qZWN0OiB0aGlzLnByb2plY3QgfSk7XG4gICAgICAgICAgICB0aGlzLnJvd1ZpZXdzW3UuZ2V0KCdpZCcpXSA9IHZpZXc7XG4gICAgICAgICAgICByb3dzLnB1c2godmlldy5yZW5kZXIoKS5lbCk7XG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHRoaXMuJCgndGFibGUgdGJvZHknKS5hcHBlbmQocm93cyk7XG4gICAgfSxcblxuXG4gICAgdXBkYXRlQ29udHJvbHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9sc0ZvclNlbGVjdGlvbigpO1xuICAgICAgICB0aGlzLnVwZGF0ZUF1dG9Bc3NpZ25CdXR0b24oKTtcbiAgICAgICAgdGhpcy51cGRhdGVTdGF0dXMoKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlU3RhdHVzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBpbmNvbHBsZXRlV29ybGRzID0gdGhpcy53b3JsZHMuZ2V0SW5jb21wbGV0ZVdvcmxkc0NvdW50KCk7XG4gICAgICAgIHZhciB1bmFzc2lnbmVkVXNlcnMgPSB0aGlzLnVzZXJzLmdldFVuYXNzaWduZWRVc2Vyc0NvdW50KCk7XG4gICAgICAgIHZhciB0b3RhbFdvcmxkcyA9IHRoaXMud29ybGRzLnNpemUoKTtcblxuICAgICAgICB2YXIgdXNlcnNUZXh0ID0gdW5hc3NpZ25lZFVzZXJzID8gdW5hc3NpZ25lZFVzZXJzID09PSAxID8gJzEgdXNlciBuZWVkcyBhc3NpZ25tZW50LicgOiB1bmFzc2lnbmVkVXNlcnMgKyAnIHVzZXJzIG5lZWQgYXNzaWdubWVudC4nIDogJ0FsbCB1c2VycyBoYXZlIGJlZW4gYXNzaWduZWQuJztcbiAgICAgICAgdmFyIHdvcmxkc1RleHQgPSAhdG90YWxXb3JsZHMgPyAnTm8gd29ybGRzIGhhdmUgYmVlbiBjcmVhdGVkLicgOiAhaW5jb2xwbGV0ZVdvcmxkcyA/ICdBbGwgd29ybGRzIGFyZSBjb21wbGV0ZS4nIDogaW5jb2xwbGV0ZVdvcmxkcyA9PT0gMSA/ICcxIGluY29tcGxldGUgd29ybGQgbmVlZHMgYXR0ZW50aW9uLicgOiBpbmNvbHBsZXRlV29ybGRzICsgJyBpbmNvbXBsZXRlIHdvcmxkcyBuZWVkIGF0dGVudGlvbi4nO1xuXG4gICAgICAgIHRoaXMuJCgnI3VzZXJzLXN0YXR1cyAudGV4dCcpLnRleHQodXNlcnNUZXh0KTtcbiAgICAgICAgdGhpcy4kKCcjd29ybGRzLXN0YXR1cyAudGV4dCcpLnRleHQod29ybGRzVGV4dCk7XG5cbiAgICAgICAgaWYgKHVuYXNzaWduZWRVc2Vycykge1xuICAgICAgICAgICAgdGhpcy4kKCcjdXNlcnMtc3RhdHVzJykuYWRkQ2xhc3MoJ2luY29tcGxldGUnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuJCgnI3VzZXJzLXN0YXR1cycpLnJlbW92ZUNsYXNzKCdpbmNvbXBsZXRlJyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaW5jb2xwbGV0ZVdvcmxkcyB8fCAhdG90YWxXb3JsZHMpIHtcbiAgICAgICAgICAgIHRoaXMuJCgnI3dvcmxkcy1zdGF0dXMnKS5hZGRDbGFzcygnaW5jb21wbGV0ZScpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy4kKCcjd29ybGRzLXN0YXR1cycpLnJlbW92ZUNsYXNzKCdpbmNvbXBsZXRlJyk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLiQoJy5zdGF0dXMtd2lkZ2V0JykuYWRkQ2xhc3MoJ3Zpc2libGUnKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlQ29udHJvbHNGb3JTZWxlY3Rpb246IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG51bVNlbGVjdGVkID0gdGhpcy4kKCd0Ym9keSA6Y2hlY2tib3g6Y2hlY2tlZCcpLmxlbmd0aDtcbiAgICAgICAgdGhpcy4kKCcuY29tcG9uZW50LmNvbnRyb2xzJylbbnVtU2VsZWN0ZWQgPyAnYWRkQ2xhc3MnIDogJ3JlbW92ZUNsYXNzJ10oJ3Zpc2libGUnKTtcbiAgICB9LFxuXG4gICAgdXBkYXRlQXV0b0Fzc2lnbkJ1dHRvbjogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgIGlmICh0aGlzLnByb2plY3QuaXNEeW5hbWljQXNzaWdubWVudCgpKSB7XG4gICAgICAgICAgICB2YXIgaGFzUm9sZXMgPSB0aGlzLnByb2plY3QuaGFzUm9sZXMoKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5zaW5nbGUnKS5oaWRlKCk7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scyAuZHluYW1pYycpLnNob3coKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5keW5hbWljLW5vLXJvbGVzLXRleHQnKVtoYXNSb2xlcyA/ICdoaWRlJyA6ICdzaG93J10oKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5uby1yb2xlcycpW2hhc1JvbGVzID8gJ2hpZGUnIDogJ3Nob3cnXSgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy4kKCcudGFibGUtY29udHJvbHMgLmR5bmFtaWMnKS5oaWRlKCk7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scyAuZHluYW1pYy1uby1yb2xlcy10ZXh0JykuaGlkZSgpO1xuICAgICAgICAgICAgdGhpcy4kKCcudGFibGUtY29udHJvbHMgLnNpbmdsZScpLnNob3coKTtcbiAgICAgICAgICAgIHRoaXMuJCgnLnRhYmxlLWNvbnRyb2xzIC5uby1yb2xlcycpLnNob3coKTtcblxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMudXNlcnMuYWxsVXNlcnNBc3NpZ25lZCgpKSB7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scycpLnJlbW92ZUNsYXNzKCd2aXNpYmxlJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLiQoJy50YWJsZS1jb250cm9scycpLmFkZENsYXNzKCd2aXNpYmxlJyk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgc2VsZWN0QWxsOiBmdW5jdGlvbiAoZSkge1xuICAgICAgICB0aGlzLiQoJ3Rib2R5IDpjaGVja2JveCcpLnByb3AoJ2NoZWNrZWQnLCBlLnRhcmdldC5jaGVja2VkKTtcbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9scygpO1xuICAgIH0sXG5cbiAgICB0b2dnbGVDb250cm9sbHM6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIHZhciB0b3RhbCA9IHRoaXMuJCgndGJvZHkgOmNoZWNrYm94Jyk7XG4gICAgICAgIHZhciBjaGVja2VkID0gdGhpcy4kKCd0Ym9keSA6Y2hlY2tib3g6Y2hlY2tlZCcpO1xuXG4gICAgICAgIGlmICh0b3RhbC5sZW5ndGggPT09IGNoZWNrZWQubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aGlzLiQoJyNzZWxlY3QtYWxsJykuYXR0cignY2hlY2tlZCcsICdjaGVja2VkJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLiQoJyNzZWxlY3QtYWxsJykucmVtb3ZlQXR0cignY2hlY2tlZCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy51cGRhdGVDb250cm9scygpO1xuICAgIH0sXG5cbiAgICBfc2hvd1VwZGF0aW5nOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuJGVsLmNzcyh7IG9wYWNpdHk6IDAuNCB9KTtcbiAgICB9LFxuXG4gICAgX2hpZGVVcGRhdGluZzogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLiRlbC5jc3MoeyBvcGFjaXR5OiAxIH0pO1xuICAgIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBBc3NpZ25tZW50OyIsIid1c2Ugc3RyaWN0JztcblxudmFyIEJhc2VDb2xsZWN0aW9uID0gZnVuY3Rpb24gKG1vZGVscywgb3B0aW9ucykge1xuICAgIHRoaXMuX21vZGVscyA9IFtdO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5fLmV4dGVuZChCYXNlQ29sbGVjdGlvbi5wcm90b3R5cGUsIHtcbiAgICBpZEF0dHJpYnV0ZTogJ2lkJyxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uIChtb2RlbHMsIG9wdGlvbnMpIHtcbiAgICB9LFxuXG4gICAgY3JlYXRlOiBmdW5jdGlvbiAoYXR0ciwgb3B0aW9ucykge1xuICAgICAgICB2YXIgbSA9IG5ldyB0aGlzLm1vZGVsKGF0dHIsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLnNldChtKTtcbiAgICAgICAgcmV0dXJuIG07XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAobW9kZWxzLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMuX21vZGVscy5sZW5ndGggPSAwO1xuICAgICAgICB0aGlzLnNldChtb2RlbHMpO1xuICAgIH0sXG5cbiAgICByZW1vdmU6IGZ1bmN0aW9uIChtb2RlbCkge1xuICAgICAgICBfLnJlbW92ZSh0aGlzLl9tb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbSA9PT0gbW9kZWw7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGRlbGV0ZSBtb2RlbC5jb2xsZWN0aW9uO1xuXG4gICAgICAgIHJldHVybiBtb2RlbDtcbiAgICB9LFxuXG4gICAgc2V0OiBmdW5jdGlvbiAobW9kZWxzKSB7XG4gICAgICAgIGlmICghbW9kZWxzKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBtb2RlbHMgPSBbXS5jb25jYXQobW9kZWxzKTtcblxuICAgICAgICBpZiAoIW1vZGVscy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIF8uZWFjaChtb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICBpZiAoIShtIGluc3RhbmNlb2YgdGhpcy5tb2RlbCkpIHtcbiAgICAgICAgICAgICAgICBtID0gbmV3IHRoaXMubW9kZWwobSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG0uY29sbGVjdGlvbiA9IHRoaXM7XG5cbiAgICAgICAgICAgIHRoaXMuX21vZGVscy5wdXNoKG0pO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICB0aGlzLnNvcnQuY2FsbCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gbW9kZWxzO1xuICAgIH0sXG5cbiAgICBzb3J0Rm46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHJldHVybiBiLl9kYXRhW3RoaXMuaWRBdHRyaWJ1dGVdIC0gYS5fZGF0YVt0aGlzLmlkQXR0cmlidXRlXTtcbiAgICB9LFxuXG4gICAgc29ydDogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLl9tb2RlbHMgPSB0aGlzLl9tb2RlbHMuc29ydCh0aGlzLnNvcnRGbi5iaW5kKHRoaXMpKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWxzO1xuICAgIH0sXG5cbiAgICBnZXRCeUlkOiBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgcmV0dXJuIF8uZmluZCh0aGlzLl9tb2RlbHMsIGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbS5nZXQodGhpcy5pZEF0dHJpYnV0ZSkgPT09IGlkO1xuICAgICAgICB9LCB0aGlzKTtcbiAgICB9LFxuXG4gICAgZWFjaDogZnVuY3Rpb24gKGNiLCBjdHgpIHtcbiAgICAgICAgcmV0dXJuIF8uZWFjaCh0aGlzLl9tb2RlbHMsIGNiLCBjdHggfHwgdGhpcyk7XG4gICAgfSxcblxuICAgIGFsbDogZnVuY3Rpb24gKGNiLCBjdHgpIHtcbiAgICAgICAgcmV0dXJuIF8uYWxsKHRoaXMuX21vZGVscywgY2IsIGN0eCB8fCB0aGlzKTtcbiAgICB9LFxuXG4gICAgdG9KU09OOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBfLmludm9rZSh0aGlzLl9tb2RlbHMsICd0b0pTT04nKTtcbiAgICB9LFxuXG4gICAgZmluZDogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiBfLmZpbmQodGhpcy5fbW9kZWxzLCBmbik7XG4gICAgfSxcblxuICAgIGZpbHRlcjogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiBfLmZpbHRlcih0aGlzLl9tb2RlbHMsIGZuKTtcbiAgICB9LFxuXG4gICAgc2l6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWxzLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgbWFwOiBmdW5jdGlvbiAoZm4sIGN0eCkge1xuICAgICAgICByZXR1cm4gXy5tYXAodGhpcy5fbW9kZWxzLCBmdW5jdGlvbiAobW9kZWwpIHtcbiAgICAgICAgICAgIHJldHVybiBmbi5jYWxsKGN0eCwgbW9kZWwudG9KU09OKCkpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgcGx1Y2s6IGZ1bmN0aW9uIChmaWVsZCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tYXAoZnVuY3Rpb24gKG0pIHtcbiAgICAgICAgICAgIHJldHVybiBtW2ZpZWxkXTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBCYXNlQ29sbGVjdGlvbjsiLCIndXNlIHN0cmljdCc7XG5cblxudmFyIEJhc2VNb2RlbCA9IGZ1bmN0aW9uIChhdHRyLCBvcHRpb25zKSB7XG4gICAgYXR0ciA9IF8uZGVmYXVsdHMoe30sIGF0dHIsIF8ucmVzdWx0KHRoaXMsICdkZWZhdWx0cycpKTtcbiAgICB0aGlzLl9kYXRhID0ge307XG4gICAgdGhpcy5zZXQoYXR0ciwgb3B0aW9ucyk7XG4gICAgdGhpcy5pbml0aWFsaXplLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5fLmV4dGVuZChCYXNlTW9kZWwucHJvdG90eXBlLCB7XG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24gKGF0dHIsIG9wdGlvbnMpIHtcblxuICAgIH0sXG5cbiAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbCwgb3B0aW9ucykge1xuXG4gICAgICAgIGlmIChrZXkgPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgYXR0cnMgPSBrZXk7XG4gICAgICAgICAgICBvcHRpb25zID0gdmFsO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWw7XG4gICAgICAgIH1cblxuICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICBfLmV4dGVuZCh0aGlzLl9kYXRhLCBhdHRycyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIGdldDogZnVuY3Rpb24gKGtleSwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5fZGF0YVtrZXldO1xuICAgIH0sXG5cbiAgICByZW1vdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHRoaXMuY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhpcy5jb2xsZWN0aW9uLnJlbW92ZSh0aGlzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICB0b0pTT046IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2RhdGE7XG4gICAgfSxcblxuICAgIHBpY2s6IGZ1bmN0aW9uIChrZXlzKSB7XG4gICAgICAgIHJldHVybiBfLnBpY2sodGhpcy5fZGF0YSwga2V5cyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBCYXNlTW9kZWw7IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgZW52ID0ge1xuICAgIGFjY291bnQ6ICcnLFxuICAgIHByb2plY3Q6ICcnLFxuICAgIGdyb3VwOiAnJyxcbiAgICBncm91cElkOiAnJyxcbiAgICB0b2tlbjogJycsXG4gICAgc2VydmVyOiB7XG4gICAgICAgIGhvc3Q6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgcHJvdG9jb2w6ICdodHRwcydcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBzZXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGVudiA9IF8ubWVyZ2UoZW52LCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBlbnY7XG4gICAgfVxufTsiLCIoZnVuY3Rpb24gKCkge1xuICAgICd1c2Ugc3RyaWN0JztcbiAgICB2YXIgQXBwID0gcmVxdWlyZSgnLi9hc3NpZ25tZW50LmpzJyk7XG5cbiAgICB3aW5kb3cuZm9yaW8gPSB3aW5kb3cuZm9yaW8gfHwge307XG4gICAgd2luZG93LmZvcmlvLk11bHRpcGxheWVyQXNzaWdubWVudENvbXBvbmVudCA9IEFwcDtcbn0pKCk7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBzZXJ2aWNlTG9jYXRvciA9IHJlcXVpcmUoJy4vc2VydmljZS1sb2NhdG9yJyk7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG4vLyB2YXIgX19zdXBlciA9IEJhc2UucHJvdG90eXBlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG5cbiAgICBpc0R5bmFtaWNBc3NpZ25tZW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldCgnd29ybGRzJykgPT09ICdkeW5hbWljJztcbiAgICB9LFxuXG4gICAgaGFzUm9sZXM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHJvbGVzID0gdGhpcy5nZXQoJ3JvbGVzJyk7XG4gICAgICAgIHJldHVybiByb2xlcyAmJiAhIXJvbGVzLmxlbmd0aDtcbiAgICB9LFxuXG4gICAgZmV0Y2g6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGFwaSA9IHNlcnZpY2VMb2NhdG9yLndvcmxkQXBpKCk7XG5cbiAgICAgICAgcmV0dXJuIGFwaS5nZXRQcm9qZWN0U2V0dGluZ3MoKS50aGVuKGZ1bmN0aW9uIChzZXR0aW5ncykge1xuICAgICAgICAgICAgdGhpcy5zZXQoc2V0dGluZ3MpO1xuICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cbn0pOyIsIid1c2Ugc3RyaWN0JztcblxudmFyIGVudiA9IHJlcXVpcmUoJy4vZGVmYXVsdHMuanMnKTtcblxudmFyIGNhY2hlID0ge307XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIHdvcmxkQXBpOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICghY2FjaGUud29ybGRBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLndvcmxkQXBpID0gbmV3IEYuc2VydmljZS5Xb3JsZChlbnYuZ2V0KCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlLndvcmxkQXBpO1xuICAgIH0sXG5cbiAgICBtZW1iZXJBcGk6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKCFjYWNoZS5tZW1iZXJBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLm1lbWJlckFwaSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKF8ucGljayhlbnYuZ2V0KCksIFsnZ3JvdXBJZCcsICdzZXJ2ZXInXSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhY2hlLm1lbWJlckFwaTtcbiAgICB9LFxuXG4gICAgdXNlckFwaTogZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoIWNhY2hlLnVzZXJBcGkpIHtcbiAgICAgICAgICAgIGNhY2hlLnVzZXJBcGkgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoXy5waWNrKGVudi5nZXQoKSwgWydhY2NvdW50JywgJ3NlcnZlciddKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gY2FjaGUudXNlckFwaTtcbiAgICB9XG59OyIsImV4cG9ydHNbXCJlZGl0LXVzZXItcm93XCJdID0gZnVuY3Rpb24ob2JqKSB7XG5vYmogfHwgKG9iaiA9IHt9KTtcbnZhciBfX3QsIF9fcCA9ICcnLCBfX2UgPSBfLmVzY2FwZSwgX19qID0gQXJyYXkucHJvdG90eXBlLmpvaW47XG5mdW5jdGlvbiBwcmludCgpIHsgX19wICs9IF9fai5jYWxsKGFyZ3VtZW50cywgJycpIH1cbndpdGggKG9iaikge1xuX19wICs9ICc8dGQ+PGlucHV0IHR5cGU9XCJjaGVja2JveFwiIGNsYXNzPVwic2VsZWN0XCIgZGF0YS1pZD1cIicgK1xuKChfX3QgPSAoIGlkICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiPC90ZD5cXG48dGQ+PC90ZD5cXG48dGQ+XFxuICAgIDxzZWxlY3QgbmFtZT1cIndvcmxkc1wiIGNsYXNzPVwiZm9ybS1jb250cm9sXCIgZGF0YS1maWVsZD1cIndvcmxkXCI+XFxuXFxuICAgICc7XG4gXy5lYWNoKHdvcmxkcywgZnVuY3Rpb24gKHcpIHsgO1xuX19wICs9ICdcXG4gICAgICAgIDxvcHRpb24gdmFsdWU9XCInICtcbigoX190ID0gKCB3ICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiICcgK1xuKChfX3QgPSAoIHcgPT09IHdvcmxkID8gJ3NlbGVjdGVkJyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJz4nICtcbigoX190ID0gKCB3ICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvb3B0aW9uPlxcbiAgICAnO1xuIH0pOyA7XG5fX3AgKz0gJ1xcbiAgICAgICAgPG9wdGlvbiB2YWx1ZT1cIicgK1xuKChfX3QgPSAoIG5ld1dvcmxkICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiIGNsYXNzPVwibmV3LXdvcmxkLXRleHRcIj48aT4nICtcbigoX190ID0gKCBuZXdXb3JsZCApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbicgLSBOZXcgLTwvaT48L29wdGlvbj5cXG4gICAgPC9zZWxlY3Q+XFxuPC90ZD5cXG48dGQ+XFxuICAgIDxzZWxlY3QgbmFtZT1cInJvbGVzXCIgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIiBkYXRhLWZpZWxkPVwicm9sZVwiPlxcbiAgICAnO1xuIF8uZWFjaChyb2xlcywgZnVuY3Rpb24gKHIpIHsgO1xuX19wICs9ICdcXG4gICAgICAgIDxvcHRpb24gdmFsdWU9XCInICtcbigoX190ID0gKCByICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiICcgK1xuKChfX3QgPSAoIHIgPT09IHJvbGUgPyAnc2VsZWN0ZWQnIDogJycgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPicgK1xuKChfX3QgPSAoIHIgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC9vcHRpb24+XFxuICAgICc7XG4gfSk7IDtcbl9fcCArPSAnXFxuXFxuICAgICc7XG4gXy5lYWNoKG9wdGlvbmFsUm9sZXMsIGZ1bmN0aW9uIChyKSB7IDtcbl9fcCArPSAnXFxuICAgICAgICA8b3B0aW9uIHZhbHVlPVwiJyArXG4oKF9fdCA9ICggciApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbidcIiAnICtcbigoX190ID0gKCByID09PSByb2xlID8gJ3NlbGVjdGVkJyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJz4nICtcbigoX190ID0gKCByICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJyA8aT4oT3B0aW9uYWwpPC9pPjwvb3B0aW9uPlxcbiAgICAnO1xuIH0pOyA7XG5fX3AgKz0gJ1xcbiAgICA8L3NlbGVjdD5cXG48L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCBsYXN0TmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCB1c2VyTmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCAhd29ybGQgPyAnPGVtIGNsYXNzPVwiZi1pY29uIGYtd2FybmluZ1wiPjwvZW0+JyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvdGQ+XFxuPHRkIGNsYXNzPVwiYWN0aW9uc1wiPlxcbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi1wcmltYXJ5IGJ0bi10b29scyBidG4tc2F2ZSBzYXZlXCI+U2F2ZTwvYnV0dG9uPlxcbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi10b29scyBidG4tY2FuY2VsIGNhbmNlbFwiPkNhbmNlbDwvYnV0dG9uPlxcbjwvdGQ+JztcblxufVxucmV0dXJuIF9fcFxufTtcbmV4cG9ydHNbXCJ1c2VyLXJvd1wiXSA9IGZ1bmN0aW9uKG9iaikge1xub2JqIHx8IChvYmogPSB7fSk7XG52YXIgX190LCBfX3AgPSAnJywgX19lID0gXy5lc2NhcGU7XG53aXRoIChvYmopIHtcbl9fcCArPSAnPHRkPjxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBjbGFzcz1cInNlbGVjdFwiIGRhdGEtaWQ9XCInICtcbigoX190ID0gKCBpZCkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJ1wiPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggIWlzV29ybGRDb21wbGV0ZSA/ICc8ZW0gY2xhc3M9XCJmLWljb24gZi13YXJuaW5nXCI+PC9lbT4nIDogJycgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggd29ybGQgKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nPC90ZD5cXG48dGQ+JyArXG4oKF9fdCA9ICggcm9sZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCBsYXN0TmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCB1c2VyTmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICtcbic8L3RkPlxcbjx0ZD4nICtcbigoX190ID0gKCAhd29ybGQgPyAnPGVtIGNsYXNzPVwiZi1pY29uIGYtd2FybmluZ1wiPjwvZW0+JyA6ICcnICkpID09IG51bGwgPyAnJyA6IF9fdCkgK1xuJzwvdGQ+XFxuPHRkIGNsYXNzPVwiYWN0aW9uc1wiPjxidXR0b24gY2xhc3M9XCJidG4gZWRpdCBidG4tZWRpdCBidG4tdG9vbHMgYXV0by1oaWRlXCI+RWRpdDwvYnV0dG9uPjwvdGQ+JztcblxufVxucmV0dXJuIF9fcFxufTsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLW1vZGVsJyk7XG52YXIgc2VydmljZUxvY2F0b3IgPSByZXF1aXJlKCcuL3NlcnZpY2UtbG9jYXRvcicpO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBkZWZhdWx0czoge1xuICAgICAgICB3b3JsZDogJycsXG4gICAgICAgIHJvbGU6ICcnLFxuICAgICAgICBhY3RpdmU6IHRydWUsXG4gICAgICAgIGlzV29ybGRDb21wbGV0ZTogdHJ1ZSxcbiAgICAgICAgZmlyc3ROYW1lOiAnJyxcbiAgICAgICAgbGFzdE5hbWU6ICcnXG4gICAgfSxcblxuICAgIG1ha2VBY3RpdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG1lbWJlckFwaSA9IHNlcnZpY2VMb2NhdG9yLm1lbWJlckFwaSgpO1xuICAgICAgICB2YXIgcGFyYW1zID0ge1xuICAgICAgICAgICAgdXNlcklkOiB0aGlzLmdldCgnaWQnKSxcbiAgICAgICAgICAgIGdyb3VwSWQ6IHRoaXMuZ2V0KCdncm91cElkJylcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLmdldCgnYWN0aXZlJyk7XG4gICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCB0cnVlKTtcblxuICAgICAgICByZXR1cm4gbWVtYmVyQXBpLm1ha2VVc2VyQWN0aXZlKHBhcmFtcylcbiAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyByZXZlcnQgdGhlIGNoYW5nZVxuICAgICAgICAgICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBvcmlnaW5hbCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBtYWtlSW5hY3RpdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG1lbWJlckFwaSA9IHNlcnZpY2VMb2NhdG9yLm1lbWJlckFwaSgpO1xuICAgICAgICB2YXIgcGFyYW1zID0ge1xuICAgICAgICAgICAgdXNlcklkOiB0aGlzLmdldCgnaWQnKSxcbiAgICAgICAgICAgIGdyb3VwSWQ6IHRoaXMuZ2V0KCdncm91cElkJylcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLmdldCgnYWN0aXZlJyk7XG4gICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBmYWxzZSk7XG5cbiAgICAgICAgcmV0dXJuIG1lbWJlckFwaS5tYWtlVXNlckluYWN0aXZlKHBhcmFtcylcbiAgICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyByZXZlcnQgdGhlIGNoYW5nZVxuICAgICAgICAgICAgICAgIHRoaXMuc2V0KCdhY3RpdmUnLCBvcmlnaW5hbCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cblxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcblxudmFyIE1vZGVsID0gcmVxdWlyZSgnLi91c2VyLW1vZGVsJyk7XG52YXIgQmFzZSA9IHJlcXVpcmUoJy4vYmFzZS1jb2xsZWN0aW9uJyk7XG52YXIgZW52ID0gcmVxdWlyZSgnLi9kZWZhdWx0cycpO1xudmFyIHNlcnZpY2VMb2NhdG9yID0gcmVxdWlyZSgnLi9zZXJ2aWNlLWxvY2F0b3InKTtcblxuXG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBtb2RlbDogTW9kZWwsXG5cbiAgICBzb3J0Rm46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHZhciBhdyA9IGEuZ2V0KCd3b3JsZCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIHZhciBidyA9IGIuZ2V0KCd3b3JsZCcpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIGlmIChhdyAhPT0gYncpIHtcbiAgICAgICAgICAgIHJldHVybiBhdyA8IGJ3ID8gLTEgOiAxO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGIuZ2V0KCd1c2VyTmFtZScpID4gYS5nZXQoJ3VzZXJOYW1lJykgPyAtMSA6IDE7XG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgJC5hamF4U2V0dXAoe1xuICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgIEF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIGVudi5nZXQoKS50b2tlblxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgYWxsVXNlcnNBc3NpZ25lZDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5hbGwoZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgIHJldHVybiAhIXUuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0VW5hc3NpZ25lZFVzZXJzQ291bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmlsdGVyKGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICByZXR1cm4gIXUuZ2V0KCd3b3JsZCcpO1xuICAgICAgICB9KS5sZW5ndGg7XG4gICAgfSxcblxuICAgIGZldGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBncm91cElkID0gZW52LmdldCgpLmdyb3VwSWQ7XG5cbiAgICAgICAgdmFyIGdldEdyb3VwVXNlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgbWVtYmVyQXBpID0gc2VydmljZUxvY2F0b3IubWVtYmVyQXBpKCk7XG4gICAgICAgICAgICB2YXIgdXNlckFwaSA9IHNlcnZpY2VMb2NhdG9yLnVzZXJBcGkoKTtcblxuICAgICAgICAgICAgdmFyIGxvYWRHcm91cE1lbWJlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1lbWJlckFwaS5nZXRHcm91cERldGFpbHMoKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBsb2FkVXNlcnNJbmZvID0gZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgdmFyIG5vbkZhY0FuZEFjdGl2ZSA9IGZ1bmN0aW9uICh1KSB7IHJldHVybiB1LmFjdGl2ZSAmJiB1LnJvbGUgIT09ICdmYWNpbGl0YXRvcic7IH07XG4gICAgICAgICAgICAgICAgdmFyIHVzZXJzID0gXy5wbHVjayhfLmZpbHRlcihncm91cC5tZW1iZXJzLCBub25GYWNBbmRBY3RpdmUpLCAndXNlcklkJyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVzZXJBcGkuZ2V0KHsgaWQ6IHVzZXJzIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgcmV0dXJuIGxvYWRHcm91cE1lbWJlcnMoKVxuICAgICAgICAgICAgICAgIC50aGVuKGxvYWRVc2Vyc0luZm8pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgZ2V0R3JvdXBVc2VycygpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAodXNlcnMpIHtcbiAgICAgICAgICAgICAgICB1c2VycyA9IF8ubWFwKHVzZXJzLCBmdW5jdGlvbiAodSkgeyByZXR1cm4gXy5leHRlbmQodSwgeyBncm91cElkOiBncm91cElkIH0pOyB9KTtcbiAgICAgICAgICAgICAgICBfdGhpcy5zZXQodXNlcnMpO1xuICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHVzZXJzKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgIH1cblxufSk7XG4iLCIndXNlIHN0cmljdCc7XG52YXIgc2VydmljZUxvY2F0b3IgPSByZXF1aXJlKCcuL3NlcnZpY2UtbG9jYXRvcicpO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIEJhc2UgPSByZXF1aXJlKCcuL2Jhc2UtbW9kZWwnKTtcbnZhciBfX3N1cGVyID0gQmFzZS5wcm90b3R5cGU7XG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcblxuICAgIGRlZmF1bHRzOiB7XG4gICAgICAgIHVzZXJzOiBudWxsLFxuICAgICAgICBtb2RlbDogJ21vZGVsLmVxbidcbiAgICB9LFxuXG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICBfX3N1cGVyLmluaXRpYWxpemUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcblxuICAgICAgICB0aGlzLl9kYXRhLnVzZXJzID0gdGhpcy5fZGF0YS51c2VycyB8fCBbXTtcblxuICAgICAgICB0aGlzLl93b3JsZEFwaSA9IHNlcnZpY2VMb2NhdG9yLndvcmxkQXBpKCk7XG5cbiAgICAgICAgdmFyIGlkID0gdGhpcy5nZXQoJ2lkJyk7XG4gICAgICAgIGlmIChpZCkge1xuICAgICAgICAgICAgdGhpcy5fd29ybGRBcGkudXBkYXRlQ29uZmlnKHsgZmlsdGVyOiBpZCB9KTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBhZGRVc2VyOiBmdW5jdGlvbiAodXNlcikge1xuICAgICAgICB2YXIgdXNlcnMgPSB0aGlzLmdldCgndXNlcnMnKTtcbiAgICAgICAgdXNlcnMucHVzaCh1c2VyKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5zYXZlKCk7XG4gICAgfSxcblxuICAgIHJlbW92ZVVzZXI6IGZ1bmN0aW9uICh1c2VyKSB7XG4gICAgICAgIHZhciBpZCA9IHRoaXMuZ2V0KCdpZCcpO1xuICAgICAgICB2YXIgY2hlY2tXb3JsZCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmICghdGhpcy5nZXQoJ3VzZXJzJykubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5yZW1vdmUoKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fd29ybGRBcGkudXBkYXRlQ29uZmlnKHsgZmlsdGVyOiBpZCB9KS5kZWxldGUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfS5iaW5kKHRoaXMpO1xuXG4gICAgICAgIF8ucmVtb3ZlKHRoaXMuZ2V0KCd1c2VycycpLCBmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgcmV0dXJuIHUuZ2V0KCdpZCcpID09PSB1c2VyLmdldCgnaWQnKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuX3dvcmxkQXBpXG4gICAgICAgICAgICAudXBkYXRlQ29uZmlnKHsgZmlsdGVyOiBpZCB9KVxuICAgICAgICAgICAgLnJlbW92ZVVzZXIoeyB1c2VySWQ6IHVzZXIuZ2V0KCdpZCcpIH0pXG4gICAgICAgICAgICAudGhlbihjaGVja1dvcmxkKTtcbiAgICB9LFxuXG4gICAgc2F2ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB2YXIgbWFwVXNlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gXy5tYXAodGhpcy5nZXQoJ3VzZXJzJyksIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgdmFyIHJlcyA9IHsgdXNlcklkOiB1LmdldCgnaWQnKSB9O1xuICAgICAgICAgICAgICAgIHZhciByb2xlID0gdS5nZXQoJ3JvbGUnKTtcblxuICAgICAgICAgICAgICAgIGlmIChyb2xlKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlcy5yb2xlID0gcm9sZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gcmVzO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICB2YXIgY3JlYXRlV29ybGQgPSBfLnBhcnRpYWwodGhpcy5fd29ybGRBcGkuY3JlYXRlLCB0aGlzLnBpY2soWydtb2RlbCcsICduYW1lJywgJ21pblVzZXJzJ10pKTtcbiAgICAgICAgdmFyIGFkZFVzZXJzID0gXy5wYXJ0aWFsKF90aGlzLl93b3JsZEFwaS5hZGRVc2VycywgbWFwVXNlcnMoKSwgeyBmaWx0ZXI6IF90aGlzLmdldCgnaWQnKSB9KTtcbiAgICAgICAgdmFyIHNhdmVkVXNlcnMgPSB0aGlzLmdldCgndXNlcnMnKTtcbiAgICAgICAgaWYgKHRoaXMuaXNOZXcoKSkge1xuICAgICAgICAgICAgLy8gd2UgbmVlZCB0byBjcmVhdGUgdGhlIHdvcmxkIGluIHRoZSBBUEkgYW5kIHRoZW4gYWRkIHRoZSB1c2Vyc1xuICAgICAgICAgICAgcmV0dXJuIGNyZWF0ZVdvcmxkKClcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgX3RoaXMuc2V0KHdvcmxkKTtcbiAgICAgICAgICAgICAgICAgICAgX3RoaXMuX3dvcmxkQXBpLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogd29ybGQuaWQgfSk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAudGhlbihhZGRVc2VycylcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAodXNlcnMpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gc2luY2Ugd2UgcmUtc2V0IHRoZSB3b3JsZCwgcmUtc2V0IHRoZSB1c2Vyc1xuICAgICAgICAgICAgICAgICAgICBfdGhpcy5zZXQoJ3VzZXJzJywgc2F2ZWRVc2Vycyk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyB0aGUgd29ybGQgaXMgYWxyZWFkeSBjcmVhdGVkIGp1c3QgYWRkIHRoZSB1c2Vyc1xuICAgICAgICAgICAgcmV0dXJuIGFkZFVzZXJzKCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgaXNOZXc6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuICF0aGlzLmdldCgnbGFzdE1vZGlmaWVkJyk7XG4gICAgfVxuXG59KTsiLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBNb2RlbCA9IHJlcXVpcmUoJy4vd29ybGQtbW9kZWwnKTtcbnZhciBVc2VyTW9kZWwgPSByZXF1aXJlKCcuL3VzZXItbW9kZWwnKTtcbnZhciBzZXJ2aWNlTG9jYXRvciA9IHJlcXVpcmUoJy4vc2VydmljZS1sb2NhdG9yJyk7XG5cbnZhciBCYXNlID0gcmVxdWlyZSgnLi9iYXNlLWNvbGxlY3Rpb24nKTtcbnZhciBfX3N1cGVyID0gQmFzZS5wcm90b3R5cGU7XG5cbnZhciBkb25lRm4gPSBmdW5jdGlvbiAoZHRkLCBhZnRlcikge1xuICAgIHJldHVybiBfLmFmdGVyKGFmdGVyLCBkdGQucmVzb2x2ZSk7XG59O1xuXG52YXIgd29ybGRBcGk7XG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBtb2RlbDogTW9kZWwsXG5cbiAgICBpbml0aWFsaXplOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIF9fc3VwZXIuaW5pdGlhbGl6ZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICB3b3JsZEFwaSA9IHNlcnZpY2VMb2NhdG9yLndvcmxkQXBpKCk7XG4gICAgfSxcblxuICAgIGF1dG9Bc3NpZ25BbGw6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiB3b3JsZEFwaS5hdXRvQXNzaWduKG9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGRzKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5yZXNldCh0aGlzLnBhcnNlKHdvcmxkcykpO1xuICAgICAgICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICB9LFxuXG4gICAgZ2V0SW5jb21wbGV0ZVdvcmxkc0NvdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmZpbHRlcihmdW5jdGlvbiAodykge1xuICAgICAgICAgICAgcmV0dXJuICF3LmdldCgnY29tcGxldGUnKTtcbiAgICAgICAgfSkubGVuZ3RoO1xuICAgIH0sXG5cbiAgICB1cGRhdGVVc2VyOiBmdW5jdGlvbiAodXNlcikge1xuICAgICAgICB2YXIgd29ybGROYW1lID0gdXNlci5nZXQoJ3dvcmxkJyk7XG4gICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgIHZhciBwcmV2V29ybGQgPSB0aGlzLmdldFdvcmxkQnlVc2VyKHVzZXIpO1xuICAgICAgICB2YXIgY3VyV29ybGQgPSB0aGlzLmdldE9yQ3JlYXRlV29ybGQod29ybGROYW1lKTtcbiAgICAgICAgdmFyIGRvbmUgPSBkb25lRm4oZHRkLCAxKTtcblxuICAgICAgICAvLyBjaGVjayBpZiB0aGVyZSdzIGFueXRoaW5nIHRvIGRvXG4gICAgICAgIGlmICghcHJldldvcmxkICYmICFjdXJXb3JsZCkge1xuICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZXNvbHZlKCkucHJvbWlzZSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHByZXZXb3JsZCkge1xuICAgICAgICAgICAgcHJldldvcmxkLnJlbW92ZVVzZXIodXNlcilcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChjdXJXb3JsZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGN1cldvcmxkLmFkZFVzZXIodXNlcik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC50aGVuKGRvbmUpO1xuICAgICAgICB9IGVsc2UgaWYgKGN1cldvcmxkKSB7XG4gICAgICAgICAgICBjdXJXb3JsZC5hZGRVc2VyKHVzZXIpXG4gICAgICAgICAgICAgICAgLnRoZW4oZG9uZSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgZ2V0T3JDcmVhdGVXb3JsZDogZnVuY3Rpb24gKHdvcmxkTmFtZSkge1xuICAgICAgICBpZiAoIXdvcmxkTmFtZSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHdvcmxkID0gdGhpcy5nZXRXb3JkQnlOYW1lKHdvcmxkTmFtZSk7XG5cbiAgICAgICAgaWYgKCF3b3JsZCkge1xuICAgICAgICAgICAgd29ybGQgPSB0aGlzLmNyZWF0ZSh7IG5hbWU6IHdvcmxkTmFtZSB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB3b3JsZDtcbiAgICB9LFxuXG4gICAgZ2V0V29yZEJ5TmFtZTogZnVuY3Rpb24gKHdvcmxkTmFtZSkge1xuICAgICAgICByZXR1cm4gdGhpcy5maW5kKGZ1bmN0aW9uICh3b3JsZCkge1xuICAgICAgICAgICAgcmV0dXJuIHdvcmxkLmdldCgnbmFtZScpID09PSB3b3JsZE5hbWU7XG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICBnZXRXb3JsZEJ5VXNlcjogZnVuY3Rpb24gKHVzZXIpIHtcbiAgICAgICAgaWYgKCF1c2VyLmdldCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdnZXRXb3JsZEJ5VXNlciBleHBlY3RlcyBhIG1vZGVsICgnICsgdXNlciArICcpJyk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgaWQgPSB1c2VyLmdldCgnaWQnKTtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0V29ybGRCeVVzZXJJZChpZCk7XG4gICAgfSxcblxuICAgIGdldFdvcmxkQnlVc2VySWQ6IGZ1bmN0aW9uICh1c2VySWQpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmluZChmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgIHJldHVybiBfLmZpbmQod29ybGQuZ2V0KCd1c2VycycpLCBmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB1LmdldCgnaWQnKSA9PT0gdXNlcklkO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICBnZXRXb3JsZE5hbWVzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnBsdWNrKCduYW1lJyk7XG4gICAgfSxcblxuICAgIGdldE5leHRXb3JsZE5hbWU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHBhZCA9IGZ1bmN0aW9uIChudW0sIHBsYWNlcykge1xuICAgICAgICAgICAgdmFyIHplcm9zID0gJzAwMDAwMDAwMDAwMDAwMDAwMCc7XG4gICAgICAgICAgICB2YXIgZGlnaXRzID0gbnVtLnRvU3RyaW5nKCkubGVuZ3RoO1xuICAgICAgICAgICAgdmFyIG5lZWRlZCA9IHBsYWNlcyAtIGRpZ2l0cztcbiAgICAgICAgICAgIHJldHVybiB6ZXJvcy5zdWJzdHIoMCwgbmVlZGVkKSArIG51bTtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgd29ybGRzID0gdGhpcy5nZXRXb3JsZE5hbWVzKCk7XG5cbiAgICAgICAgaWYgKCF3b3JsZHMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gJ1dvcmxkMDAxJztcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBwcm9wZXJOYW1lcyA9IF8uZmlsdGVyKHdvcmxkcywgZnVuY3Rpb24gKHcpIHsgcmV0dXJuIC9Xb3JsZFxcZFxcZFxcZC8udGVzdCh3KTsgfSkuc29ydCgpO1xuICAgICAgICB2YXIgbGFzdFdvcmxkID0gcHJvcGVyTmFtZXNbcHJvcGVyTmFtZXMubGVuZ3RoIC0gMV07XG4gICAgICAgIHZhciBudW1Xb3JsZCA9ICtsYXN0V29ybGQubWF0Y2goL1dvcmxkKFxcZFxcZFxcZCkvKVsxXTtcbiAgICAgICAgcmV0dXJuICdXb3JsZCcgKyBwYWQobnVtV29ybGQgKyAxLCAzKTtcbiAgICB9LFxuXG4gICAgc2V0VXNlcnNDb2xsZWN0aW9uOiBmdW5jdGlvbiAodXNlcnNDb2xsZWN0aW9uKSB7XG4gICAgICAgIHRoaXMudXNlcnNDb2xsZWN0aW9uID0gdXNlcnNDb2xsZWN0aW9uO1xuICAgIH0sXG5cbiAgICBqb2luVXNlcnM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHVzZXJzSGFzaCA9IHt9O1xuICAgICAgICB2YXIgdXNlcnNDb2xsZWN0aW9uID0gdGhpcy51c2Vyc0NvbGxlY3Rpb247XG4gICAgICAgIHVzZXJzQ29sbGVjdGlvbi5lYWNoKGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICB1LnNldCh7IGlzV29ybGRDb21wbGV0ZTogdHJ1ZSB9KTtcbiAgICAgICAgICAgIHJldHVybiAodXNlcnNIYXNoW3UuZ2V0KCdpZCcpXSA9IHUpO1xuICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLmVhY2goZnVuY3Rpb24gKHcsIGkpIHtcbiAgICAgICAgICAgIHZhciBuYW1lID0gdy5nZXQoJ25hbWUnKTtcbiAgICAgICAgICAgIHZhciBpc0NvbXBsZXRlID0gdy5nZXQoJ2NvbXBsZXRlJyk7XG4gICAgICAgICAgICB3LnNldCh7IGluZGV4OiBpLCBuYW1lOiBuYW1lIHx8IChpICsgMSkgKyAnJyB9KTtcbiAgICAgICAgICAgIF8uZWFjaCh3LmdldCgndXNlcnMnKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgICAgICBpZiAodXNlcnNIYXNoW3UuZ2V0KCd1c2VySWQnKV0pIHtcbiAgICAgICAgICAgICAgICAgICAgdXNlcnNIYXNoW3UuZ2V0KCd1c2VySWQnKV0uc2V0KHsgd29ybGQ6IG5hbWUsIHJvbGU6IHUuZ2V0KCdyb2xlJyksIGlzV29ybGRDb21wbGV0ZTogaXNDb21wbGV0ZSB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSwgdGhpcyk7XG5cbiAgICAgICAgdXNlcnNDb2xsZWN0aW9uLnNvcnQoKTtcbiAgICB9LFxuXG4gICAgZmV0Y2g6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHdvcmxkQXBpLmxpc3QoKVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkcykge1xuICAgICAgICAgICAgICAgIHRoaXMucmVzZXQodGhpcy5wYXJzZSh3b3JsZHMpKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfSxcblxuICAgIHBhcnNlOiBmdW5jdGlvbiAod29ybGRzKSB7XG4gICAgICAgIGlmICh3b3JsZHMubGVuZ3RoKSB7XG4gICAgICAgICAgICB3b3JsZHMgPSBfLm1hcCh3b3JsZHMsIGZ1bmN0aW9uICh3KSB7XG4gICAgICAgICAgICAgICAgdmFyIHVzZXJzID0gXy5tYXAody51c2VycywgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gaW4gdGhlIHdvcmxkIGFwaSB1c2VycyBJZHMgY29tZXMgYXMgdXNlcklkXG4gICAgICAgICAgICAgICAgICAgIC8vIG1ha2Ugc3VyZSB3ZSBhZGQgaXQgYXMgaWQgc28gd2UgY2FuIHVzZSB0aGVcbiAgICAgICAgICAgICAgICAgICAgLy8gc2FtZSBjb2RlIHRvIGFjY2VzcyBtb2RlbHMgdGhhdCBjb21lIGZyb20gdGhlXG4gICAgICAgICAgICAgICAgICAgIC8vIG1lbWJlci9sb2NhbCBhcGkgYXMgd2l0aCB0aGUgd29ybGQgYXBpXG4gICAgICAgICAgICAgICAgICAgIHUuaWQgPSB1LnVzZXJJZDtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBVc2VyTW9kZWwodSk7XG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICB3LnVzZXJzID0gdXNlcnM7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gdztcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHdvcmxkcztcbiAgICB9XG59KTtcbiIsIid1c2Ugc3RyaWN0JztcblxuLyoqXG4qIFV0aWxpdHkgY2xhc3MgdG8gbWFrZSBhamF4IGNhbGxzIHNlcXVlbmNpYWxcbiovXG5mdW5jdGlvbiBBamF4UXVldWUgKCkge1xuICAgIHRoaXMucXVldWUgPSBbXTtcbn1cblxuJC5leHRlbmQoQWpheFF1ZXVlLnByb3RvdHlwZSwge1xuICAgIGFkZDogZnVuY3Rpb24gKGZuKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnF1ZXVlLnB1c2goZm4pO1xuICAgIH0sXG5cbiAgICBleGVjdXRlOiBmdW5jdGlvbiAoY29udGV4dCkge1xuICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICBjb250ZXh0ID0gY29udGV4dCB8fCB0aGlzO1xuXG4gICAgICAgIGZ1bmN0aW9uIG5leHQoKSB7XG4gICAgICAgICAgICBpZiAoX3RoaXMucXVldWUubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgdmFyIGZuID0gX3RoaXMucXVldWUuc2hpZnQoKTtcblxuICAgICAgICAgICAgICAgIGZuLmNhbGwoY29udGV4dClcbiAgICAgICAgICAgICAgICAgICAgLnRoZW4obmV4dClcbiAgICAgICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBuZXh0KCk7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfVxufSk7XG5cblxubW9kdWxlLmV4cG9ydHMgPSBBamF4UXVldWU7IiwiLyoqXG4vKiBJbmhlcml0IGZyb20gYSBjbGFzcyAodXNpbmcgcHJvdG90eXBlIGJvcnJvd2luZylcbiovXG4ndXNlIHN0cmljdCc7XG5cbmZ1bmN0aW9uIGluaGVyaXQoQywgUCkge1xuICAgIHZhciBGID0gZnVuY3Rpb24gKCkge307XG4gICAgRi5wcm90b3R5cGUgPSBQLnByb3RvdHlwZTtcbiAgICBDLnByb3RvdHlwZSA9IG5ldyBGKCk7XG4gICAgQy5fX3N1cGVyID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDO1xufVxuXG4vKipcbiogU2hhbGxvdyBjb3B5IG9mIGFuIG9iamVjdFxuKi9cbnZhciBleHRlbmQgPSBmdW5jdGlvbiAoZGVzdCAvKiwgdmFyX2FyZ3MqLykge1xuICAgIHZhciBvYmogPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgIHZhciBjdXJyZW50O1xuICAgIGZvciAodmFyIGogPSAwOyBqPG9iai5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAoIShjdXJyZW50ID0gb2JqW2pdKSkge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkbyBub3Qgd3JhcCBpbm5lciBpbiBkZXN0Lmhhc093blByb3BlcnR5IG9yIGJhZCB0aGluZ3Mgd2lsbCBoYXBwZW5cbiAgICAgICAgLypqc2hpbnQgLVcwODkgKi9cbiAgICAgICAgZm9yICh2YXIga2V5IGluIGN1cnJlbnQpIHtcbiAgICAgICAgICAgIGRlc3Rba2V5XSA9IGN1cnJlbnRba2V5XTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBkZXN0O1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoYmFzZSwgcHJvcHMsIHN0YXRpY1Byb3BzKSB7XG4gICAgdmFyIHBhcmVudCA9IGJhc2U7XG4gICAgdmFyIGNoaWxkO1xuXG4gICAgY2hpbGQgPSBwcm9wcyAmJiBwcm9wcy5oYXNPd25Qcm9wZXJ0eSgnY29uc3RydWN0b3InKSA/IHByb3BzLmNvbnN0cnVjdG9yIDogZnVuY3Rpb24gKCkgeyByZXR1cm4gcGFyZW50LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7IH07XG5cbiAgICAvLyBhZGQgc3RhdGljIHByb3BlcnRpZXMgdG8gdGhlIGNoaWxkIGNvbnN0cnVjdG9yIGZ1bmN0aW9uXG4gICAgZXh0ZW5kKGNoaWxkLCBwYXJlbnQsIHN0YXRpY1Byb3BzKTtcblxuICAgIC8vIGFzc29jaWF0ZSBwcm90b3R5cGUgY2hhaW5cbiAgICBpbmhlcml0KGNoaWxkLCBwYXJlbnQpO1xuXG4gICAgLy8gYWRkIGluc3RhbmNlIHByb3BlcnRpZXNcbiAgICBpZiAocHJvcHMpIHtcbiAgICAgICAgZXh0ZW5kKGNoaWxkLnByb3RvdHlwZSwgcHJvcHMpO1xuICAgIH1cblxuICAgIC8vIGRvbmVcbiAgICByZXR1cm4gY2hpbGQ7XG59O1xuIl19 diff --git a/dist/components/login/login.js b/dist/components/login/login.js index 743bbf26..98cd82b0 100644 --- a/dist/components/login/login.js +++ b/dist/components/login/login.js @@ -92,8 +92,6 @@ $(function () { }) .then(function () { window.location = action; - }) - .done(function () { $('.group-selection-dialog').hide(); }); }); diff --git a/dist/epicenter.js b/dist/epicenter.js index baa66120..a8167a42 100644 --- a/dist/epicenter.js +++ b/dist/epicenter.js @@ -365,7 +365,9 @@ function fromArrayBuffer (that, array, byteOffset, length) { throw new RangeError('\'length\' is out of bounds') } - if (length === undefined) { + if (byteOffset === undefined && length === undefined) { + array = new Uint8Array(array) + } else if (length === undefined) { array = new Uint8Array(array, byteOffset) } else { array = new Uint8Array(array, byteOffset, length) @@ -1919,11 +1921,96 @@ module.exports = Array.isArray || function (arr) { }; },{}],5:[function(require,module,exports){ +'use strict'; +/* eslint-disable no-unused-vars */ +var hasOwnProperty = Object.prototype.hasOwnProperty; +var propIsEnumerable = Object.prototype.propertyIsEnumerable; + +function toObject(val) { + if (val === null || val === undefined) { + throw new TypeError('Object.assign cannot be called with null or undefined'); + } + + return Object(val); +} + +function shouldUseNative() { + try { + if (!Object.assign) { + return false; + } + + // Detect buggy property enumeration order in older V8 versions. + + // https://bugs.chromium.org/p/v8/issues/detail?id=4118 + var test1 = new String('abc'); // eslint-disable-line + test1[5] = 'de'; + if (Object.getOwnPropertyNames(test1)[0] === '5') { + return false; + } + + // https://bugs.chromium.org/p/v8/issues/detail?id=3056 + var test2 = {}; + for (var i = 0; i < 10; i++) { + test2['_' + String.fromCharCode(i)] = i; + } + var order2 = Object.getOwnPropertyNames(test2).map(function (n) { + return test2[n]; + }); + if (order2.join('') !== '0123456789') { + return false; + } + + // https://bugs.chromium.org/p/v8/issues/detail?id=3056 + var test3 = {}; + 'abcdefghijklmnopqrst'.split('').forEach(function (letter) { + test3[letter] = letter; + }); + if (Object.keys(Object.assign({}, test3)).join('') !== + 'abcdefghijklmnopqrst') { + return false; + } + + return true; + } catch (e) { + // We don't expect any of the above to throw, but better to be safe. + return false; + } +} + +module.exports = shouldUseNative() ? Object.assign : function (target, source) { + var from; + var to = toObject(target); + var symbols; + + for (var s = 1; s < arguments.length; s++) { + from = Object(arguments[s]); + + for (var key in from) { + if (hasOwnProperty.call(from, key)) { + to[key] = from[key]; + } + } + + if (Object.getOwnPropertySymbols) { + symbols = Object.getOwnPropertySymbols(from); + for (var i = 0; i < symbols.length; i++) { + if (propIsEnumerable.call(from, symbols[i])) { + to[symbols[i]] = from[symbols[i]]; + } + } + } + } + + return to; +}; + +},{}],6:[function(require,module,exports){ module.exports={ "version": "v2" } -},{}],6:[function(require,module,exports){ +},{}],7:[function(require,module,exports){ (function (global){ /** * Epicenter Javascript libraries @@ -1966,6 +2053,7 @@ F.service.State = require('./service/state-api-adapter'); F.service.User = require('./service/user-api-adapter'); F.service.Member = require('./service/member-api-adapter'); F.service.Asset = require('./service/asset-api-adapter'); +F.service.Group = require('./service/group-api-service'); F.store.Cookie = require('./store/cookie-store'); F.factory.Store = require('./store/store-factory'); @@ -1994,7 +2082,11 @@ module.exports = F; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +<<<<<<< HEAD +},{"./api-version.json":6,"./env-load":8,"./managers/auth-manager":9,"./managers/epicenter-channel-manager":11,"./managers/run-manager":13,"./managers/run-strategies/always-new-strategy":14,"./managers/run-strategies/conditional-creation-strategy":15,"./managers/run-strategies/identity-strategy":16,"./managers/run-strategies/new-if-initialized-strategy":18,"./managers/run-strategies/new-if-missing-strategy":19,"./managers/run-strategies/new-if-persisted-strategy":20,"./managers/scenario-manager":23,"./managers/world-manager":25,"./service/admin-file-service":26,"./service/asset-api-adapter":27,"./service/auth-api-service":28,"./service/channel-service":29,"./service/configuration-service":30,"./service/data-api-service":31,"./service/group-api-service":32,"./service/member-api-adapter":33,"./service/run-api-service":34,"./service/state-api-adapter":36,"./service/url-config-service":37,"./service/user-api-adapter":38,"./service/variables-api-service":39,"./service/world-api-adapter":40,"./store/cookie-store":41,"./store/store-factory":43,"./transport/ajax-http-transport":44,"./transport/http-transport-factory":45,"./util/inherit":46,"./util/make-sequence":47,"./util/query-util":50,"./util/run-util":51}],8:[function(require,module,exports){ +======= },{"./api-version.json":5,"./env-load":7,"./managers/auth-manager":8,"./managers/epicenter-channel-manager":10,"./managers/run-manager":12,"./managers/run-strategies/always-new-strategy":13,"./managers/run-strategies/conditional-creation-strategy":14,"./managers/run-strategies/identity-strategy":15,"./managers/run-strategies/new-if-initialized-strategy":17,"./managers/run-strategies/new-if-missing-strategy":18,"./managers/run-strategies/new-if-persisted-strategy":19,"./managers/scenario-manager":22,"./managers/world-manager":24,"./service/admin-file-service":25,"./service/asset-api-adapter":26,"./service/auth-api-service":27,"./service/channel-service":28,"./service/configuration-service":29,"./service/data-api-service":30,"./service/member-api-adapter":32,"./service/run-api-service":33,"./service/state-api-adapter":34,"./service/url-config-service":35,"./service/user-api-adapter":36,"./service/variables-api-service":37,"./service/world-api-adapter":38,"./store/cookie-store":39,"./store/store-factory":41,"./transport/ajax-http-transport":42,"./transport/http-transport-factory":43,"./util/inherit":44,"./util/make-sequence":45,"./util/query-util":48,"./util/run-util":49}],7:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var urlConfigService = require('./service/url-config-service'); @@ -2024,7 +2116,11 @@ var envLoad = function (callback) { module.exports = envLoad; +<<<<<<< HEAD +},{"./service/url-config-service":37}],9:[function(require,module,exports){ +======= },{"./service/url-config-service":35}],8:[function(require,module,exports){ +>>>>>>> dms3-version /** * ## Authorization Manager * @@ -2060,9 +2156,11 @@ module.exports = envLoad; 'use strict'; var AuthAdapter = require('../service/auth-api-service'); var MemberAdapter = require('../service/member-api-adapter'); +var GroupService = require('../service/group-api-service'); var SessionManager = require('../store/session-manager'); var Buffer = require('buffer').Buffer; var _pick = require('../util/object-util')._pick; +var objectAssign = require('object-assign'); var defaults = { requiresGroup: true @@ -2180,19 +2278,19 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { return; } - _this.getUserGroups({ userId: userInfo.user_id, token: token }, userGroupOpts).done(function (memberInfo) { - data.userGroups = memberInfo; + var handleGroupList = function (groupList) { + data.userGroups = groupList; var group = null; - if (memberInfo.length === 0) { + if (groupList.length === 0) { handleGroupError('The user has no groups associated in this account', 401, data); return; - } else if (memberInfo.length === 1) { + } else if (groupList.length === 1) { // Select the only group - group = memberInfo[0]; - } else if (memberInfo.length > 1) { + group = groupList[0]; + } else if (groupList.length > 1) { if (groupId) { - var filteredGroups = $.grep(memberInfo, function (resGroup) { + var filteredGroups = $.grep(groupList, function (resGroup) { return resGroup.groupId === groupId; }); group = filteredGroups.length === 1 ? filteredGroups[0] : null; @@ -2200,12 +2298,15 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { } if (group) { + // A team member does not get the group members because is calling the Group API + // but it's automatically a fac user + var isFac = isTeamMember ? true : _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator'; var groupData = { - 'groupId': group.groupId, - 'groupName': group.name, - 'isFac': _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator' + groupId: group.groupId, + groupName: group.name, + isFac: isFac }; - var sessionInfoWithGroup = $.extend({}, sessionInfo, groupData); + var sessionInfoWithGroup = objectAssign({}, sessionInfo, groupData); sessionInfo.groups[project] = groupData; _this.sessionManager.saveSession(sessionInfoWithGroup, adapterOptions); outSuccess.apply(this, [data]); @@ -2213,7 +2314,23 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { } else { handleGroupError('This user is associated with more than one group. Please specify a group id to log into and try again', 403, data); } - }).fail($d.reject); + }; + + if (!isTeamMember) { + _this.getUserGroups({ userId: userInfo.user_id, token: token }, userGroupOpts) + .then(handleGroupList, $d.reject); + } else { + var opts = objectAssign({}, userGroupOpts, { token: token }); + var groupService = new GroupService(opts); + groupService.getGroups({ account: adapterOptions.account, project: project }) + .then(function (groups) { + // Group API returns id instead of groupId + groups.forEach(function (group) { + group.groupId = group.id; + }); + handleGroupList(groups); + }, $d.reject); + } }; adapterOptions.success = handleSuccess; @@ -2352,24 +2469,23 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { return this.sessionManager.getSession(options); }, - // (replace with /* */ comment block, to make visible in docs, once EPICENTER-1939 is complete) - // - // Add one or more groups to the current session. - // - // This method assumes that the project and group exist and the user specified in the session is part of this project and group. - // - // Returns the new session object. - // - // **Example** - // - // authMgr.addGroups({ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' }); - // authMgr.addGroups([{ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' }, { project: ... }]); - // - // **Parameters** - // @param {object|array} `groups` (Required) The group object must contain the `project` (**Project ID**) and `groupName` properties. - // @param {string} `group.isFac` (optional) Defaults to `false`. Set to `true` if the user in the session should be a facilitator in this group. - // @param {string} `group.groupId` (optional) Defaults to undefined. Needed mostly for the Members API. - // + /* + * Adds one or more groups to the current session. + * + * This method assumes that the project and group exist and the user specified in the session is part of this project and group. + * + * Returns the new session object. + * + * **Example** + * + * authMgr.addGroups({ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' }); + * authMgr.addGroups([{ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' }, { project: 'hello-world', groupName: '...' }]); + * + * **Parameters** + * @param {object|array} `groups` (Required) The group object must contain the `project` (**Project ID**) and `groupName` properties. If passing an array of such objects, all of the objects must contain *different* `project` (**Project ID**) values: although end users may be logged in to multiple projects at once, they may only be logged in to one group per project at a time. + * @param {string} `group.isFac` (optional) Defaults to `false`. Set to `true` if the user in the session should be a facilitator in this group. + * @param {string} `group.groupId` (optional) Defaults to undefined. Needed mostly for the Members API. + */ addGroups: function (groups) { var session = this.getCurrentUserSessionInfo(); var isArray = Array.isArray(groups); @@ -2393,7 +2509,11 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { module.exports = AuthManager; +<<<<<<< HEAD +},{"../service/auth-api-service":28,"../service/group-api-service":32,"../service/member-api-adapter":33,"../store/session-manager":42,"../util/object-util":48,"buffer":2,"object-assign":5}],10:[function(require,module,exports){ +======= },{"../service/auth-api-service":27,"../service/member-api-adapter":32,"../store/session-manager":40,"../util/object-util":46,"buffer":2}],9:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var Channel = require('../service/channel-service'); @@ -2639,7 +2759,11 @@ ChannelManager.prototype = $.extend(ChannelManager.prototype, { module.exports = ChannelManager; +<<<<<<< HEAD +},{"../service/channel-service":29,"../store/session-manager":42}],11:[function(require,module,exports){ +======= },{"../service/channel-service":28,"../store/session-manager":40}],10:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; /** @@ -3022,14 +3146,18 @@ var EpicenterChannelManager = classFrom(ChannelManager, { module.exports = EpicenterChannelManager; +<<<<<<< HEAD +},{"../service/url-config-service":37,"../store/session-manager":42,"../util/inherit":46,"./auth-manager":9,"./channel-manager":10}],12:[function(require,module,exports){ +======= },{"../service/url-config-service":35,"../store/session-manager":40,"../util/inherit":44,"./auth-manager":8,"./channel-manager":9}],11:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; module.exports = { EPI_SESSION_KEY: 'epicenterjs.session', STRATEGY_SESSION_KEY: 'epicenter-scenario' }; -},{}],12:[function(require,module,exports){ +},{}],13:[function(require,module,exports){ /** * ## Run Manager * @@ -3186,7 +3314,11 @@ RunManager.prototype = { module.exports = RunManager; +<<<<<<< HEAD +},{"../service/run-api-service":34,"./run-strategies/strategies-map":22,"./special-operations":24}],14:[function(require,module,exports){ +======= },{"../service/run-api-service":33,"./run-strategies/strategies-map":21,"./special-operations":23}],13:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var classFrom = require('../../util/inherit'); @@ -3207,18 +3339,19 @@ var Strategy = classFrom(ConditionalStrategy, { module.exports = Strategy; +<<<<<<< HEAD +},{"../../util/inherit":46,"./conditional-creation-strategy":15}],15:[function(require,module,exports){ +======= },{"../../util/inherit":44,"./conditional-creation-strategy":14}],14:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var makeSeq = require('../../util/make-sequence'); var Base = require('./identity-strategy'); -var SessionStore = require('../../store/store-factory'); +var SessionManager = require('../../store/session-manager'); var classFrom = require('../../util/inherit'); -var UrlService = require('../../service/url-config-service'); var AuthManager = require('../auth-manager'); -var sessionStore = new SessionStore({}); -var urlService = new UrlService(); var keyNames = require('../key-names'); var defaults = { @@ -3226,18 +3359,8 @@ var defaults = { path: '' }; -function setRunInSession(sessionKey, run, path) { - if (!path) { - if (!urlService.isLocalhost()) { - path = '/' + [urlService.appPath, urlService.accountPath, urlService.projectPath].join('/'); - // make sure we don't get consecuteive '/' so we have a valid path for the session - path = path.replace(/\/{2,}/g,'/'); - } else { - path = ''; - } - } - // set the seesionKey for the run - sessionStore.set(sessionKey, JSON.stringify({ runId: run.id }), { root: path }); +function setRunInSession(sessionKey, run, sessionManager) { + sessionManager.getStore().set(sessionKey, JSON.stringify({ runId: run.id })); } /** @@ -3258,6 +3381,7 @@ var Strategy = classFrom(Base, { this.run = makeSeq(runService); this.condition = typeof condition !== 'function' ? function () { return condition; } : condition; this.options = $.extend(true, {}, defaults, options); + this.sessionManager = new SessionManager(options); this.runOptions = this.options.run; }, @@ -3275,7 +3399,7 @@ var Strategy = classFrom(Base, { return this.run .create(opt, runServiceOptions) .then(function (run) { - setRunInSession(_this.options.sessionKey, run, _this.options.path); + setRunInSession(_this.options.sessionKey, run, _this.sessionManager); run.freshlyCreated = true; return run; }) @@ -3283,10 +3407,13 @@ var Strategy = classFrom(Base, { }, getRun: function () { + var sessionStore = this.sessionManager.getStore(); var runSession = JSON.parse(sessionStore.get(this.options.sessionKey)); if (runSession && runSession.runId) { - return this._loadAndCheck(runSession); + return this._loadAndCheck(runSession).fail(function () { + return this.reset(); //if it got the wrong cookie for e.g. + }.bind(this)); } else { return this.reset(); } @@ -3309,7 +3436,7 @@ var Strategy = classFrom(Base, { // so we don't get in the middle of the queue return _this.run.original.create(opt) .then(function (run) { - setRunInSession(_this.options.sessionKey, run); + setRunInSession(_this.options.sessionKey, run, _this.sessionManager); run.freshlyCreated = true; return run; }); @@ -3323,7 +3450,11 @@ var Strategy = classFrom(Base, { module.exports = Strategy; +<<<<<<< HEAD +},{"../../store/session-manager":42,"../../util/inherit":46,"../../util/make-sequence":47,"../auth-manager":9,"../key-names":12,"./identity-strategy":16}],16:[function(require,module,exports){ +======= },{"../../service/url-config-service":35,"../../store/store-factory":41,"../../util/inherit":44,"../../util/make-sequence":45,"../auth-manager":8,"../key-names":11,"./identity-strategy":15}],15:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var classFrom = require('../../util/inherit'); @@ -3346,7 +3477,11 @@ module.exports = classFrom(Base, { } }); +<<<<<<< HEAD +},{"../../util/inherit":46}],17:[function(require,module,exports){ +======= },{"../../util/inherit":44}],16:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var classFrom = require('../../util/inherit'); @@ -3427,7 +3562,11 @@ var Strategy = classFrom(IdentityStrategy, { module.exports = Strategy; +<<<<<<< HEAD +},{"../../service/world-api-adapter":40,"../../util/inherit":46,"../auth-manager":9,"./identity-strategy":16}],18:[function(require,module,exports){ +======= },{"../../service/world-api-adapter":38,"../../util/inherit":44,"../auth-manager":8,"./identity-strategy":15}],17:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var classFrom = require('../../util/inherit'); var ConditionalStrategy = require('./conditional-creation-strategy'); @@ -3446,7 +3585,11 @@ var Strategy = classFrom(ConditionalStrategy, { module.exports = Strategy; +<<<<<<< HEAD +},{"../../util/inherit":46,"./conditional-creation-strategy":15}],19:[function(require,module,exports){ +======= },{"../../util/inherit":44,"./conditional-creation-strategy":14}],18:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var classFrom = require('../../util/inherit'); @@ -3471,7 +3614,11 @@ var Strategy = classFrom(ConditionalStrategy, { module.exports = Strategy; +<<<<<<< HEAD +},{"../../util/inherit":46,"./conditional-creation-strategy":15}],20:[function(require,module,exports){ +======= },{"../../util/inherit":44,"./conditional-creation-strategy":14}],19:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var classFrom = require('../../util/inherit'); var ConditionalStrategy = require('./conditional-creation-strategy'); @@ -3490,7 +3637,11 @@ var Strategy = classFrom(ConditionalStrategy, { module.exports = Strategy; +<<<<<<< HEAD +},{"../../util/inherit":46,"./conditional-creation-strategy":15}],21:[function(require,module,exports){ +======= },{"../../util/inherit":44,"./conditional-creation-strategy":14}],20:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var classFrom = require('../../util/inherit'); @@ -3584,7 +3735,11 @@ var Strategy = classFrom(IdentityStrategy, { module.exports = Strategy; +<<<<<<< HEAD +},{"../../service/state-api-adapter":36,"../../store/store-factory":43,"../../util/inherit":46,"../auth-manager":9,"../key-names":12,"./identity-strategy":16}],22:[function(require,module,exports){ +======= },{"../../service/state-api-adapter":34,"../../store/store-factory":41,"../../util/inherit":44,"../auth-manager":8,"../key-names":11,"./identity-strategy":15}],21:[function(require,module,exports){ +>>>>>>> dms3-version module.exports = { 'new-if-initialized': require('./new-if-initialized-strategy'), 'new-if-persisted': require('./new-if-persisted-strategy'), @@ -3595,7 +3750,7 @@ module.exports = { 'none': require('./identity-strategy') }; -},{"./always-new-strategy":13,"./identity-strategy":15,"./multiplayer-strategy":16,"./new-if-initialized-strategy":17,"./new-if-missing-strategy":18,"./new-if-persisted-strategy":19,"./persistent-single-player-strategy":20}],22:[function(require,module,exports){ +},{"./always-new-strategy":14,"./identity-strategy":16,"./multiplayer-strategy":17,"./new-if-initialized-strategy":18,"./new-if-missing-strategy":19,"./new-if-persisted-strategy":20,"./persistent-single-player-strategy":21}],23:[function(require,module,exports){ 'use strict'; var RunService = require('../service/run-api-service'); @@ -3646,7 +3801,11 @@ ScenarioManager.prototype = { module.exports = ScenarioManager; +<<<<<<< HEAD +},{"../service/run-api-service":34}],24:[function(require,module,exports){ +======= },{"../service/run-api-service":33}],23:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; @@ -3656,7 +3815,7 @@ module.exports = { } }; -},{}],24:[function(require,module,exports){ +},{}],25:[function(require,module,exports){ /** * ## World Manager * @@ -3827,7 +3986,11 @@ module.exports = function (options) { $.extend(this, api); }; +<<<<<<< HEAD +},{"../service/world-api-adapter":40,"./auth-manager":9,"./run-manager":13}],26:[function(require,module,exports){ +======= },{"../service/world-api-adapter":38,"./auth-manager":8,"./run-manager":12}],25:[function(require,module,exports){ +>>>>>>> dms3-version /** * ## File API Service * @@ -3972,7 +4135,11 @@ module.exports = function (config) { $.extend(this, publicAsyncAPI); }; +<<<<<<< HEAD +},{"../store/session-manager":42,"../transport/http-transport-factory":45,"./configuration-service":30}],27:[function(require,module,exports){ +======= },{"../store/session-manager":40,"../transport/http-transport-factory":43,"./configuration-service":29}],26:[function(require,module,exports){ +>>>>>>> dms3-version /** * ## Asset API Adapter * @@ -4352,7 +4519,11 @@ module.exports = function (config) { $.extend(this, publicAPI); }; +<<<<<<< HEAD +},{"../store/session-manager":42,"../transport/http-transport-factory":45,"../util/object-util":48,"./configuration-service":30}],28:[function(require,module,exports){ +======= },{"../store/session-manager":40,"../transport/http-transport-factory":43,"../util/object-util":46,"./configuration-service":29}],27:[function(require,module,exports){ +>>>>>>> dms3-version /** * * ## Authentication API Service @@ -4473,7 +4644,11 @@ module.exports = function (config) { $.extend(this, publicAPI); }; +<<<<<<< HEAD +},{"../transport/http-transport-factory":45,"./configuration-service":30}],29:[function(require,module,exports){ +======= },{"../transport/http-transport-factory":43,"./configuration-service":29}],28:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; /** @@ -4703,7 +4878,7 @@ Channel.prototype = $.extend(Channel.prototype, { module.exports = Channel; -},{}],29:[function(require,module,exports){ +},{}],30:[function(require,module,exports){ /** * @class ConfigurationService * @@ -4777,7 +4952,11 @@ module.exports = function (config) { }; +<<<<<<< HEAD +},{"./url-config-service":37}],31:[function(require,module,exports){ +======= },{"./url-config-service":35}],30:[function(require,module,exports){ +>>>>>>> dms3-version /** * ## Data API Service * @@ -5038,6 +5217,19 @@ module.exports = function (config) { $.extend(this, publicAPI); }; +<<<<<<< HEAD +},{"../store/session-manager":42,"../transport/http-transport-factory":45,"../util/query-util":50,"./configuration-service":30}],32:[function(require,module,exports){ +/** + * + * ## Group API Adapter + * + * The Group API Adapter provides methods to look up, create, change or remove information about groups in a project. It is based on query capabilities of the underlying RESTful [Group API](../../../rest_apis/user_management/group/). + * + * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/). + * + * var ma = new F.service.Group({ token: 'user-or-project-access-token' }); + * ma.getGroupsForProject({ account: 'acme', project: 'sample' }); +======= },{"../store/session-manager":40,"../transport/http-transport-factory":43,"../util/query-util":48,"./configuration-service":29}],31:[function(require,module,exports){ /** * @@ -5057,10 +5249,73 @@ module.exports = function (config) { * var is = rm.run.introspection(); * }); * +>>>>>>> dms3-version */ 'use strict'; +<<<<<<< HEAD +var serviceUtils = require('./service-utils'); +var TransportFactory = require('../transport/http-transport-factory'); +var objectAssign = require('object-assign'); + +var apiEndpoint = 'group/local'; + +var GroupService = function (config) { + var defaults = { + /** + * Epicenter account name. Defaults to undefined. + * @type {string} + */ + account: undefined, + + /** + * Epicenter project name. Defaults to undefined. + * @type {string} + */ + project: undefined, + + /** + * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object. + * @type {object} + */ + transport: {} + }; + var serviceOptions = serviceUtils.getDefaultOptions(defaults, config, { apiEndpoint: apiEndpoint }); + var transportOptions = serviceOptions.transport; + delete serviceOptions.transport; + var http = new TransportFactory(transportOptions, serviceOptions); + var publicAPI = { + /* + * Gets information for a group or multiple groups. + * @param {string} `params` the groupId of the target group + * @param {Object} `params` object with query parameters + * @patam {string} `params.q` partial match for name, organization or event. + * @patam {string} `params.account` Epicenter's Team ID + * @patam {string} `params.project` Epicenter's Project ID + * @patam {string} `params.name` Epicenter's Group Name + * @param {Object} `options` (Optional) Overrides for configuration options. + */ + getGroups: function (params, options) { + //groupID is part of the URL + //q, account and project are part of the query string + var finalOpts = objectAssign({}, serviceOptions, options); + var finalParams; + if (typeof params === 'string') { + finalOpts.url = serviceUtils.getApiUrl(apiEndpoint + '/' + params, finalOpts); + } else { + finalParams = params; + } + return http.get(finalParams, finalOpts); + } + }; + objectAssign(this, publicAPI); +}; + +module.exports = GroupService; + +},{"../transport/http-transport-factory":45,"./service-utils":35,"object-assign":5}],33:[function(require,module,exports){ +======= var ConfigService = require('./configuration-service'); var TransportFactory = require('../transport/http-transport-factory'); @@ -5123,6 +5378,7 @@ module.exports = function (config) { }; },{"../transport/http-transport-factory":43,"./configuration-service":29}],32:[function(require,module,exports){ +>>>>>>> dms3-version /** * * ## Member API Adapter @@ -5309,7 +5565,11 @@ module.exports = function (config) { $.extend(this, publicAPI); }; +<<<<<<< HEAD +},{"../store/session-manager":42,"../transport/http-transport-factory":45,"../util/object-util":48,"./configuration-service":30}],34:[function(require,module,exports){ +======= },{"../store/session-manager":40,"../transport/http-transport-factory":43,"../util/object-util":46,"./configuration-service":29}],33:[function(require,module,exports){ +>>>>>>> dms3-version /** * * ## Run API Service @@ -5819,7 +6079,52 @@ module.exports = function (config) { $.extend(this, publicSyncAPI); }; +<<<<<<< HEAD +},{"../store/session-manager":42,"../transport/http-transport-factory":45,"../util/object-util":48,"../util/query-util":50,"../util/run-util":51,"./configuration-service":30,"./variables-api-service":39}],35:[function(require,module,exports){ +'use strict'; + +var ConfigService = require('./configuration-service'); +var SessionManager = require('../store/session-manager'); +var objectAssign = require('object-assign'); + +var serviceUtils = { + /* + * Gets the default options for a api service. + * It will merge: + * - The Session options (Using the Session Manager) + * - The Authorization Header from the token option + * - The full url from the endpoint option + * With the supplied overrides and defaults + * + */ + getDefaultOptions: function (defaults) { + var rest = Array.prototype.slice.call(arguments, 1); + var sessionManager = new SessionManager(); + var serviceOptions = sessionManager.getMergedOptions.apply(sessionManager, [defaults].concat(rest)); + + serviceOptions.transport = objectAssign({}, serviceOptions.transport, { + url: this.getApiUrl(serviceOptions.apiEndpoint, serviceOptions) + }); + + if (serviceOptions.token) { + serviceOptions.transport.headers = { + 'Authorization': 'Bearer ' + serviceOptions.token + }; + } + return serviceOptions; + }, + + getApiUrl: function (apiEndpoint, serviceOptions) { + var urlConfig = new ConfigService(serviceOptions).get('server'); + return urlConfig.getAPIPath(apiEndpoint); + } +}; + +module.exports = serviceUtils; +},{"../store/session-manager":42,"./configuration-service":30,"object-assign":5}],36:[function(require,module,exports){ +======= },{"../store/session-manager":40,"../transport/http-transport-factory":43,"../util/object-util":46,"../util/query-util":48,"../util/run-util":49,"./configuration-service":29,"./introspection-api-service":31,"./variables-api-service":37}],34:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; /** * ## State API Adapter @@ -5943,7 +6248,11 @@ module.exports = function (config) { $.extend(this, publicAPI); }; +<<<<<<< HEAD +},{"../store/session-manager":42,"../transport/http-transport-factory":45,"../util/object-util":48,"./configuration-service":30}],37:[function(require,module,exports){ +======= },{"../store/session-manager":40,"../transport/http-transport-factory":43,"../util/object-util":46,"./configuration-service":29}],35:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var epiVersion = require('../api-version.json'); @@ -6037,7 +6346,11 @@ var UrlConfigService = function (config) { module.exports = UrlConfigService; +<<<<<<< HEAD +},{"../api-version.json":6}],38:[function(require,module,exports){ +======= },{"../api-version.json":5}],36:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; /** * ## User API Adapter @@ -6194,7 +6507,11 @@ module.exports = function (config) { +<<<<<<< HEAD +},{"../store/session-manager":42,"../transport/http-transport-factory":45,"../util/query-util":50,"./configuration-service":30}],39:[function(require,module,exports){ +======= },{"../store/session-manager":40,"../transport/http-transport-factory":43,"../util/query-util":48,"./configuration-service":29}],37:[function(require,module,exports){ +>>>>>>> dms3-version /** * * ## Variables API Service @@ -6359,7 +6676,11 @@ module.exports = function (config) { $.extend(this, publicAPI); }; +<<<<<<< HEAD +},{"../transport/http-transport-factory":45,"../util/run-util":51}],40:[function(require,module,exports){ +======= },{"../transport/http-transport-factory":43,"../util/run-util":49}],38:[function(require,module,exports){ +>>>>>>> dms3-version /** * ## World API Adapter * @@ -7108,7 +7429,11 @@ module.exports = function (config) { $.extend(this, publicAPI); }; +<<<<<<< HEAD +},{"../store/session-manager":42,"../transport/http-transport-factory":45,"../util/object-util":48,"./configuration-service":30}],41:[function(require,module,exports){ +======= },{"../store/session-manager":40,"../transport/http-transport-factory":43,"../util/object-util":46,"./configuration-service":29}],39:[function(require,module,exports){ +>>>>>>> dms3-version /** * @class Cookie Storage Service * @@ -7135,6 +7460,9 @@ var Cookie = function () { module.exports = function (config) { var host = window.location.hostname; + var validHost = host.split('.').length > 1; + var domain = validHost ? '.' + host : null; + var defaults = { /** * Name of collection @@ -7142,7 +7470,7 @@ module.exports = function (config) { */ root: '/', - domain: '.' + host, + domain: domain, cookie: new Cookie() }; this.serviceOptions = $.extend({}, defaults, config); @@ -7250,7 +7578,11 @@ module.exports = function (config) { $.extend(this, publicAPI); }; +<<<<<<< HEAD +},{}],42:[function(require,module,exports){ +======= },{}],40:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var keyNames = require('../managers/key-names'); @@ -7313,7 +7645,12 @@ var SessionManager = function (managerOptions) { return session; }, removeSession: function (options) { - return getStore(options).remove(EPI_SESSION_KEY); + var store = getStore(options); + Object.keys(keyNames).forEach(function (cookieKey) { + var cookieName = keyNames[cookieKey]; + store.remove(cookieName); + }); + return true; }, getStore: function (options) { return getStore(options); @@ -7353,7 +7690,11 @@ var SessionManager = function (managerOptions) { }; module.exports = SessionManager; +<<<<<<< HEAD +},{"../managers/key-names":12,"../util/option-utils":49,"./store-factory":43}],43:[function(require,module,exports){ +======= },{"../managers/key-names":11,"../util/option-utils":47,"./store-factory":41}],41:[function(require,module,exports){ +>>>>>>> dms3-version /** Decides type of store to provide */ @@ -7365,7 +7706,11 @@ var store = require('./cookie-store'); module.exports = store; +<<<<<<< HEAD +},{"./cookie-store":41}],44:[function(require,module,exports){ +======= },{"./cookie-store":39}],42:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var qutils = require('../util/query-util'); @@ -7474,7 +7819,11 @@ module.exports = function (config) { return $.extend(this, publicAPI); }; +<<<<<<< HEAD +},{"../util/query-util":50}],45:[function(require,module,exports){ +======= },{"../util/query-util":48}],43:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; // var isNode = false; FIXME: Browserify/minifyify has issues with the next link @@ -7482,7 +7831,11 @@ module.exports = function (config) { var transport = require('./ajax-http-transport'); module.exports = transport; +<<<<<<< HEAD +},{"./ajax-http-transport":44}],46:[function(require,module,exports){ +======= },{"./ajax-http-transport":42}],44:[function(require,module,exports){ +>>>>>>> dms3-version /** /* Inherit from a class (using prototype borrowing) */ @@ -7538,7 +7891,11 @@ module.exports = function (base, props, staticProps) { return child; }; +<<<<<<< HEAD +},{}],47:[function(require,module,exports){ +======= },{}],45:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; /*jshint loopfunc:false */ @@ -7621,7 +7978,11 @@ function MakeSeq(obj) { module.exports = MakeSeq; +<<<<<<< HEAD +},{}],48:[function(require,module,exports){ +======= },{}],46:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; module.exports = { @@ -7637,7 +7998,11 @@ module.exports = { } }; +<<<<<<< HEAD +},{}],49:[function(require,module,exports){ +======= },{}],47:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var ConfigService = require('../service/configuration-service'); @@ -7678,7 +8043,11 @@ var optionUtils = { }; module.exports = optionUtils; +<<<<<<< HEAD +},{"../service/configuration-service":30}],50:[function(require,module,exports){ +======= },{"../service/configuration-service":29}],48:[function(require,module,exports){ +>>>>>>> dms3-version /** * Utilities for working with query strings */ @@ -7792,7 +8161,11 @@ module.exports = (function () { +<<<<<<< HEAD +},{}],51:[function(require,module,exports){ +======= },{}],49:[function(require,module,exports){ +>>>>>>> dms3-version /** * Utilities for working with the run service */ @@ -8016,5 +8389,10 @@ module.exports = (function () { }; }()); +<<<<<<< HEAD +},{"./query-util":50}]},{},[7]) +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvYmFzZTY0LWpzL2xpYi9iNjQuanMiLCJub2RlX21vZHVsZXMvYnVmZmVyL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2llZWU3NTQvaW5kZXguanMiLCJub2RlX21vZHVsZXMvaXNhcnJheS9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9vYmplY3QtYXNzaWduL2luZGV4LmpzIiwic3JjL2FwaS12ZXJzaW9uLmpzb24iLCJzcmMvYXBwLmpzIiwic3JjL2Vudi1sb2FkLmpzIiwic3JjL21hbmFnZXJzL2F1dGgtbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9jaGFubmVsLW1hbmFnZXIuanMiLCJzcmMvbWFuYWdlcnMvZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9rZXktbmFtZXMuanMiLCJzcmMvbWFuYWdlcnMvcnVuLW1hbmFnZXIuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvYWx3YXlzLW5ldy1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9pZGVudGl0eS1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9tdWx0aXBsYXllci1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtaW5pdGlhbGl6ZWQtc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvbmV3LWlmLW1pc3Npbmctc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvbmV3LWlmLXBlcnNpc3RlZC1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9wZXJzaXN0ZW50LXNpbmdsZS1wbGF5ZXItc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvc3RyYXRlZ2llcy1tYXAuanMiLCJzcmMvbWFuYWdlcnMvc2NlbmFyaW8tbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9zcGVjaWFsLW9wZXJhdGlvbnMuanMiLCJzcmMvbWFuYWdlcnMvd29ybGQtbWFuYWdlci5qcyIsInNyYy9zZXJ2aWNlL2FkbWluLWZpbGUtc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL2Fzc2V0LWFwaS1hZGFwdGVyLmpzIiwic3JjL3NlcnZpY2UvYXV0aC1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL2NoYW5uZWwtc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL2NvbmZpZ3VyYXRpb24tc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL2RhdGEtYXBpLXNlcnZpY2UuanMiLCJzcmMvc2VydmljZS9ncm91cC1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3J1bi1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3NlcnZpY2UtdXRpbHMuanMiLCJzcmMvc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3VybC1jb25maWctc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3VzZXItYXBpLWFkYXB0ZXIuanMiLCJzcmMvc2VydmljZS92YXJpYWJsZXMtYXBpLXNlcnZpY2UuanMiLCJzcmMvc2VydmljZS93b3JsZC1hcGktYWRhcHRlci5qcyIsInNyYy9zdG9yZS9jb29raWUtc3RvcmUuanMiLCJzcmMvc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyLmpzIiwic3JjL3N0b3JlL3N0b3JlLWZhY3RvcnkuanMiLCJzcmMvdHJhbnNwb3J0L2FqYXgtaHR0cC10cmFuc3BvcnQuanMiLCJzcmMvdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnkuanMiLCJzcmMvdXRpbC9pbmhlcml0LmpzIiwic3JjL3V0aWwvbWFrZS1zZXF1ZW5jZS5qcyIsInNyYy91dGlsL29iamVjdC11dGlsLmpzIiwic3JjL3V0aWwvb3B0aW9uLXV0aWxzLmpzIiwic3JjL3V0aWwvcXVlcnktdXRpbC5qcyIsInNyYy91dGlsL3J1bi11dGlsLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FDN0dBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDanJEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0xBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuRkE7QUFDQTtBQUNBO0FBQ0E7OztBQ0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUNuRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbllBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcFBBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdYQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0VBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1RkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDektBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMVhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2SEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcE9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25RQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RmQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM3VCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0lBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNkQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiJ3VzZSBzdHJpY3QnXG5cbmV4cG9ydHMudG9CeXRlQXJyYXkgPSB0b0J5dGVBcnJheVxuZXhwb3J0cy5mcm9tQnl0ZUFycmF5ID0gZnJvbUJ5dGVBcnJheVxuXG52YXIgbG9va3VwID0gW11cbnZhciByZXZMb29rdXAgPSBbXVxudmFyIEFyciA9IHR5cGVvZiBVaW50OEFycmF5ICE9PSAndW5kZWZpbmVkJyA/IFVpbnQ4QXJyYXkgOiBBcnJheVxuXG5mdW5jdGlvbiBpbml0ICgpIHtcbiAgdmFyIGNvZGUgPSAnQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODkrLydcbiAgZm9yICh2YXIgaSA9IDAsIGxlbiA9IGNvZGUubGVuZ3RoOyBpIDwgbGVuOyArK2kpIHtcbiAgICBsb29rdXBbaV0gPSBjb2RlW2ldXG4gICAgcmV2TG9va3VwW2NvZGUuY2hhckNvZGVBdChpKV0gPSBpXG4gIH1cblxuICByZXZMb29rdXBbJy0nLmNoYXJDb2RlQXQoMCldID0gNjJcbiAgcmV2TG9va3VwWydfJy5jaGFyQ29kZUF0KDApXSA9IDYzXG59XG5cbmluaXQoKVxuXG5mdW5jdGlvbiB0b0J5dGVBcnJheSAoYjY0KSB7XG4gIHZhciBpLCBqLCBsLCB0bXAsIHBsYWNlSG9sZGVycywgYXJyXG4gIHZhciBsZW4gPSBiNjQubGVuZ3RoXG5cbiAgaWYgKGxlbiAlIDQgPiAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHN0cmluZy4gTGVuZ3RoIG11c3QgYmUgYSBtdWx0aXBsZSBvZiA0JylcbiAgfVxuXG4gIC8vIHRoZSBudW1iZXIgb2YgZXF1YWwgc2lnbnMgKHBsYWNlIGhvbGRlcnMpXG4gIC8vIGlmIHRoZXJlIGFyZSB0d28gcGxhY2Vob2xkZXJzLCB0aGFuIHRoZSB0d28gY2hhcmFjdGVycyBiZWZvcmUgaXRcbiAgLy8gcmVwcmVzZW50IG9uZSBieXRlXG4gIC8vIGlmIHRoZXJlIGlzIG9ubHkgb25lLCB0aGVuIHRoZSB0aHJlZSBjaGFyYWN0ZXJzIGJlZm9yZSBpdCByZXByZXNlbnQgMiBieXRlc1xuICAvLyB0aGlzIGlzIGp1c3QgYSBjaGVhcCBoYWNrIHRvIG5vdCBkbyBpbmRleE9mIHR3aWNlXG4gIHBsYWNlSG9sZGVycyA9IGI2NFtsZW4gLSAyXSA9PT0gJz0nID8gMiA6IGI2NFtsZW4gLSAxXSA9PT0gJz0nID8gMSA6IDBcblxuICAvLyBiYXNlNjQgaXMgNC8zICsgdXAgdG8gdHdvIGNoYXJhY3RlcnMgb2YgdGhlIG9yaWdpbmFsIGRhdGFcbiAgYXJyID0gbmV3IEFycihsZW4gKiAzIC8gNCAtIHBsYWNlSG9sZGVycylcblxuICAvLyBpZiB0aGVyZSBhcmUgcGxhY2Vob2xkZXJzLCBvbmx5IGdldCB1cCB0byB0aGUgbGFzdCBjb21wbGV0ZSA0IGNoYXJzXG4gIGwgPSBwbGFjZUhvbGRlcnMgPiAwID8gbGVuIC0gNCA6IGxlblxuXG4gIHZhciBMID0gMFxuXG4gIGZvciAoaSA9IDAsIGogPSAwOyBpIDwgbDsgaSArPSA0LCBqICs9IDMpIHtcbiAgICB0bXAgPSAocmV2TG9va3VwW2I2NC5jaGFyQ29kZUF0KGkpXSA8PCAxOCkgfCAocmV2TG9va3VwW2I2NC5jaGFyQ29kZUF0KGkgKyAxKV0gPDwgMTIpIHwgKHJldkxvb2t1cFtiNjQuY2hhckNvZGVBdChpICsgMildIDw8IDYpIHwgcmV2TG9va3VwW2I2NC5jaGFyQ29kZUF0KGkgKyAzKV1cbiAgICBhcnJbTCsrXSA9ICh0bXAgPj4gMTYpICYgMHhGRlxuICAgIGFycltMKytdID0gKHRtcCA+PiA4KSAmIDB4RkZcbiAgICBhcnJbTCsrXSA9IHRtcCAmIDB4RkZcbiAgfVxuXG4gIGlmIChwbGFjZUhvbGRlcnMgPT09IDIpIHtcbiAgICB0bXAgPSAocmV2TG9va3VwW2I2NC5jaGFyQ29kZUF0KGkpXSA8PCAyKSB8IChyZXZMb29rdXBbYjY0LmNoYXJDb2RlQXQoaSArIDEpXSA+PiA0KVxuICAgIGFycltMKytdID0gdG1wICYgMHhGRlxuICB9IGVsc2UgaWYgKHBsYWNlSG9sZGVycyA9PT0gMSkge1xuICAgIHRtcCA9IChyZXZMb29rdXBbYjY0LmNoYXJDb2RlQXQoaSldIDw8IDEwKSB8IChyZXZMb29rdXBbYjY0LmNoYXJDb2RlQXQoaSArIDEpXSA8PCA0KSB8IChyZXZMb29rdXBbYjY0LmNoYXJDb2RlQXQoaSArIDIpXSA+PiAyKVxuICAgIGFycltMKytdID0gKHRtcCA+PiA4KSAmIDB4RkZcbiAgICBhcnJbTCsrXSA9IHRtcCAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBhcnJcbn1cblxuZnVuY3Rpb24gdHJpcGxldFRvQmFzZTY0IChudW0pIHtcbiAgcmV0dXJuIGxvb2t1cFtudW0gPj4gMTggJiAweDNGXSArIGxvb2t1cFtudW0gPj4gMTIgJiAweDNGXSArIGxvb2t1cFtudW0gPj4gNiAmIDB4M0ZdICsgbG9va3VwW251bSAmIDB4M0ZdXG59XG5cbmZ1bmN0aW9uIGVuY29kZUNodW5rICh1aW50OCwgc3RhcnQsIGVuZCkge1xuICB2YXIgdG1wXG4gIHZhciBvdXRwdXQgPSBbXVxuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkgKz0gMykge1xuICAgIHRtcCA9ICh1aW50OFtpXSA8PCAxNikgKyAodWludDhbaSArIDFdIDw8IDgpICsgKHVpbnQ4W2kgKyAyXSlcbiAgICBvdXRwdXQucHVzaCh0cmlwbGV0VG9CYXNlNjQodG1wKSlcbiAgfVxuICByZXR1cm4gb3V0cHV0LmpvaW4oJycpXG59XG5cbmZ1bmN0aW9uIGZyb21CeXRlQXJyYXkgKHVpbnQ4KSB7XG4gIHZhciB0bXBcbiAgdmFyIGxlbiA9IHVpbnQ4Lmxlbmd0aFxuICB2YXIgZXh0cmFCeXRlcyA9IGxlbiAlIDMgLy8gaWYgd2UgaGF2ZSAxIGJ5dGUgbGVmdCwgcGFkIDIgYnl0ZXNcbiAgdmFyIG91dHB1dCA9ICcnXG4gIHZhciBwYXJ0cyA9IFtdXG4gIHZhciBtYXhDaHVua0xlbmd0aCA9IDE2MzgzIC8vIG11c3QgYmUgbXVsdGlwbGUgb2YgM1xuXG4gIC8vIGdvIHRocm91Z2ggdGhlIGFycmF5IGV2ZXJ5IHRocmVlIGJ5dGVzLCB3ZSdsbCBkZWFsIHdpdGggdHJhaWxpbmcgc3R1ZmYgbGF0ZXJcbiAgZm9yICh2YXIgaSA9IDAsIGxlbjIgPSBsZW4gLSBleHRyYUJ5dGVzOyBpIDwgbGVuMjsgaSArPSBtYXhDaHVua0xlbmd0aCkge1xuICAgIHBhcnRzLnB1c2goZW5jb2RlQ2h1bmsodWludDgsIGksIChpICsgbWF4Q2h1bmtMZW5ndGgpID4gbGVuMiA/IGxlbjIgOiAoaSArIG1heENodW5rTGVuZ3RoKSkpXG4gIH1cblxuICAvLyBwYWQgdGhlIGVuZCB3aXRoIHplcm9zLCBidXQgbWFrZSBzdXJlIHRvIG5vdCBmb3JnZXQgdGhlIGV4dHJhIGJ5dGVzXG4gIGlmIChleHRyYUJ5dGVzID09PSAxKSB7XG4gICAgdG1wID0gdWludDhbbGVuIC0gMV1cbiAgICBvdXRwdXQgKz0gbG9va3VwW3RtcCA+PiAyXVxuICAgIG91dHB1dCArPSBsb29rdXBbKHRtcCA8PCA0KSAmIDB4M0ZdXG4gICAgb3V0cHV0ICs9ICc9PSdcbiAgfSBlbHNlIGlmIChleHRyYUJ5dGVzID09PSAyKSB7XG4gICAgdG1wID0gKHVpbnQ4W2xlbiAtIDJdIDw8IDgpICsgKHVpbnQ4W2xlbiAtIDFdKVxuICAgIG91dHB1dCArPSBsb29rdXBbdG1wID4+IDEwXVxuICAgIG91dHB1dCArPSBsb29rdXBbKHRtcCA+PiA0KSAmIDB4M0ZdXG4gICAgb3V0cHV0ICs9IGxvb2t1cFsodG1wIDw8IDIpICYgMHgzRl1cbiAgICBvdXRwdXQgKz0gJz0nXG4gIH1cblxuICBwYXJ0cy5wdXNoKG91dHB1dClcblxuICByZXR1cm4gcGFydHMuam9pbignJylcbn1cbiIsIi8qIVxuICogVGhlIGJ1ZmZlciBtb2R1bGUgZnJvbSBub2RlLmpzLCBmb3IgdGhlIGJyb3dzZXIuXG4gKlxuICogQGF1dGhvciAgIEZlcm9zcyBBYm91a2hhZGlqZWggPGZlcm9zc0BmZXJvc3Mub3JnPiA8aHR0cDovL2Zlcm9zcy5vcmc+XG4gKiBAbGljZW5zZSAgTUlUXG4gKi9cbi8qIGVzbGludC1kaXNhYmxlIG5vLXByb3RvICovXG5cbid1c2Ugc3RyaWN0J1xuXG52YXIgYmFzZTY0ID0gcmVxdWlyZSgnYmFzZTY0LWpzJylcbnZhciBpZWVlNzU0ID0gcmVxdWlyZSgnaWVlZTc1NCcpXG52YXIgaXNBcnJheSA9IHJlcXVpcmUoJ2lzYXJyYXknKVxuXG5leHBvcnRzLkJ1ZmZlciA9IEJ1ZmZlclxuZXhwb3J0cy5TbG93QnVmZmVyID0gU2xvd0J1ZmZlclxuZXhwb3J0cy5JTlNQRUNUX01BWF9CWVRFUyA9IDUwXG5cbi8qKlxuICogSWYgYEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUYDpcbiAqICAgPT09IHRydWUgICAgVXNlIFVpbnQ4QXJyYXkgaW1wbGVtZW50YXRpb24gKGZhc3Rlc3QpXG4gKiAgID09PSBmYWxzZSAgIFVzZSBPYmplY3QgaW1wbGVtZW50YXRpb24gKG1vc3QgY29tcGF0aWJsZSwgZXZlbiBJRTYpXG4gKlxuICogQnJvd3NlcnMgdGhhdCBzdXBwb3J0IHR5cGVkIGFycmF5cyBhcmUgSUUgMTArLCBGaXJlZm94IDQrLCBDaHJvbWUgNyssIFNhZmFyaSA1LjErLFxuICogT3BlcmEgMTEuNissIGlPUyA0LjIrLlxuICpcbiAqIER1ZSB0byB2YXJpb3VzIGJyb3dzZXIgYnVncywgc29tZXRpbWVzIHRoZSBPYmplY3QgaW1wbGVtZW50YXRpb24gd2lsbCBiZSB1c2VkIGV2ZW5cbiAqIHdoZW4gdGhlIGJyb3dzZXIgc3VwcG9ydHMgdHlwZWQgYXJyYXlzLlxuICpcbiAqIE5vdGU6XG4gKlxuICogICAtIEZpcmVmb3ggNC0yOSBsYWNrcyBzdXBwb3J0IGZvciBhZGRpbmcgbmV3IHByb3BlcnRpZXMgdG8gYFVpbnQ4QXJyYXlgIGluc3RhbmNlcyxcbiAqICAgICBTZWU6IGh0dHBzOi8vYnVnemlsbGEubW96aWxsYS5vcmcvc2hvd19idWcuY2dpP2lkPTY5NTQzOC5cbiAqXG4gKiAgIC0gQ2hyb21lIDktMTAgaXMgbWlzc2luZyB0aGUgYFR5cGVkQXJyYXkucHJvdG90eXBlLnN1YmFycmF5YCBmdW5jdGlvbi5cbiAqXG4gKiAgIC0gSUUxMCBoYXMgYSBicm9rZW4gYFR5cGVkQXJyYXkucHJvdG90eXBlLnN1YmFycmF5YCBmdW5jdGlvbiB3aGljaCByZXR1cm5zIGFycmF5cyBvZlxuICogICAgIGluY29ycmVjdCBsZW5ndGggaW4gc29tZSBzaXR1YXRpb25zLlxuXG4gKiBXZSBkZXRlY3QgdGhlc2UgYnVnZ3kgYnJvd3NlcnMgYW5kIHNldCBgQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRgIHRvIGBmYWxzZWAgc28gdGhleVxuICogZ2V0IHRoZSBPYmplY3QgaW1wbGVtZW50YXRpb24sIHdoaWNoIGlzIHNsb3dlciBidXQgYmVoYXZlcyBjb3JyZWN0bHkuXG4gKi9cbkJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUID0gZ2xvYmFsLlRZUEVEX0FSUkFZX1NVUFBPUlQgIT09IHVuZGVmaW5lZFxuICA/IGdsb2JhbC5UWVBFRF9BUlJBWV9TVVBQT1JUXG4gIDogdHlwZWRBcnJheVN1cHBvcnQoKVxuXG4vKlxuICogRXhwb3J0IGtNYXhMZW5ndGggYWZ0ZXIgdHlwZWQgYXJyYXkgc3VwcG9ydCBpcyBkZXRlcm1pbmVkLlxuICovXG5leHBvcnRzLmtNYXhMZW5ndGggPSBrTWF4TGVuZ3RoKClcblxuZnVuY3Rpb24gdHlwZWRBcnJheVN1cHBvcnQgKCkge1xuICB0cnkge1xuICAgIHZhciBhcnIgPSBuZXcgVWludDhBcnJheSgxKVxuICAgIGFyci5fX3Byb3RvX18gPSB7X19wcm90b19fOiBVaW50OEFycmF5LnByb3RvdHlwZSwgZm9vOiBmdW5jdGlvbiAoKSB7IHJldHVybiA0MiB9fVxuICAgIHJldHVybiBhcnIuZm9vKCkgPT09IDQyICYmIC8vIHR5cGVkIGFycmF5IGluc3RhbmNlcyBjYW4gYmUgYXVnbWVudGVkXG4gICAgICAgIHR5cGVvZiBhcnIuc3ViYXJyYXkgPT09ICdmdW5jdGlvbicgJiYgLy8gY2hyb21lIDktMTAgbGFjayBgc3ViYXJyYXlgXG4gICAgICAgIGFyci5zdWJhcnJheSgxLCAxKS5ieXRlTGVuZ3RoID09PSAwIC8vIGllMTAgaGFzIGJyb2tlbiBgc3ViYXJyYXlgXG4gIH0gY2F0Y2ggKGUpIHtcbiAgICByZXR1cm4gZmFsc2VcbiAgfVxufVxuXG5mdW5jdGlvbiBrTWF4TGVuZ3RoICgpIHtcbiAgcmV0dXJuIEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUXG4gICAgPyAweDdmZmZmZmZmXG4gICAgOiAweDNmZmZmZmZmXG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUJ1ZmZlciAodGhhdCwgbGVuZ3RoKSB7XG4gIGlmIChrTWF4TGVuZ3RoKCkgPCBsZW5ndGgpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignSW52YWxpZCB0eXBlZCBhcnJheSBsZW5ndGgnKVxuICB9XG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIC8vIFJldHVybiBhbiBhdWdtZW50ZWQgYFVpbnQ4QXJyYXlgIGluc3RhbmNlLCBmb3IgYmVzdCBwZXJmb3JtYW5jZVxuICAgIHRoYXQgPSBuZXcgVWludDhBcnJheShsZW5ndGgpXG4gICAgdGhhdC5fX3Byb3RvX18gPSBCdWZmZXIucHJvdG90eXBlXG4gIH0gZWxzZSB7XG4gICAgLy8gRmFsbGJhY2s6IFJldHVybiBhbiBvYmplY3QgaW5zdGFuY2Ugb2YgdGhlIEJ1ZmZlciBjbGFzc1xuICAgIGlmICh0aGF0ID09PSBudWxsKSB7XG4gICAgICB0aGF0ID0gbmV3IEJ1ZmZlcihsZW5ndGgpXG4gICAgfVxuICAgIHRoYXQubGVuZ3RoID0gbGVuZ3RoXG4gIH1cblxuICByZXR1cm4gdGhhdFxufVxuXG4vKipcbiAqIFRoZSBCdWZmZXIgY29uc3RydWN0b3IgcmV0dXJucyBpbnN0YW5jZXMgb2YgYFVpbnQ4QXJyYXlgIHRoYXQgaGF2ZSB0aGVpclxuICogcHJvdG90eXBlIGNoYW5nZWQgdG8gYEJ1ZmZlci5wcm90b3R5cGVgLiBGdXJ0aGVybW9yZSwgYEJ1ZmZlcmAgaXMgYSBzdWJjbGFzcyBvZlxuICogYFVpbnQ4QXJyYXlgLCBzbyB0aGUgcmV0dXJuZWQgaW5zdGFuY2VzIHdpbGwgaGF2ZSBhbGwgdGhlIG5vZGUgYEJ1ZmZlcmAgbWV0aG9kc1xuICogYW5kIHRoZSBgVWludDhBcnJheWAgbWV0aG9kcy4gU3F1YXJlIGJyYWNrZXQgbm90YXRpb24gd29ya3MgYXMgZXhwZWN0ZWQgLS0gaXRcbiAqIHJldHVybnMgYSBzaW5nbGUgb2N0ZXQuXG4gKlxuICogVGhlIGBVaW50OEFycmF5YCBwcm90b3R5cGUgcmVtYWlucyB1bm1vZGlmaWVkLlxuICovXG5cbmZ1bmN0aW9uIEJ1ZmZlciAoYXJnLCBlbmNvZGluZ09yT2Zmc2V0LCBsZW5ndGgpIHtcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCAmJiAhKHRoaXMgaW5zdGFuY2VvZiBCdWZmZXIpKSB7XG4gICAgcmV0dXJuIG5ldyBCdWZmZXIoYXJnLCBlbmNvZGluZ09yT2Zmc2V0LCBsZW5ndGgpXG4gIH1cblxuICAvLyBDb21tb24gY2FzZS5cbiAgaWYgKHR5cGVvZiBhcmcgPT09ICdudW1iZXInKSB7XG4gICAgaWYgKHR5cGVvZiBlbmNvZGluZ09yT2Zmc2V0ID09PSAnc3RyaW5nJykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAnSWYgZW5jb2RpbmcgaXMgc3BlY2lmaWVkIHRoZW4gdGhlIGZpcnN0IGFyZ3VtZW50IG11c3QgYmUgYSBzdHJpbmcnXG4gICAgICApXG4gICAgfVxuICAgIHJldHVybiBhbGxvY1Vuc2FmZSh0aGlzLCBhcmcpXG4gIH1cbiAgcmV0dXJuIGZyb20odGhpcywgYXJnLCBlbmNvZGluZ09yT2Zmc2V0LCBsZW5ndGgpXG59XG5cbkJ1ZmZlci5wb29sU2l6ZSA9IDgxOTIgLy8gbm90IHVzZWQgYnkgdGhpcyBpbXBsZW1lbnRhdGlvblxuXG4vLyBUT0RPOiBMZWdhY3ksIG5vdCBuZWVkZWQgYW55bW9yZS4gUmVtb3ZlIGluIG5leHQgbWFqb3IgdmVyc2lvbi5cbkJ1ZmZlci5fYXVnbWVudCA9IGZ1bmN0aW9uIChhcnIpIHtcbiAgYXJyLl9fcHJvdG9fXyA9IEJ1ZmZlci5wcm90b3R5cGVcbiAgcmV0dXJuIGFyclxufVxuXG5mdW5jdGlvbiBmcm9tICh0aGF0LCB2YWx1ZSwgZW5jb2RpbmdPck9mZnNldCwgbGVuZ3RoKSB7XG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignXCJ2YWx1ZVwiIGFyZ3VtZW50IG11c3Qgbm90IGJlIGEgbnVtYmVyJylcbiAgfVxuXG4gIGlmICh0eXBlb2YgQXJyYXlCdWZmZXIgIT09ICd1bmRlZmluZWQnICYmIHZhbHVlIGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHtcbiAgICByZXR1cm4gZnJvbUFycmF5QnVmZmVyKHRoYXQsIHZhbHVlLCBlbmNvZGluZ09yT2Zmc2V0LCBsZW5ndGgpXG4gIH1cblxuICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xuICAgIHJldHVybiBmcm9tU3RyaW5nKHRoYXQsIHZhbHVlLCBlbmNvZGluZ09yT2Zmc2V0KVxuICB9XG5cbiAgcmV0dXJuIGZyb21PYmplY3QodGhhdCwgdmFsdWUpXG59XG5cbi8qKlxuICogRnVuY3Rpb25hbGx5IGVxdWl2YWxlbnQgdG8gQnVmZmVyKGFyZywgZW5jb2RpbmcpIGJ1dCB0aHJvd3MgYSBUeXBlRXJyb3JcbiAqIGlmIHZhbHVlIGlzIGEgbnVtYmVyLlxuICogQnVmZmVyLmZyb20oc3RyWywgZW5jb2RpbmddKVxuICogQnVmZmVyLmZyb20oYXJyYXkpXG4gKiBCdWZmZXIuZnJvbShidWZmZXIpXG4gKiBCdWZmZXIuZnJvbShhcnJheUJ1ZmZlclssIGJ5dGVPZmZzZXRbLCBsZW5ndGhdXSlcbiAqKi9cbkJ1ZmZlci5mcm9tID0gZnVuY3Rpb24gKHZhbHVlLCBlbmNvZGluZ09yT2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGZyb20obnVsbCwgdmFsdWUsIGVuY29kaW5nT3JPZmZzZXQsIGxlbmd0aClcbn1cblxuaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gIEJ1ZmZlci5wcm90b3R5cGUuX19wcm90b19fID0gVWludDhBcnJheS5wcm90b3R5cGVcbiAgQnVmZmVyLl9fcHJvdG9fXyA9IFVpbnQ4QXJyYXlcbiAgaWYgKHR5cGVvZiBTeW1ib2wgIT09ICd1bmRlZmluZWQnICYmIFN5bWJvbC5zcGVjaWVzICYmXG4gICAgICBCdWZmZXJbU3ltYm9sLnNwZWNpZXNdID09PSBCdWZmZXIpIHtcbiAgICAvLyBGaXggc3ViYXJyYXkoKSBpbiBFUzIwMTYuIFNlZTogaHR0cHM6Ly9naXRodWIuY29tL2Zlcm9zcy9idWZmZXIvcHVsbC85N1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShCdWZmZXIsIFN5bWJvbC5zcGVjaWVzLCB7XG4gICAgICB2YWx1ZTogbnVsbCxcbiAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pXG4gIH1cbn1cblxuZnVuY3Rpb24gYXNzZXJ0U2l6ZSAoc2l6ZSkge1xuICBpZiAodHlwZW9mIHNpemUgIT09ICdudW1iZXInKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignXCJzaXplXCIgYXJndW1lbnQgbXVzdCBiZSBhIG51bWJlcicpXG4gIH1cbn1cblxuZnVuY3Rpb24gYWxsb2MgKHRoYXQsIHNpemUsIGZpbGwsIGVuY29kaW5nKSB7XG4gIGFzc2VydFNpemUoc2l6ZSlcbiAgaWYgKHNpemUgPD0gMCkge1xuICAgIHJldHVybiBjcmVhdGVCdWZmZXIodGhhdCwgc2l6ZSlcbiAgfVxuICBpZiAoZmlsbCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgLy8gT25seSBwYXkgYXR0ZW50aW9uIHRvIGVuY29kaW5nIGlmIGl0J3MgYSBzdHJpbmcuIFRoaXNcbiAgICAvLyBwcmV2ZW50cyBhY2NpZGVudGFsbHkgc2VuZGluZyBpbiBhIG51bWJlciB0aGF0IHdvdWxkXG4gICAgLy8gYmUgaW50ZXJwcmV0dGVkIGFzIGEgc3RhcnQgb2Zmc2V0LlxuICAgIHJldHVybiB0eXBlb2YgZW5jb2RpbmcgPT09ICdzdHJpbmcnXG4gICAgICA/IGNyZWF0ZUJ1ZmZlcih0aGF0LCBzaXplKS5maWxsKGZpbGwsIGVuY29kaW5nKVxuICAgICAgOiBjcmVhdGVCdWZmZXIodGhhdCwgc2l6ZSkuZmlsbChmaWxsKVxuICB9XG4gIHJldHVybiBjcmVhdGVCdWZmZXIodGhhdCwgc2l6ZSlcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgbmV3IGZpbGxlZCBCdWZmZXIgaW5zdGFuY2UuXG4gKiBhbGxvYyhzaXplWywgZmlsbFssIGVuY29kaW5nXV0pXG4gKiovXG5CdWZmZXIuYWxsb2MgPSBmdW5jdGlvbiAoc2l6ZSwgZmlsbCwgZW5jb2RpbmcpIHtcbiAgcmV0dXJuIGFsbG9jKG51bGwsIHNpemUsIGZpbGwsIGVuY29kaW5nKVxufVxuXG5mdW5jdGlvbiBhbGxvY1Vuc2FmZSAodGhhdCwgc2l6ZSkge1xuICBhc3NlcnRTaXplKHNpemUpXG4gIHRoYXQgPSBjcmVhdGVCdWZmZXIodGhhdCwgc2l6ZSA8IDAgPyAwIDogY2hlY2tlZChzaXplKSB8IDApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNpemU7ICsraSkge1xuICAgICAgdGhhdFtpXSA9IDBcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHRoYXRcbn1cblxuLyoqXG4gKiBFcXVpdmFsZW50IHRvIEJ1ZmZlcihudW0pLCBieSBkZWZhdWx0IGNyZWF0ZXMgYSBub24temVyby1maWxsZWQgQnVmZmVyIGluc3RhbmNlLlxuICogKi9cbkJ1ZmZlci5hbGxvY1Vuc2FmZSA9IGZ1bmN0aW9uIChzaXplKSB7XG4gIHJldHVybiBhbGxvY1Vuc2FmZShudWxsLCBzaXplKVxufVxuLyoqXG4gKiBFcXVpdmFsZW50IHRvIFNsb3dCdWZmZXIobnVtKSwgYnkgZGVmYXVsdCBjcmVhdGVzIGEgbm9uLXplcm8tZmlsbGVkIEJ1ZmZlciBpbnN0YW5jZS5cbiAqL1xuQnVmZmVyLmFsbG9jVW5zYWZlU2xvdyA9IGZ1bmN0aW9uIChzaXplKSB7XG4gIHJldHVybiBhbGxvY1Vuc2FmZShudWxsLCBzaXplKVxufVxuXG5mdW5jdGlvbiBmcm9tU3RyaW5nICh0aGF0LCBzdHJpbmcsIGVuY29kaW5nKSB7XG4gIGlmICh0eXBlb2YgZW5jb2RpbmcgIT09ICdzdHJpbmcnIHx8IGVuY29kaW5nID09PSAnJykge1xuICAgIGVuY29kaW5nID0gJ3V0ZjgnXG4gIH1cblxuICBpZiAoIUJ1ZmZlci5pc0VuY29kaW5nKGVuY29kaW5nKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1wiZW5jb2RpbmdcIiBtdXN0IGJlIGEgdmFsaWQgc3RyaW5nIGVuY29kaW5nJylcbiAgfVxuXG4gIHZhciBsZW5ndGggPSBieXRlTGVuZ3RoKHN0cmluZywgZW5jb2RpbmcpIHwgMFxuICB0aGF0ID0gY3JlYXRlQnVmZmVyKHRoYXQsIGxlbmd0aClcblxuICB0aGF0LndyaXRlKHN0cmluZywgZW5jb2RpbmcpXG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheUxpa2UgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBjcmVhdGVCdWZmZXIodGhhdCwgbGVuZ3RoKVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSArPSAxKSB7XG4gICAgdGhhdFtpXSA9IGFycmF5W2ldICYgMjU1XG4gIH1cbiAgcmV0dXJuIHRoYXRcbn1cblxuZnVuY3Rpb24gZnJvbUFycmF5QnVmZmVyICh0aGF0LCBhcnJheSwgYnl0ZU9mZnNldCwgbGVuZ3RoKSB7XG4gIGFycmF5LmJ5dGVMZW5ndGggLy8gdGhpcyB0aHJvd3MgaWYgYGFycmF5YCBpcyBub3QgYSB2YWxpZCBBcnJheUJ1ZmZlclxuXG4gIGlmIChieXRlT2Zmc2V0IDwgMCB8fCBhcnJheS5ieXRlTGVuZ3RoIDwgYnl0ZU9mZnNldCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdcXCdvZmZzZXRcXCcgaXMgb3V0IG9mIGJvdW5kcycpXG4gIH1cblxuICBpZiAoYXJyYXkuYnl0ZUxlbmd0aCA8IGJ5dGVPZmZzZXQgKyAobGVuZ3RoIHx8IDApKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ1xcJ2xlbmd0aFxcJyBpcyBvdXQgb2YgYm91bmRzJylcbiAgfVxuXG4gIGlmIChieXRlT2Zmc2V0ID09PSB1bmRlZmluZWQgJiYgbGVuZ3RoID09PSB1bmRlZmluZWQpIHtcbiAgICBhcnJheSA9IG5ldyBVaW50OEFycmF5KGFycmF5KVxuICB9IGVsc2UgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgYXJyYXkgPSBuZXcgVWludDhBcnJheShhcnJheSwgYnl0ZU9mZnNldClcbiAgfSBlbHNlIHtcbiAgICBhcnJheSA9IG5ldyBVaW50OEFycmF5KGFycmF5LCBieXRlT2Zmc2V0LCBsZW5ndGgpXG4gIH1cblxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICAvLyBSZXR1cm4gYW4gYXVnbWVudGVkIGBVaW50OEFycmF5YCBpbnN0YW5jZSwgZm9yIGJlc3QgcGVyZm9ybWFuY2VcbiAgICB0aGF0ID0gYXJyYXlcbiAgICB0aGF0Ll9fcHJvdG9fXyA9IEJ1ZmZlci5wcm90b3R5cGVcbiAgfSBlbHNlIHtcbiAgICAvLyBGYWxsYmFjazogUmV0dXJuIGFuIG9iamVjdCBpbnN0YW5jZSBvZiB0aGUgQnVmZmVyIGNsYXNzXG4gICAgdGhhdCA9IGZyb21BcnJheUxpa2UodGhhdCwgYXJyYXkpXG4gIH1cbiAgcmV0dXJuIHRoYXRcbn1cblxuZnVuY3Rpb24gZnJvbU9iamVjdCAodGhhdCwgb2JqKSB7XG4gIGlmIChCdWZmZXIuaXNCdWZmZXIob2JqKSkge1xuICAgIHZhciBsZW4gPSBjaGVja2VkKG9iai5sZW5ndGgpIHwgMFxuICAgIHRoYXQgPSBjcmVhdGVCdWZmZXIodGhhdCwgbGVuKVxuXG4gICAgaWYgKHRoYXQubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gdGhhdFxuICAgIH1cblxuICAgIG9iai5jb3B5KHRoYXQsIDAsIDAsIGxlbilcbiAgICByZXR1cm4gdGhhdFxuICB9XG5cbiAgaWYgKG9iaikge1xuICAgIGlmICgodHlwZW9mIEFycmF5QnVmZmVyICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICBvYmouYnVmZmVyIGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHx8ICdsZW5ndGgnIGluIG9iaikge1xuICAgICAgaWYgKHR5cGVvZiBvYmoubGVuZ3RoICE9PSAnbnVtYmVyJyB8fCBpc25hbihvYmoubGVuZ3RoKSkge1xuICAgICAgICByZXR1cm4gY3JlYXRlQnVmZmVyKHRoYXQsIDApXG4gICAgICB9XG4gICAgICByZXR1cm4gZnJvbUFycmF5TGlrZSh0aGF0LCBvYmopXG4gICAgfVxuXG4gICAgaWYgKG9iai50eXBlID09PSAnQnVmZmVyJyAmJiBpc0FycmF5KG9iai5kYXRhKSkge1xuICAgICAgcmV0dXJuIGZyb21BcnJheUxpa2UodGhhdCwgb2JqLmRhdGEpXG4gICAgfVxuICB9XG5cbiAgdGhyb3cgbmV3IFR5cGVFcnJvcignRmlyc3QgYXJndW1lbnQgbXVzdCBiZSBhIHN0cmluZywgQnVmZmVyLCBBcnJheUJ1ZmZlciwgQXJyYXksIG9yIGFycmF5LWxpa2Ugb2JqZWN0LicpXG59XG5cbmZ1bmN0aW9uIGNoZWNrZWQgKGxlbmd0aCkge1xuICAvLyBOb3RlOiBjYW5ub3QgdXNlIGBsZW5ndGggPCBrTWF4TGVuZ3RoYCBoZXJlIGJlY2F1c2UgdGhhdCBmYWlscyB3aGVuXG4gIC8vIGxlbmd0aCBpcyBOYU4gKHdoaWNoIGlzIG90aGVyd2lzZSBjb2VyY2VkIHRvIHplcm8uKVxuICBpZiAobGVuZ3RoID49IGtNYXhMZW5ndGgoKSkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdBdHRlbXB0IHRvIGFsbG9jYXRlIEJ1ZmZlciBsYXJnZXIgdGhhbiBtYXhpbXVtICcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICdzaXplOiAweCcgKyBrTWF4TGVuZ3RoKCkudG9TdHJpbmcoMTYpICsgJyBieXRlcycpXG4gIH1cbiAgcmV0dXJuIGxlbmd0aCB8IDBcbn1cblxuZnVuY3Rpb24gU2xvd0J1ZmZlciAobGVuZ3RoKSB7XG4gIGlmICgrbGVuZ3RoICE9IGxlbmd0aCkgeyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIGVxZXFlcVxuICAgIGxlbmd0aCA9IDBcbiAgfVxuICByZXR1cm4gQnVmZmVyLmFsbG9jKCtsZW5ndGgpXG59XG5cbkJ1ZmZlci5pc0J1ZmZlciA9IGZ1bmN0aW9uIGlzQnVmZmVyIChiKSB7XG4gIHJldHVybiAhIShiICE9IG51bGwgJiYgYi5faXNCdWZmZXIpXG59XG5cbkJ1ZmZlci5jb21wYXJlID0gZnVuY3Rpb24gY29tcGFyZSAoYSwgYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihhKSB8fCAhQnVmZmVyLmlzQnVmZmVyKGIpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnRzIG11c3QgYmUgQnVmZmVycycpXG4gIH1cblxuICBpZiAoYSA9PT0gYikgcmV0dXJuIDBcblxuICB2YXIgeCA9IGEubGVuZ3RoXG4gIHZhciB5ID0gYi5sZW5ndGhcblxuICBmb3IgKHZhciBpID0gMCwgbGVuID0gTWF0aC5taW4oeCwgeSk7IGkgPCBsZW47ICsraSkge1xuICAgIGlmIChhW2ldICE9PSBiW2ldKSB7XG4gICAgICB4ID0gYVtpXVxuICAgICAgeSA9IGJbaV1cbiAgICAgIGJyZWFrXG4gICAgfVxuICB9XG5cbiAgaWYgKHggPCB5KSByZXR1cm4gLTFcbiAgaWYgKHkgPCB4KSByZXR1cm4gMVxuICByZXR1cm4gMFxufVxuXG5CdWZmZXIuaXNFbmNvZGluZyA9IGZ1bmN0aW9uIGlzRW5jb2RpbmcgKGVuY29kaW5nKSB7XG4gIHN3aXRjaCAoU3RyaW5nKGVuY29kaW5nKS50b0xvd2VyQ2FzZSgpKSB7XG4gICAgY2FzZSAnaGV4JzpcbiAgICBjYXNlICd1dGY4JzpcbiAgICBjYXNlICd1dGYtOCc6XG4gICAgY2FzZSAnYXNjaWknOlxuICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgY2FzZSAnYmFzZTY0JzpcbiAgICBjYXNlICdyYXcnOlxuICAgIGNhc2UgJ3VjczInOlxuICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICBjYXNlICd1dGYxNmxlJzpcbiAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICByZXR1cm4gdHJ1ZVxuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gZmFsc2VcbiAgfVxufVxuXG5CdWZmZXIuY29uY2F0ID0gZnVuY3Rpb24gY29uY2F0IChsaXN0LCBsZW5ndGgpIHtcbiAgaWYgKCFpc0FycmF5KGxpc3QpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignXCJsaXN0XCIgYXJndW1lbnQgbXVzdCBiZSBhbiBBcnJheSBvZiBCdWZmZXJzJylcbiAgfVxuXG4gIGlmIChsaXN0Lmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBCdWZmZXIuYWxsb2MoMClcbiAgfVxuXG4gIHZhciBpXG4gIGlmIChsZW5ndGggPT09IHVuZGVmaW5lZCkge1xuICAgIGxlbmd0aCA9IDBcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGlzdC5sZW5ndGg7ICsraSkge1xuICAgICAgbGVuZ3RoICs9IGxpc3RbaV0ubGVuZ3RoXG4gICAgfVxuICB9XG5cbiAgdmFyIGJ1ZmZlciA9IEJ1ZmZlci5hbGxvY1Vuc2FmZShsZW5ndGgpXG4gIHZhciBwb3MgPSAwXG4gIGZvciAoaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgKytpKSB7XG4gICAgdmFyIGJ1ZiA9IGxpc3RbaV1cbiAgICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihidWYpKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdcImxpc3RcIiBhcmd1bWVudCBtdXN0IGJlIGFuIEFycmF5IG9mIEJ1ZmZlcnMnKVxuICAgIH1cbiAgICBidWYuY29weShidWZmZXIsIHBvcylcbiAgICBwb3MgKz0gYnVmLmxlbmd0aFxuICB9XG4gIHJldHVybiBidWZmZXJcbn1cblxuZnVuY3Rpb24gYnl0ZUxlbmd0aCAoc3RyaW5nLCBlbmNvZGluZykge1xuICBpZiAoQnVmZmVyLmlzQnVmZmVyKHN0cmluZykpIHtcbiAgICByZXR1cm4gc3RyaW5nLmxlbmd0aFxuICB9XG4gIGlmICh0eXBlb2YgQXJyYXlCdWZmZXIgIT09ICd1bmRlZmluZWQnICYmIHR5cGVvZiBBcnJheUJ1ZmZlci5pc1ZpZXcgPT09ICdmdW5jdGlvbicgJiZcbiAgICAgIChBcnJheUJ1ZmZlci5pc1ZpZXcoc3RyaW5nKSB8fCBzdHJpbmcgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikpIHtcbiAgICByZXR1cm4gc3RyaW5nLmJ5dGVMZW5ndGhcbiAgfVxuICBpZiAodHlwZW9mIHN0cmluZyAhPT0gJ3N0cmluZycpIHtcbiAgICBzdHJpbmcgPSAnJyArIHN0cmluZ1xuICB9XG5cbiAgdmFyIGxlbiA9IHN0cmluZy5sZW5ndGhcbiAgaWYgKGxlbiA9PT0gMCkgcmV0dXJuIDBcblxuICAvLyBVc2UgYSBmb3IgbG9vcCB0byBhdm9pZCByZWN1cnNpb25cbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcbiAgZm9yICg7Oykge1xuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICBjYXNlICdyYXcnOlxuICAgICAgY2FzZSAncmF3cyc6XG4gICAgICAgIHJldHVybiBsZW5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgY2FzZSB1bmRlZmluZWQ6XG4gICAgICAgIHJldHVybiB1dGY4VG9CeXRlcyhzdHJpbmcpLmxlbmd0aFxuICAgICAgY2FzZSAndWNzMic6XG4gICAgICBjYXNlICd1Y3MtMic6XG4gICAgICBjYXNlICd1dGYxNmxlJzpcbiAgICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgICAgcmV0dXJuIGxlbiAqIDJcbiAgICAgIGNhc2UgJ2hleCc6XG4gICAgICAgIHJldHVybiBsZW4gPj4+IDFcbiAgICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgICAgIHJldHVybiBiYXNlNjRUb0J5dGVzKHN0cmluZykubGVuZ3RoXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBpZiAobG93ZXJlZENhc2UpIHJldHVybiB1dGY4VG9CeXRlcyhzdHJpbmcpLmxlbmd0aCAvLyBhc3N1bWUgdXRmOFxuICAgICAgICBlbmNvZGluZyA9ICgnJyArIGVuY29kaW5nKS50b0xvd2VyQ2FzZSgpXG4gICAgICAgIGxvd2VyZWRDYXNlID0gdHJ1ZVxuICAgIH1cbiAgfVxufVxuQnVmZmVyLmJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoXG5cbmZ1bmN0aW9uIHNsb3dUb1N0cmluZyAoZW5jb2RpbmcsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcblxuICAvLyBObyBuZWVkIHRvIHZlcmlmeSB0aGF0IFwidGhpcy5sZW5ndGggPD0gTUFYX1VJTlQzMlwiIHNpbmNlIGl0J3MgYSByZWFkLW9ubHlcbiAgLy8gcHJvcGVydHkgb2YgYSB0eXBlZCBhcnJheS5cblxuICAvLyBUaGlzIGJlaGF2ZXMgbmVpdGhlciBsaWtlIFN0cmluZyBub3IgVWludDhBcnJheSBpbiB0aGF0IHdlIHNldCBzdGFydC9lbmRcbiAgLy8gdG8gdGhlaXIgdXBwZXIvbG93ZXIgYm91bmRzIGlmIHRoZSB2YWx1ZSBwYXNzZWQgaXMgb3V0IG9mIHJhbmdlLlxuICAvLyB1bmRlZmluZWQgaXMgaGFuZGxlZCBzcGVjaWFsbHkgYXMgcGVyIEVDTUEtMjYyIDZ0aCBFZGl0aW9uLFxuICAvLyBTZWN0aW9uIDEzLjMuMy43IFJ1bnRpbWUgU2VtYW50aWNzOiBLZXllZEJpbmRpbmdJbml0aWFsaXphdGlvbi5cbiAgaWYgKHN0YXJ0ID09PSB1bmRlZmluZWQgfHwgc3RhcnQgPCAwKSB7XG4gICAgc3RhcnQgPSAwXG4gIH1cbiAgLy8gUmV0dXJuIGVhcmx5IGlmIHN0YXJ0ID4gdGhpcy5sZW5ndGguIERvbmUgaGVyZSB0byBwcmV2ZW50IHBvdGVudGlhbCB1aW50MzJcbiAgLy8gY29lcmNpb24gZmFpbCBiZWxvdy5cbiAgaWYgKHN0YXJ0ID4gdGhpcy5sZW5ndGgpIHtcbiAgICByZXR1cm4gJydcbiAgfVxuXG4gIGlmIChlbmQgPT09IHVuZGVmaW5lZCB8fCBlbmQgPiB0aGlzLmxlbmd0aCkge1xuICAgIGVuZCA9IHRoaXMubGVuZ3RoXG4gIH1cblxuICBpZiAoZW5kIDw9IDApIHtcbiAgICByZXR1cm4gJydcbiAgfVxuXG4gIC8vIEZvcmNlIGNvZXJzaW9uIHRvIHVpbnQzMi4gVGhpcyB3aWxsIGFsc28gY29lcmNlIGZhbHNleS9OYU4gdmFsdWVzIHRvIDAuXG4gIGVuZCA+Pj49IDBcbiAgc3RhcnQgPj4+PSAwXG5cbiAgaWYgKGVuZCA8PSBzdGFydCkge1xuICAgIHJldHVybiAnJ1xuICB9XG5cbiAgaWYgKCFlbmNvZGluZykgZW5jb2RpbmcgPSAndXRmOCdcblxuICB3aGlsZSAodHJ1ZSkge1xuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgIGNhc2UgJ2hleCc6XG4gICAgICAgIHJldHVybiBoZXhTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICd1dGY4JzpcbiAgICAgIGNhc2UgJ3V0Zi04JzpcbiAgICAgICAgcmV0dXJuIHV0ZjhTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICdhc2NpaSc6XG4gICAgICAgIHJldHVybiBhc2NpaVNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICAgIHJldHVybiBiaW5hcnlTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICdiYXNlNjQnOlxuICAgICAgICByZXR1cm4gYmFzZTY0U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAndWNzMic6XG4gICAgICBjYXNlICd1Y3MtMic6XG4gICAgICBjYXNlICd1dGYxNmxlJzpcbiAgICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgICAgcmV0dXJuIHV0ZjE2bGVTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBpZiAobG93ZXJlZENhc2UpIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Vua25vd24gZW5jb2Rpbmc6ICcgKyBlbmNvZGluZylcbiAgICAgICAgZW5jb2RpbmcgPSAoZW5jb2RpbmcgKyAnJykudG9Mb3dlckNhc2UoKVxuICAgICAgICBsb3dlcmVkQ2FzZSA9IHRydWVcbiAgICB9XG4gIH1cbn1cblxuLy8gVGhlIHByb3BlcnR5IGlzIHVzZWQgYnkgYEJ1ZmZlci5pc0J1ZmZlcmAgYW5kIGBpcy1idWZmZXJgIChpbiBTYWZhcmkgNS03KSB0byBkZXRlY3Rcbi8vIEJ1ZmZlciBpbnN0YW5jZXMuXG5CdWZmZXIucHJvdG90eXBlLl9pc0J1ZmZlciA9IHRydWVcblxuZnVuY3Rpb24gc3dhcCAoYiwgbiwgbSkge1xuICB2YXIgaSA9IGJbbl1cbiAgYltuXSA9IGJbbV1cbiAgYlttXSA9IGlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5zd2FwMTYgPSBmdW5jdGlvbiBzd2FwMTYgKCkge1xuICB2YXIgbGVuID0gdGhpcy5sZW5ndGhcbiAgaWYgKGxlbiAlIDIgIT09IDApIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignQnVmZmVyIHNpemUgbXVzdCBiZSBhIG11bHRpcGxlIG9mIDE2LWJpdHMnKVxuICB9XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuOyBpICs9IDIpIHtcbiAgICBzd2FwKHRoaXMsIGksIGkgKyAxKVxuICB9XG4gIHJldHVybiB0aGlzXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuc3dhcDMyID0gZnVuY3Rpb24gc3dhcDMyICgpIHtcbiAgdmFyIGxlbiA9IHRoaXMubGVuZ3RoXG4gIGlmIChsZW4gJSA0ICE9PSAwKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ0J1ZmZlciBzaXplIG11c3QgYmUgYSBtdWx0aXBsZSBvZiAzMi1iaXRzJylcbiAgfVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbjsgaSArPSA0KSB7XG4gICAgc3dhcCh0aGlzLCBpLCBpICsgMylcbiAgICBzd2FwKHRoaXMsIGkgKyAxLCBpICsgMilcbiAgfVxuICByZXR1cm4gdGhpc1xufVxuXG5CdWZmZXIucHJvdG90eXBlLnRvU3RyaW5nID0gZnVuY3Rpb24gdG9TdHJpbmcgKCkge1xuICB2YXIgbGVuZ3RoID0gdGhpcy5sZW5ndGggfCAwXG4gIGlmIChsZW5ndGggPT09IDApIHJldHVybiAnJ1xuICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHV0ZjhTbGljZSh0aGlzLCAwLCBsZW5ndGgpXG4gIHJldHVybiBzbG93VG9TdHJpbmcuYXBwbHkodGhpcywgYXJndW1lbnRzKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLmVxdWFscyA9IGZ1bmN0aW9uIGVxdWFscyAoYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihiKSkgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnQgbXVzdCBiZSBhIEJ1ZmZlcicpXG4gIGlmICh0aGlzID09PSBiKSByZXR1cm4gdHJ1ZVxuICByZXR1cm4gQnVmZmVyLmNvbXBhcmUodGhpcywgYikgPT09IDBcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5pbnNwZWN0ID0gZnVuY3Rpb24gaW5zcGVjdCAoKSB7XG4gIHZhciBzdHIgPSAnJ1xuICB2YXIgbWF4ID0gZXhwb3J0cy5JTlNQRUNUX01BWF9CWVRFU1xuICBpZiAodGhpcy5sZW5ndGggPiAwKSB7XG4gICAgc3RyID0gdGhpcy50b1N0cmluZygnaGV4JywgMCwgbWF4KS5tYXRjaCgvLnsyfS9nKS5qb2luKCcgJylcbiAgICBpZiAodGhpcy5sZW5ndGggPiBtYXgpIHN0ciArPSAnIC4uLiAnXG4gIH1cbiAgcmV0dXJuICc8QnVmZmVyICcgKyBzdHIgKyAnPidcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5jb21wYXJlID0gZnVuY3Rpb24gY29tcGFyZSAodGFyZ2V0LCBzdGFydCwgZW5kLCB0aGlzU3RhcnQsIHRoaXNFbmQpIHtcbiAgaWYgKCFCdWZmZXIuaXNCdWZmZXIodGFyZ2V0KSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0FyZ3VtZW50IG11c3QgYmUgYSBCdWZmZXInKVxuICB9XG5cbiAgaWYgKHN0YXJ0ID09PSB1bmRlZmluZWQpIHtcbiAgICBzdGFydCA9IDBcbiAgfVxuICBpZiAoZW5kID09PSB1bmRlZmluZWQpIHtcbiAgICBlbmQgPSB0YXJnZXQgPyB0YXJnZXQubGVuZ3RoIDogMFxuICB9XG4gIGlmICh0aGlzU3RhcnQgPT09IHVuZGVmaW5lZCkge1xuICAgIHRoaXNTdGFydCA9IDBcbiAgfVxuICBpZiAodGhpc0VuZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgdGhpc0VuZCA9IHRoaXMubGVuZ3RoXG4gIH1cblxuICBpZiAoc3RhcnQgPCAwIHx8IGVuZCA+IHRhcmdldC5sZW5ndGggfHwgdGhpc1N0YXJ0IDwgMCB8fCB0aGlzRW5kID4gdGhpcy5sZW5ndGgpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignb3V0IG9mIHJhbmdlIGluZGV4JylcbiAgfVxuXG4gIGlmICh0aGlzU3RhcnQgPj0gdGhpc0VuZCAmJiBzdGFydCA+PSBlbmQpIHtcbiAgICByZXR1cm4gMFxuICB9XG4gIGlmICh0aGlzU3RhcnQgPj0gdGhpc0VuZCkge1xuICAgIHJldHVybiAtMVxuICB9XG4gIGlmIChzdGFydCA+PSBlbmQpIHtcbiAgICByZXR1cm4gMVxuICB9XG5cbiAgc3RhcnQgPj4+PSAwXG4gIGVuZCA+Pj49IDBcbiAgdGhpc1N0YXJ0ID4+Pj0gMFxuICB0aGlzRW5kID4+Pj0gMFxuXG4gIGlmICh0aGlzID09PSB0YXJnZXQpIHJldHVybiAwXG5cbiAgdmFyIHggPSB0aGlzRW5kIC0gdGhpc1N0YXJ0XG4gIHZhciB5ID0gZW5kIC0gc3RhcnRcbiAgdmFyIGxlbiA9IE1hdGgubWluKHgsIHkpXG5cbiAgdmFyIHRoaXNDb3B5ID0gdGhpcy5zbGljZSh0aGlzU3RhcnQsIHRoaXNFbmQpXG4gIHZhciB0YXJnZXRDb3B5ID0gdGFyZ2V0LnNsaWNlKHN0YXJ0LCBlbmQpXG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW47ICsraSkge1xuICAgIGlmICh0aGlzQ29weVtpXSAhPT0gdGFyZ2V0Q29weVtpXSkge1xuICAgICAgeCA9IHRoaXNDb3B5W2ldXG4gICAgICB5ID0gdGFyZ2V0Q29weVtpXVxuICAgICAgYnJlYWtcbiAgICB9XG4gIH1cblxuICBpZiAoeCA8IHkpIHJldHVybiAtMVxuICBpZiAoeSA8IHgpIHJldHVybiAxXG4gIHJldHVybiAwXG59XG5cbmZ1bmN0aW9uIGFycmF5SW5kZXhPZiAoYXJyLCB2YWwsIGJ5dGVPZmZzZXQsIGVuY29kaW5nKSB7XG4gIHZhciBpbmRleFNpemUgPSAxXG4gIHZhciBhcnJMZW5ndGggPSBhcnIubGVuZ3RoXG4gIHZhciB2YWxMZW5ndGggPSB2YWwubGVuZ3RoXG5cbiAgaWYgKGVuY29kaW5nICE9PSB1bmRlZmluZWQpIHtcbiAgICBlbmNvZGluZyA9IFN0cmluZyhlbmNvZGluZykudG9Mb3dlckNhc2UoKVxuICAgIGlmIChlbmNvZGluZyA9PT0gJ3VjczInIHx8IGVuY29kaW5nID09PSAndWNzLTInIHx8XG4gICAgICAgIGVuY29kaW5nID09PSAndXRmMTZsZScgfHwgZW5jb2RpbmcgPT09ICd1dGYtMTZsZScpIHtcbiAgICAgIGlmIChhcnIubGVuZ3RoIDwgMiB8fCB2YWwubGVuZ3RoIDwgMikge1xuICAgICAgICByZXR1cm4gLTFcbiAgICAgIH1cbiAgICAgIGluZGV4U2l6ZSA9IDJcbiAgICAgIGFyckxlbmd0aCAvPSAyXG4gICAgICB2YWxMZW5ndGggLz0gMlxuICAgICAgYnl0ZU9mZnNldCAvPSAyXG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gcmVhZCAoYnVmLCBpKSB7XG4gICAgaWYgKGluZGV4U2l6ZSA9PT0gMSkge1xuICAgICAgcmV0dXJuIGJ1ZltpXVxuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gYnVmLnJlYWRVSW50MTZCRShpICogaW5kZXhTaXplKVxuICAgIH1cbiAgfVxuXG4gIHZhciBmb3VuZEluZGV4ID0gLTFcbiAgZm9yICh2YXIgaSA9IGJ5dGVPZmZzZXQ7IGkgPCBhcnJMZW5ndGg7ICsraSkge1xuICAgIGlmIChyZWFkKGFyciwgaSkgPT09IHJlYWQodmFsLCBmb3VuZEluZGV4ID09PSAtMSA/IDAgOiBpIC0gZm91bmRJbmRleCkpIHtcbiAgICAgIGlmIChmb3VuZEluZGV4ID09PSAtMSkgZm91bmRJbmRleCA9IGlcbiAgICAgIGlmIChpIC0gZm91bmRJbmRleCArIDEgPT09IHZhbExlbmd0aCkgcmV0dXJuIGZvdW5kSW5kZXggKiBpbmRleFNpemVcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKGZvdW5kSW5kZXggIT09IC0xKSBpIC09IGkgLSBmb3VuZEluZGV4XG4gICAgICBmb3VuZEluZGV4ID0gLTFcbiAgICB9XG4gIH1cblxuICByZXR1cm4gLTFcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5pbmRleE9mID0gZnVuY3Rpb24gaW5kZXhPZiAodmFsLCBieXRlT2Zmc2V0LCBlbmNvZGluZykge1xuICBpZiAodHlwZW9mIGJ5dGVPZmZzZXQgPT09ICdzdHJpbmcnKSB7XG4gICAgZW5jb2RpbmcgPSBieXRlT2Zmc2V0XG4gICAgYnl0ZU9mZnNldCA9IDBcbiAgfSBlbHNlIGlmIChieXRlT2Zmc2V0ID4gMHg3ZmZmZmZmZikge1xuICAgIGJ5dGVPZmZzZXQgPSAweDdmZmZmZmZmXG4gIH0gZWxzZSBpZiAoYnl0ZU9mZnNldCA8IC0weDgwMDAwMDAwKSB7XG4gICAgYnl0ZU9mZnNldCA9IC0weDgwMDAwMDAwXG4gIH1cbiAgYnl0ZU9mZnNldCA+Pj0gMFxuXG4gIGlmICh0aGlzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIC0xXG4gIGlmIChieXRlT2Zmc2V0ID49IHRoaXMubGVuZ3RoKSByZXR1cm4gLTFcblxuICAvLyBOZWdhdGl2ZSBvZmZzZXRzIHN0YXJ0IGZyb20gdGhlIGVuZCBvZiB0aGUgYnVmZmVyXG4gIGlmIChieXRlT2Zmc2V0IDwgMCkgYnl0ZU9mZnNldCA9IE1hdGgubWF4KHRoaXMubGVuZ3RoICsgYnl0ZU9mZnNldCwgMClcblxuICBpZiAodHlwZW9mIHZhbCA9PT0gJ3N0cmluZycpIHtcbiAgICB2YWwgPSBCdWZmZXIuZnJvbSh2YWwsIGVuY29kaW5nKVxuICB9XG5cbiAgaWYgKEJ1ZmZlci5pc0J1ZmZlcih2YWwpKSB7XG4gICAgLy8gc3BlY2lhbCBjYXNlOiBsb29raW5nIGZvciBlbXB0eSBzdHJpbmcvYnVmZmVyIGFsd2F5cyBmYWlsc1xuICAgIGlmICh2YWwubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gLTFcbiAgICB9XG4gICAgcmV0dXJuIGFycmF5SW5kZXhPZih0aGlzLCB2YWwsIGJ5dGVPZmZzZXQsIGVuY29kaW5nKVxuICB9XG4gIGlmICh0eXBlb2YgdmFsID09PSAnbnVtYmVyJykge1xuICAgIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCAmJiBVaW50OEFycmF5LnByb3RvdHlwZS5pbmRleE9mID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICByZXR1cm4gVWludDhBcnJheS5wcm90b3R5cGUuaW5kZXhPZi5jYWxsKHRoaXMsIHZhbCwgYnl0ZU9mZnNldClcbiAgICB9XG4gICAgcmV0dXJuIGFycmF5SW5kZXhPZih0aGlzLCBbIHZhbCBdLCBieXRlT2Zmc2V0LCBlbmNvZGluZylcbiAgfVxuXG4gIHRocm93IG5ldyBUeXBlRXJyb3IoJ3ZhbCBtdXN0IGJlIHN0cmluZywgbnVtYmVyIG9yIEJ1ZmZlcicpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuaW5jbHVkZXMgPSBmdW5jdGlvbiBpbmNsdWRlcyAodmFsLCBieXRlT2Zmc2V0LCBlbmNvZGluZykge1xuICByZXR1cm4gdGhpcy5pbmRleE9mKHZhbCwgYnl0ZU9mZnNldCwgZW5jb2RpbmcpICE9PSAtMVxufVxuXG5mdW5jdGlvbiBoZXhXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIG9mZnNldCA9IE51bWJlcihvZmZzZXQpIHx8IDBcbiAgdmFyIHJlbWFpbmluZyA9IGJ1Zi5sZW5ndGggLSBvZmZzZXRcbiAgaWYgKCFsZW5ndGgpIHtcbiAgICBsZW5ndGggPSByZW1haW5pbmdcbiAgfSBlbHNlIHtcbiAgICBsZW5ndGggPSBOdW1iZXIobGVuZ3RoKVxuICAgIGlmIChsZW5ndGggPiByZW1haW5pbmcpIHtcbiAgICAgIGxlbmd0aCA9IHJlbWFpbmluZ1xuICAgIH1cbiAgfVxuXG4gIC8vIG11c3QgYmUgYW4gZXZlbiBudW1iZXIgb2YgZGlnaXRzXG4gIHZhciBzdHJMZW4gPSBzdHJpbmcubGVuZ3RoXG4gIGlmIChzdHJMZW4gJSAyICE9PSAwKSB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgaGV4IHN0cmluZycpXG5cbiAgaWYgKGxlbmd0aCA+IHN0ckxlbiAvIDIpIHtcbiAgICBsZW5ndGggPSBzdHJMZW4gLyAyXG4gIH1cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7ICsraSkge1xuICAgIHZhciBwYXJzZWQgPSBwYXJzZUludChzdHJpbmcuc3Vic3RyKGkgKiAyLCAyKSwgMTYpXG4gICAgaWYgKGlzTmFOKHBhcnNlZCkpIHJldHVybiBpXG4gICAgYnVmW29mZnNldCArIGldID0gcGFyc2VkXG4gIH1cbiAgcmV0dXJuIGlcbn1cblxuZnVuY3Rpb24gdXRmOFdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIodXRmOFRvQnl0ZXMoc3RyaW5nLCBidWYubGVuZ3RoIC0gb2Zmc2V0KSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gYXNjaWlXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKGFzY2lpVG9CeXRlcyhzdHJpbmcpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiBiaW5hcnlXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBhc2NpaVdyaXRlKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gYmFzZTY0V3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcihiYXNlNjRUb0J5dGVzKHN0cmluZyksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIHVjczJXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKHV0ZjE2bGVUb0J5dGVzKHN0cmluZywgYnVmLmxlbmd0aCAtIG9mZnNldCksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGUgPSBmdW5jdGlvbiB3cml0ZSAoc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCwgZW5jb2RpbmcpIHtcbiAgLy8gQnVmZmVyI3dyaXRlKHN0cmluZylcbiAgaWYgKG9mZnNldCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgZW5jb2RpbmcgPSAndXRmOCdcbiAgICBsZW5ndGggPSB0aGlzLmxlbmd0aFxuICAgIG9mZnNldCA9IDBcbiAgLy8gQnVmZmVyI3dyaXRlKHN0cmluZywgZW5jb2RpbmcpXG4gIH0gZWxzZSBpZiAobGVuZ3RoID09PSB1bmRlZmluZWQgJiYgdHlwZW9mIG9mZnNldCA9PT0gJ3N0cmluZycpIHtcbiAgICBlbmNvZGluZyA9IG9mZnNldFxuICAgIGxlbmd0aCA9IHRoaXMubGVuZ3RoXG4gICAgb2Zmc2V0ID0gMFxuICAvLyBCdWZmZXIjd3JpdGUoc3RyaW5nLCBvZmZzZXRbLCBsZW5ndGhdWywgZW5jb2RpbmddKVxuICB9IGVsc2UgaWYgKGlzRmluaXRlKG9mZnNldCkpIHtcbiAgICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gICAgaWYgKGlzRmluaXRlKGxlbmd0aCkpIHtcbiAgICAgIGxlbmd0aCA9IGxlbmd0aCB8IDBcbiAgICAgIGlmIChlbmNvZGluZyA9PT0gdW5kZWZpbmVkKSBlbmNvZGluZyA9ICd1dGY4J1xuICAgIH0gZWxzZSB7XG4gICAgICBlbmNvZGluZyA9IGxlbmd0aFxuICAgICAgbGVuZ3RoID0gdW5kZWZpbmVkXG4gICAgfVxuICAvLyBsZWdhY3kgd3JpdGUoc3RyaW5nLCBlbmNvZGluZywgb2Zmc2V0LCBsZW5ndGgpIC0gcmVtb3ZlIGluIHYwLjEzXG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgJ0J1ZmZlci53cml0ZShzdHJpbmcsIGVuY29kaW5nLCBvZmZzZXRbLCBsZW5ndGhdKSBpcyBubyBsb25nZXIgc3VwcG9ydGVkJ1xuICAgIClcbiAgfVxuXG4gIHZhciByZW1haW5pbmcgPSB0aGlzLmxlbmd0aCAtIG9mZnNldFxuICBpZiAobGVuZ3RoID09PSB1bmRlZmluZWQgfHwgbGVuZ3RoID4gcmVtYWluaW5nKSBsZW5ndGggPSByZW1haW5pbmdcblxuICBpZiAoKHN0cmluZy5sZW5ndGggPiAwICYmIChsZW5ndGggPCAwIHx8IG9mZnNldCA8IDApKSB8fCBvZmZzZXQgPiB0aGlzLmxlbmd0aCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdBdHRlbXB0IHRvIHdyaXRlIG91dHNpZGUgYnVmZmVyIGJvdW5kcycpXG4gIH1cblxuICBpZiAoIWVuY29kaW5nKSBlbmNvZGluZyA9ICd1dGY4J1xuXG4gIHZhciBsb3dlcmVkQ2FzZSA9IGZhbHNlXG4gIGZvciAoOzspIHtcbiAgICBzd2l0Y2ggKGVuY29kaW5nKSB7XG4gICAgICBjYXNlICdoZXgnOlxuICAgICAgICByZXR1cm4gaGV4V3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAndXRmOCc6XG4gICAgICBjYXNlICd1dGYtOCc6XG4gICAgICAgIHJldHVybiB1dGY4V3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAnYXNjaWknOlxuICAgICAgICByZXR1cm4gYXNjaWlXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICdiaW5hcnknOlxuICAgICAgICByZXR1cm4gYmluYXJ5V3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgLy8gV2FybmluZzogbWF4TGVuZ3RoIG5vdCB0YWtlbiBpbnRvIGFjY291bnQgaW4gYmFzZTY0V3JpdGVcbiAgICAgICAgcmV0dXJuIGJhc2U2NFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ3VjczInOlxuICAgICAgY2FzZSAndWNzLTInOlxuICAgICAgY2FzZSAndXRmMTZsZSc6XG4gICAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICAgIHJldHVybiB1Y3MyV3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGxvd2VyZWRDYXNlKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdVbmtub3duIGVuY29kaW5nOiAnICsgZW5jb2RpbmcpXG4gICAgICAgIGVuY29kaW5nID0gKCcnICsgZW5jb2RpbmcpLnRvTG93ZXJDYXNlKClcbiAgICAgICAgbG93ZXJlZENhc2UgPSB0cnVlXG4gICAgfVxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUudG9KU09OID0gZnVuY3Rpb24gdG9KU09OICgpIHtcbiAgcmV0dXJuIHtcbiAgICB0eXBlOiAnQnVmZmVyJyxcbiAgICBkYXRhOiBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbCh0aGlzLl9hcnIgfHwgdGhpcywgMClcbiAgfVxufVxuXG5mdW5jdGlvbiBiYXNlNjRTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIGlmIChzdGFydCA9PT0gMCAmJiBlbmQgPT09IGJ1Zi5sZW5ndGgpIHtcbiAgICByZXR1cm4gYmFzZTY0LmZyb21CeXRlQXJyYXkoYnVmKVxuICB9IGVsc2Uge1xuICAgIHJldHVybiBiYXNlNjQuZnJvbUJ5dGVBcnJheShidWYuc2xpY2Uoc3RhcnQsIGVuZCkpXG4gIH1cbn1cblxuZnVuY3Rpb24gdXRmOFNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgZW5kID0gTWF0aC5taW4oYnVmLmxlbmd0aCwgZW5kKVxuICB2YXIgcmVzID0gW11cblxuICB2YXIgaSA9IHN0YXJ0XG4gIHdoaWxlIChpIDwgZW5kKSB7XG4gICAgdmFyIGZpcnN0Qnl0ZSA9IGJ1ZltpXVxuICAgIHZhciBjb2RlUG9pbnQgPSBudWxsXG4gICAgdmFyIGJ5dGVzUGVyU2VxdWVuY2UgPSAoZmlyc3RCeXRlID4gMHhFRikgPyA0XG4gICAgICA6IChmaXJzdEJ5dGUgPiAweERGKSA/IDNcbiAgICAgIDogKGZpcnN0Qnl0ZSA+IDB4QkYpID8gMlxuICAgICAgOiAxXG5cbiAgICBpZiAoaSArIGJ5dGVzUGVyU2VxdWVuY2UgPD0gZW5kKSB7XG4gICAgICB2YXIgc2Vjb25kQnl0ZSwgdGhpcmRCeXRlLCBmb3VydGhCeXRlLCB0ZW1wQ29kZVBvaW50XG5cbiAgICAgIHN3aXRjaCAoYnl0ZXNQZXJTZXF1ZW5jZSkge1xuICAgICAgICBjYXNlIDE6XG4gICAgICAgICAgaWYgKGZpcnN0Qnl0ZSA8IDB4ODApIHtcbiAgICAgICAgICAgIGNvZGVQb2ludCA9IGZpcnN0Qnl0ZVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgc2Vjb25kQnl0ZSA9IGJ1ZltpICsgMV1cbiAgICAgICAgICBpZiAoKHNlY29uZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCkge1xuICAgICAgICAgICAgdGVtcENvZGVQb2ludCA9IChmaXJzdEJ5dGUgJiAweDFGKSA8PCAweDYgfCAoc2Vjb25kQnl0ZSAmIDB4M0YpXG4gICAgICAgICAgICBpZiAodGVtcENvZGVQb2ludCA+IDB4N0YpIHtcbiAgICAgICAgICAgICAgY29kZVBvaW50ID0gdGVtcENvZGVQb2ludFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDM6XG4gICAgICAgICAgc2Vjb25kQnl0ZSA9IGJ1ZltpICsgMV1cbiAgICAgICAgICB0aGlyZEJ5dGUgPSBidWZbaSArIDJdXG4gICAgICAgICAgaWYgKChzZWNvbmRCeXRlICYgMHhDMCkgPT09IDB4ODAgJiYgKHRoaXJkQnl0ZSAmIDB4QzApID09PSAweDgwKSB7XG4gICAgICAgICAgICB0ZW1wQ29kZVBvaW50ID0gKGZpcnN0Qnl0ZSAmIDB4RikgPDwgMHhDIHwgKHNlY29uZEJ5dGUgJiAweDNGKSA8PCAweDYgfCAodGhpcmRCeXRlICYgMHgzRilcbiAgICAgICAgICAgIGlmICh0ZW1wQ29kZVBvaW50ID4gMHg3RkYgJiYgKHRlbXBDb2RlUG9pbnQgPCAweEQ4MDAgfHwgdGVtcENvZGVQb2ludCA+IDB4REZGRikpIHtcbiAgICAgICAgICAgICAgY29kZVBvaW50ID0gdGVtcENvZGVQb2ludFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDQ6XG4gICAgICAgICAgc2Vjb25kQnl0ZSA9IGJ1ZltpICsgMV1cbiAgICAgICAgICB0aGlyZEJ5dGUgPSBidWZbaSArIDJdXG4gICAgICAgICAgZm91cnRoQnl0ZSA9IGJ1ZltpICsgM11cbiAgICAgICAgICBpZiAoKHNlY29uZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCAmJiAodGhpcmRCeXRlICYgMHhDMCkgPT09IDB4ODAgJiYgKGZvdXJ0aEJ5dGUgJiAweEMwKSA9PT0gMHg4MCkge1xuICAgICAgICAgICAgdGVtcENvZGVQb2ludCA9IChmaXJzdEJ5dGUgJiAweEYpIDw8IDB4MTIgfCAoc2Vjb25kQnl0ZSAmIDB4M0YpIDw8IDB4QyB8ICh0aGlyZEJ5dGUgJiAweDNGKSA8PCAweDYgfCAoZm91cnRoQnl0ZSAmIDB4M0YpXG4gICAgICAgICAgICBpZiAodGVtcENvZGVQb2ludCA+IDB4RkZGRiAmJiB0ZW1wQ29kZVBvaW50IDwgMHgxMTAwMDApIHtcbiAgICAgICAgICAgICAgY29kZVBvaW50ID0gdGVtcENvZGVQb2ludFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoY29kZVBvaW50ID09PSBudWxsKSB7XG4gICAgICAvLyB3ZSBkaWQgbm90IGdlbmVyYXRlIGEgdmFsaWQgY29kZVBvaW50IHNvIGluc2VydCBhXG4gICAgICAvLyByZXBsYWNlbWVudCBjaGFyIChVK0ZGRkQpIGFuZCBhZHZhbmNlIG9ubHkgMSBieXRlXG4gICAgICBjb2RlUG9pbnQgPSAweEZGRkRcbiAgICAgIGJ5dGVzUGVyU2VxdWVuY2UgPSAxXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPiAweEZGRkYpIHtcbiAgICAgIC8vIGVuY29kZSB0byB1dGYxNiAoc3Vycm9nYXRlIHBhaXIgZGFuY2UpXG4gICAgICBjb2RlUG9pbnQgLT0gMHgxMDAwMFxuICAgICAgcmVzLnB1c2goY29kZVBvaW50ID4+PiAxMCAmIDB4M0ZGIHwgMHhEODAwKVxuICAgICAgY29kZVBvaW50ID0gMHhEQzAwIHwgY29kZVBvaW50ICYgMHgzRkZcbiAgICB9XG5cbiAgICByZXMucHVzaChjb2RlUG9pbnQpXG4gICAgaSArPSBieXRlc1BlclNlcXVlbmNlXG4gIH1cblxuICByZXR1cm4gZGVjb2RlQ29kZVBvaW50c0FycmF5KHJlcylcbn1cblxuLy8gQmFzZWQgb24gaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMjI3NDcyNzIvNjgwNzQyLCB0aGUgYnJvd3NlciB3aXRoXG4vLyB0aGUgbG93ZXN0IGxpbWl0IGlzIENocm9tZSwgd2l0aCAweDEwMDAwIGFyZ3MuXG4vLyBXZSBnbyAxIG1hZ25pdHVkZSBsZXNzLCBmb3Igc2FmZXR5XG52YXIgTUFYX0FSR1VNRU5UU19MRU5HVEggPSAweDEwMDBcblxuZnVuY3Rpb24gZGVjb2RlQ29kZVBvaW50c0FycmF5IChjb2RlUG9pbnRzKSB7XG4gIHZhciBsZW4gPSBjb2RlUG9pbnRzLmxlbmd0aFxuICBpZiAobGVuIDw9IE1BWF9BUkdVTUVOVFNfTEVOR1RIKSB7XG4gICAgcmV0dXJuIFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkoU3RyaW5nLCBjb2RlUG9pbnRzKSAvLyBhdm9pZCBleHRyYSBzbGljZSgpXG4gIH1cblxuICAvLyBEZWNvZGUgaW4gY2h1bmtzIHRvIGF2b2lkIFwiY2FsbCBzdGFjayBzaXplIGV4Y2VlZGVkXCIuXG4gIHZhciByZXMgPSAnJ1xuICB2YXIgaSA9IDBcbiAgd2hpbGUgKGkgPCBsZW4pIHtcbiAgICByZXMgKz0gU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShcbiAgICAgIFN0cmluZyxcbiAgICAgIGNvZGVQb2ludHMuc2xpY2UoaSwgaSArPSBNQVhfQVJHVU1FTlRTX0xFTkdUSClcbiAgICApXG4gIH1cbiAgcmV0dXJuIHJlc1xufVxuXG5mdW5jdGlvbiBhc2NpaVNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIHJldCA9ICcnXG4gIGVuZCA9IE1hdGgubWluKGJ1Zi5sZW5ndGgsIGVuZClcblxuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7ICsraSkge1xuICAgIHJldCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJ1ZltpXSAmIDB4N0YpXG4gIH1cbiAgcmV0dXJuIHJldFxufVxuXG5mdW5jdGlvbiBiaW5hcnlTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciByZXQgPSAnJ1xuICBlbmQgPSBNYXRoLm1pbihidWYubGVuZ3RoLCBlbmQpXG5cbiAgZm9yICh2YXIgaSA9IHN0YXJ0OyBpIDwgZW5kOyArK2kpIHtcbiAgICByZXQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShidWZbaV0pXG4gIH1cbiAgcmV0dXJuIHJldFxufVxuXG5mdW5jdGlvbiBoZXhTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciBsZW4gPSBidWYubGVuZ3RoXG5cbiAgaWYgKCFzdGFydCB8fCBzdGFydCA8IDApIHN0YXJ0ID0gMFxuICBpZiAoIWVuZCB8fCBlbmQgPCAwIHx8IGVuZCA+IGxlbikgZW5kID0gbGVuXG5cbiAgdmFyIG91dCA9ICcnXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgKytpKSB7XG4gICAgb3V0ICs9IHRvSGV4KGJ1ZltpXSlcbiAgfVxuICByZXR1cm4gb3V0XG59XG5cbmZ1bmN0aW9uIHV0ZjE2bGVTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciBieXRlcyA9IGJ1Zi5zbGljZShzdGFydCwgZW5kKVxuICB2YXIgcmVzID0gJydcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBieXRlcy5sZW5ndGg7IGkgKz0gMikge1xuICAgIHJlcyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJ5dGVzW2ldICsgYnl0ZXNbaSArIDFdICogMjU2KVxuICB9XG4gIHJldHVybiByZXNcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5zbGljZSA9IGZ1bmN0aW9uIHNsaWNlIChzdGFydCwgZW5kKSB7XG4gIHZhciBsZW4gPSB0aGlzLmxlbmd0aFxuICBzdGFydCA9IH5+c3RhcnRcbiAgZW5kID0gZW5kID09PSB1bmRlZmluZWQgPyBsZW4gOiB+fmVuZFxuXG4gIGlmIChzdGFydCA8IDApIHtcbiAgICBzdGFydCArPSBsZW5cbiAgICBpZiAoc3RhcnQgPCAwKSBzdGFydCA9IDBcbiAgfSBlbHNlIGlmIChzdGFydCA+IGxlbikge1xuICAgIHN0YXJ0ID0gbGVuXG4gIH1cblxuICBpZiAoZW5kIDwgMCkge1xuICAgIGVuZCArPSBsZW5cbiAgICBpZiAoZW5kIDwgMCkgZW5kID0gMFxuICB9IGVsc2UgaWYgKGVuZCA+IGxlbikge1xuICAgIGVuZCA9IGxlblxuICB9XG5cbiAgaWYgKGVuZCA8IHN0YXJ0KSBlbmQgPSBzdGFydFxuXG4gIHZhciBuZXdCdWZcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgbmV3QnVmID0gdGhpcy5zdWJhcnJheShzdGFydCwgZW5kKVxuICAgIG5ld0J1Zi5fX3Byb3RvX18gPSBCdWZmZXIucHJvdG90eXBlXG4gIH0gZWxzZSB7XG4gICAgdmFyIHNsaWNlTGVuID0gZW5kIC0gc3RhcnRcbiAgICBuZXdCdWYgPSBuZXcgQnVmZmVyKHNsaWNlTGVuLCB1bmRlZmluZWQpXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzbGljZUxlbjsgKytpKSB7XG4gICAgICBuZXdCdWZbaV0gPSB0aGlzW2kgKyBzdGFydF1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gbmV3QnVmXG59XG5cbi8qXG4gKiBOZWVkIHRvIG1ha2Ugc3VyZSB0aGF0IGJ1ZmZlciBpc24ndCB0cnlpbmcgdG8gd3JpdGUgb3V0IG9mIGJvdW5kcy5cbiAqL1xuZnVuY3Rpb24gY2hlY2tPZmZzZXQgKG9mZnNldCwgZXh0LCBsZW5ndGgpIHtcbiAgaWYgKChvZmZzZXQgJSAxKSAhPT0gMCB8fCBvZmZzZXQgPCAwKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignb2Zmc2V0IGlzIG5vdCB1aW50JylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGxlbmd0aCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ1RyeWluZyB0byBhY2Nlc3MgYmV5b25kIGJ1ZmZlciBsZW5ndGgnKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50TEUgPSBmdW5jdGlvbiByZWFkVUludExFIChvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgYnl0ZUxlbmd0aCwgdGhpcy5sZW5ndGgpXG5cbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0XVxuICB2YXIgbXVsID0gMVxuICB2YXIgaSA9IDBcbiAgd2hpbGUgKCsraSA8IGJ5dGVMZW5ndGggJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyBpXSAqIG11bFxuICB9XG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50QkUgPSBmdW5jdGlvbiByZWFkVUludEJFIChvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuICB9XG5cbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0ICsgLS1ieXRlTGVuZ3RoXVxuICB2YXIgbXVsID0gMVxuICB3aGlsZSAoYnl0ZUxlbmd0aCA+IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyAtLWJ5dGVMZW5ndGhdICogbXVsXG4gIH1cblxuICByZXR1cm4gdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQ4ID0gZnVuY3Rpb24gcmVhZFVJbnQ4IChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMSwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiB0aGlzW29mZnNldF1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDE2TEUgPSBmdW5jdGlvbiByZWFkVUludDE2TEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIHRoaXNbb2Zmc2V0XSB8ICh0aGlzW29mZnNldCArIDFdIDw8IDgpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQxNkJFID0gZnVuY3Rpb24gcmVhZFVJbnQxNkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiAodGhpc1tvZmZzZXRdIDw8IDgpIHwgdGhpc1tvZmZzZXQgKyAxXVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MzJMRSA9IGZ1bmN0aW9uIHJlYWRVSW50MzJMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuXG4gIHJldHVybiAoKHRoaXNbb2Zmc2V0XSkgfFxuICAgICAgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOCkgfFxuICAgICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgMTYpKSArXG4gICAgICAodGhpc1tvZmZzZXQgKyAzXSAqIDB4MTAwMDAwMClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDMyQkUgPSBmdW5jdGlvbiByZWFkVUludDMyQkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSAqIDB4MTAwMDAwMCkgK1xuICAgICgodGhpc1tvZmZzZXQgKyAxXSA8PCAxNikgfFxuICAgICh0aGlzW29mZnNldCArIDJdIDw8IDgpIHxcbiAgICB0aGlzW29mZnNldCArIDNdKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnRMRSA9IGZ1bmN0aW9uIHJlYWRJbnRMRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldF1cbiAgdmFyIG11bCA9IDFcbiAgdmFyIGkgPSAwXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgaV0gKiBtdWxcbiAgfVxuICBtdWwgKj0gMHg4MFxuXG4gIGlmICh2YWwgPj0gbXVsKSB2YWwgLT0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpXG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnRCRSA9IGZ1bmN0aW9uIHJlYWRJbnRCRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuXG4gIHZhciBpID0gYnl0ZUxlbmd0aFxuICB2YXIgbXVsID0gMVxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXQgKyAtLWldXG4gIHdoaWxlIChpID4gMCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIC0taV0gKiBtdWxcbiAgfVxuICBtdWwgKj0gMHg4MFxuXG4gIGlmICh2YWwgPj0gbXVsKSB2YWwgLT0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpXG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQ4ID0gZnVuY3Rpb24gcmVhZEludDggKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAxLCB0aGlzLmxlbmd0aClcbiAgaWYgKCEodGhpc1tvZmZzZXRdICYgMHg4MCkpIHJldHVybiAodGhpc1tvZmZzZXRdKVxuICByZXR1cm4gKCgweGZmIC0gdGhpc1tvZmZzZXRdICsgMSkgKiAtMSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MTZMRSA9IGZ1bmN0aW9uIHJlYWRJbnQxNkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldF0gfCAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KVxuICByZXR1cm4gKHZhbCAmIDB4ODAwMCkgPyB2YWwgfCAweEZGRkYwMDAwIDogdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDE2QkUgPSBmdW5jdGlvbiByZWFkSW50MTZCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXQgKyAxXSB8ICh0aGlzW29mZnNldF0gPDwgOClcbiAgcmV0dXJuICh2YWwgJiAweDgwMDApID8gdmFsIHwgMHhGRkZGMDAwMCA6IHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQzMkxFID0gZnVuY3Rpb24gcmVhZEludDMyTEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSkgfFxuICAgICh0aGlzW29mZnNldCArIDFdIDw8IDgpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCAxNikgfFxuICAgICh0aGlzW29mZnNldCArIDNdIDw8IDI0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQzMkJFID0gZnVuY3Rpb24gcmVhZEludDMyQkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSA8PCAyNCkgfFxuICAgICh0aGlzW29mZnNldCArIDFdIDw8IDE2KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgOCkgfFxuICAgICh0aGlzW29mZnNldCArIDNdKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRGbG9hdExFID0gZnVuY3Rpb24gcmVhZEZsb2F0TEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIHRydWUsIDIzLCA0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRGbG9hdEJFID0gZnVuY3Rpb24gcmVhZEZsb2F0QkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIGZhbHNlLCAyMywgNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRG91YmxlTEUgPSBmdW5jdGlvbiByZWFkRG91YmxlTEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA4LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIHRydWUsIDUyLCA4KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWREb3VibGVCRSA9IGZ1bmN0aW9uIHJlYWREb3VibGVCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDgsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgZmFsc2UsIDUyLCA4KVxufVxuXG5mdW5jdGlvbiBjaGVja0ludCAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBleHQsIG1heCwgbWluKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGJ1ZikpIHRocm93IG5ldyBUeXBlRXJyb3IoJ1wiYnVmZmVyXCIgYXJndW1lbnQgbXVzdCBiZSBhIEJ1ZmZlciBpbnN0YW5jZScpXG4gIGlmICh2YWx1ZSA+IG1heCB8fCB2YWx1ZSA8IG1pbikgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ1widmFsdWVcIiBhcmd1bWVudCBpcyBvdXQgb2YgYm91bmRzJylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGJ1Zi5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdJbmRleCBvdXQgb2YgcmFuZ2UnKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludExFID0gZnVuY3Rpb24gd3JpdGVVSW50TEUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICB2YXIgbWF4Qnl0ZXMgPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aCkgLSAxXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbWF4Qnl0ZXMsIDApXG4gIH1cblxuICB2YXIgbXVsID0gMVxuICB2YXIgaSA9IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICh2YWx1ZSAvIG11bCkgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludEJFID0gZnVuY3Rpb24gd3JpdGVVSW50QkUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICB2YXIgbWF4Qnl0ZXMgPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aCkgLSAxXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbWF4Qnl0ZXMsIDApXG4gIH1cblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHRoaXNbb2Zmc2V0ICsgaV0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKC0taSA+PSAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICh2YWx1ZSAvIG11bCkgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDggPSBmdW5jdGlvbiB3cml0ZVVJbnQ4ICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDEsIDB4ZmYsIDApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHZhbHVlID0gTWF0aC5mbG9vcih2YWx1ZSlcbiAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgcmV0dXJuIG9mZnNldCArIDFcbn1cblxuZnVuY3Rpb24gb2JqZWN0V3JpdGVVSW50MTYgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuKSB7XG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmICsgdmFsdWUgKyAxXG4gIGZvciAodmFyIGkgPSAwLCBqID0gTWF0aC5taW4oYnVmLmxlbmd0aCAtIG9mZnNldCwgMik7IGkgPCBqOyArK2kpIHtcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSAodmFsdWUgJiAoMHhmZiA8PCAoOCAqIChsaXR0bGVFbmRpYW4gPyBpIDogMSAtIGkpKSkpID4+PlxuICAgICAgKGxpdHRsZUVuZGlhbiA/IGkgOiAxIC0gaSkgKiA4XG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQxNkxFID0gZnVuY3Rpb24gd3JpdGVVSW50MTZMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweGZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MTZCRSA9IGZ1bmN0aW9uIHdyaXRlVUludDE2QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHhmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuZnVuY3Rpb24gb2JqZWN0V3JpdGVVSW50MzIgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuKSB7XG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmZmZmZiArIHZhbHVlICsgMVxuICBmb3IgKHZhciBpID0gMCwgaiA9IE1hdGgubWluKGJ1Zi5sZW5ndGggLSBvZmZzZXQsIDQpOyBpIDwgajsgKytpKSB7XG4gICAgYnVmW29mZnNldCArIGldID0gKHZhbHVlID4+PiAobGl0dGxlRW5kaWFuID8gaSA6IDMgLSBpKSAqIDgpICYgMHhmZlxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MzJMRSA9IGZ1bmN0aW9uIHdyaXRlVUludDMyTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHhmZmZmZmZmZiwgMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQzMkJFID0gZnVuY3Rpb24gd3JpdGVVSW50MzJCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweGZmZmZmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDI0KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDE2KVxuICAgIHRoaXNbb2Zmc2V0ICsgMl0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludExFID0gZnVuY3Rpb24gd3JpdGVJbnRMRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IDBcbiAgdmFyIG11bCA9IDFcbiAgdmFyIHN1YiA9IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgaWYgKHZhbHVlIDwgMCAmJiBzdWIgPT09IDAgJiYgdGhpc1tvZmZzZXQgKyBpIC0gMV0gIT09IDApIHtcbiAgICAgIHN1YiA9IDFcbiAgICB9XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICgodmFsdWUgLyBtdWwpID4+IDApIC0gc3ViICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIG9mZnNldCArIGJ5dGVMZW5ndGhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludEJFID0gZnVuY3Rpb24gd3JpdGVJbnRCRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHZhciBzdWIgPSAwXG4gIHRoaXNbb2Zmc2V0ICsgaV0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKC0taSA+PSAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgaWYgKHZhbHVlIDwgMCAmJiBzdWIgPT09IDAgJiYgdGhpc1tvZmZzZXQgKyBpICsgMV0gIT09IDApIHtcbiAgICAgIHN1YiA9IDFcbiAgICB9XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICgodmFsdWUgLyBtdWwpID4+IDApIC0gc3ViICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIG9mZnNldCArIGJ5dGVMZW5ndGhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDggPSBmdW5jdGlvbiB3cml0ZUludDggKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMSwgMHg3ZiwgLTB4ODApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHZhbHVlID0gTWF0aC5mbG9vcih2YWx1ZSlcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmICsgdmFsdWUgKyAxXG4gIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIHJldHVybiBvZmZzZXQgKyAxXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQxNkxFID0gZnVuY3Rpb24gd3JpdGVJbnQxNkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4N2ZmZiwgLTB4ODAwMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDE2QkUgPSBmdW5jdGlvbiB3cml0ZUludDE2QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHg3ZmZmLCAtMHg4MDAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDMyTEUgPSBmdW5jdGlvbiB3cml0ZUludDMyTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHg3ZmZmZmZmZiwgLTB4ODAwMDAwMDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlID4+PiAyNClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQzMkJFID0gZnVuY3Rpb24gd3JpdGVJbnQzMkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4N2ZmZmZmZmYsIC0weDgwMDAwMDAwKVxuICBpZiAodmFsdWUgPCAwKSB2YWx1ZSA9IDB4ZmZmZmZmZmYgKyB2YWx1ZSArIDFcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlID4+PiAyNClcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0ICsgM10gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbmZ1bmN0aW9uIGNoZWNrSUVFRTc1NCAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBleHQsIG1heCwgbWluKSB7XG4gIGlmIChvZmZzZXQgKyBleHQgPiBidWYubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignSW5kZXggb3V0IG9mIHJhbmdlJylcbiAgaWYgKG9mZnNldCA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdJbmRleCBvdXQgb2YgcmFuZ2UnKVxufVxuXG5mdW5jdGlvbiB3cml0ZUZsb2F0IChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrSUVFRTc1NChidWYsIHZhbHVlLCBvZmZzZXQsIDQsIDMuNDAyODIzNDY2Mzg1Mjg4NmUrMzgsIC0zLjQwMjgyMzQ2NjM4NTI4ODZlKzM4KVxuICB9XG4gIGllZWU3NTQud3JpdGUoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4sIDIzLCA0KVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlRmxvYXRMRSA9IGZ1bmN0aW9uIHdyaXRlRmxvYXRMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRmxvYXQodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSwgbm9Bc3NlcnQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVGbG9hdEJFID0gZnVuY3Rpb24gd3JpdGVGbG9hdEJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVGbG9hdCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSwgbm9Bc3NlcnQpXG59XG5cbmZ1bmN0aW9uIHdyaXRlRG91YmxlIChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrSUVFRTc1NChidWYsIHZhbHVlLCBvZmZzZXQsIDgsIDEuNzk3NjkzMTM0ODYyMzE1N0UrMzA4LCAtMS43OTc2OTMxMzQ4NjIzMTU3RSszMDgpXG4gIH1cbiAgaWVlZTc1NC53cml0ZShidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgNTIsIDgpXG4gIHJldHVybiBvZmZzZXQgKyA4XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVEb3VibGVMRSA9IGZ1bmN0aW9uIHdyaXRlRG91YmxlTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZURvdWJsZSh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlLCBub0Fzc2VydClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZURvdWJsZUJFID0gZnVuY3Rpb24gd3JpdGVEb3VibGVCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRG91YmxlKHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlLCBub0Fzc2VydClcbn1cblxuLy8gY29weSh0YXJnZXRCdWZmZXIsIHRhcmdldFN0YXJ0PTAsIHNvdXJjZVN0YXJ0PTAsIHNvdXJjZUVuZD1idWZmZXIubGVuZ3RoKVxuQnVmZmVyLnByb3RvdHlwZS5jb3B5ID0gZnVuY3Rpb24gY29weSAodGFyZ2V0LCB0YXJnZXRTdGFydCwgc3RhcnQsIGVuZCkge1xuICBpZiAoIXN0YXJ0KSBzdGFydCA9IDBcbiAgaWYgKCFlbmQgJiYgZW5kICE9PSAwKSBlbmQgPSB0aGlzLmxlbmd0aFxuICBpZiAodGFyZ2V0U3RhcnQgPj0gdGFyZ2V0Lmxlbmd0aCkgdGFyZ2V0U3RhcnQgPSB0YXJnZXQubGVuZ3RoXG4gIGlmICghdGFyZ2V0U3RhcnQpIHRhcmdldFN0YXJ0ID0gMFxuICBpZiAoZW5kID4gMCAmJiBlbmQgPCBzdGFydCkgZW5kID0gc3RhcnRcblxuICAvLyBDb3B5IDAgYnl0ZXM7IHdlJ3JlIGRvbmVcbiAgaWYgKGVuZCA9PT0gc3RhcnQpIHJldHVybiAwXG4gIGlmICh0YXJnZXQubGVuZ3RoID09PSAwIHx8IHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm4gMFxuXG4gIC8vIEZhdGFsIGVycm9yIGNvbmRpdGlvbnNcbiAgaWYgKHRhcmdldFN0YXJ0IDwgMCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCd0YXJnZXRTdGFydCBvdXQgb2YgYm91bmRzJylcbiAgfVxuICBpZiAoc3RhcnQgPCAwIHx8IHN0YXJ0ID49IHRoaXMubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc291cmNlU3RhcnQgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChlbmQgPCAwKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc291cmNlRW5kIG91dCBvZiBib3VuZHMnKVxuXG4gIC8vIEFyZSB3ZSBvb2I/XG4gIGlmIChlbmQgPiB0aGlzLmxlbmd0aCkgZW5kID0gdGhpcy5sZW5ndGhcbiAgaWYgKHRhcmdldC5sZW5ndGggLSB0YXJnZXRTdGFydCA8IGVuZCAtIHN0YXJ0KSB7XG4gICAgZW5kID0gdGFyZ2V0Lmxlbmd0aCAtIHRhcmdldFN0YXJ0ICsgc3RhcnRcbiAgfVxuXG4gIHZhciBsZW4gPSBlbmQgLSBzdGFydFxuICB2YXIgaVxuXG4gIGlmICh0aGlzID09PSB0YXJnZXQgJiYgc3RhcnQgPCB0YXJnZXRTdGFydCAmJiB0YXJnZXRTdGFydCA8IGVuZCkge1xuICAgIC8vIGRlc2NlbmRpbmcgY29weSBmcm9tIGVuZFxuICAgIGZvciAoaSA9IGxlbiAtIDE7IGkgPj0gMDsgLS1pKSB7XG4gICAgICB0YXJnZXRbaSArIHRhcmdldFN0YXJ0XSA9IHRoaXNbaSArIHN0YXJ0XVxuICAgIH1cbiAgfSBlbHNlIGlmIChsZW4gPCAxMDAwIHx8ICFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIC8vIGFzY2VuZGluZyBjb3B5IGZyb20gc3RhcnRcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuOyArK2kpIHtcbiAgICAgIHRhcmdldFtpICsgdGFyZ2V0U3RhcnRdID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIFVpbnQ4QXJyYXkucHJvdG90eXBlLnNldC5jYWxsKFxuICAgICAgdGFyZ2V0LFxuICAgICAgdGhpcy5zdWJhcnJheShzdGFydCwgc3RhcnQgKyBsZW4pLFxuICAgICAgdGFyZ2V0U3RhcnRcbiAgICApXG4gIH1cblxuICByZXR1cm4gbGVuXG59XG5cbi8vIFVzYWdlOlxuLy8gICAgYnVmZmVyLmZpbGwobnVtYmVyWywgb2Zmc2V0WywgZW5kXV0pXG4vLyAgICBidWZmZXIuZmlsbChidWZmZXJbLCBvZmZzZXRbLCBlbmRdXSlcbi8vICAgIGJ1ZmZlci5maWxsKHN0cmluZ1ssIG9mZnNldFssIGVuZF1dWywgZW5jb2RpbmddKVxuQnVmZmVyLnByb3RvdHlwZS5maWxsID0gZnVuY3Rpb24gZmlsbCAodmFsLCBzdGFydCwgZW5kLCBlbmNvZGluZykge1xuICAvLyBIYW5kbGUgc3RyaW5nIGNhc2VzOlxuICBpZiAodHlwZW9mIHZhbCA9PT0gJ3N0cmluZycpIHtcbiAgICBpZiAodHlwZW9mIHN0YXJ0ID09PSAnc3RyaW5nJykge1xuICAgICAgZW5jb2RpbmcgPSBzdGFydFxuICAgICAgc3RhcnQgPSAwXG4gICAgICBlbmQgPSB0aGlzLmxlbmd0aFxuICAgIH0gZWxzZSBpZiAodHlwZW9mIGVuZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgIGVuY29kaW5nID0gZW5kXG4gICAgICBlbmQgPSB0aGlzLmxlbmd0aFxuICAgIH1cbiAgICBpZiAodmFsLmxlbmd0aCA9PT0gMSkge1xuICAgICAgdmFyIGNvZGUgPSB2YWwuY2hhckNvZGVBdCgwKVxuICAgICAgaWYgKGNvZGUgPCAyNTYpIHtcbiAgICAgICAgdmFsID0gY29kZVxuICAgICAgfVxuICAgIH1cbiAgICBpZiAoZW5jb2RpbmcgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgZW5jb2RpbmcgIT09ICdzdHJpbmcnKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdlbmNvZGluZyBtdXN0IGJlIGEgc3RyaW5nJylcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBlbmNvZGluZyA9PT0gJ3N0cmluZycgJiYgIUJ1ZmZlci5pc0VuY29kaW5nKGVuY29kaW5nKSkge1xuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignVW5rbm93biBlbmNvZGluZzogJyArIGVuY29kaW5nKVxuICAgIH1cbiAgfSBlbHNlIGlmICh0eXBlb2YgdmFsID09PSAnbnVtYmVyJykge1xuICAgIHZhbCA9IHZhbCAmIDI1NVxuICB9XG5cbiAgLy8gSW52YWxpZCByYW5nZXMgYXJlIG5vdCBzZXQgdG8gYSBkZWZhdWx0LCBzbyBjYW4gcmFuZ2UgY2hlY2sgZWFybHkuXG4gIGlmIChzdGFydCA8IDAgfHwgdGhpcy5sZW5ndGggPCBzdGFydCB8fCB0aGlzLmxlbmd0aCA8IGVuZCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdPdXQgb2YgcmFuZ2UgaW5kZXgnKVxuICB9XG5cbiAgaWYgKGVuZCA8PSBzdGFydCkge1xuICAgIHJldHVybiB0aGlzXG4gIH1cblxuICBzdGFydCA9IHN0YXJ0ID4+PiAwXG4gIGVuZCA9IGVuZCA9PT0gdW5kZWZpbmVkID8gdGhpcy5sZW5ndGggOiBlbmQgPj4+IDBcblxuICBpZiAoIXZhbCkgdmFsID0gMFxuXG4gIHZhciBpXG4gIGlmICh0eXBlb2YgdmFsID09PSAnbnVtYmVyJykge1xuICAgIGZvciAoaSA9IHN0YXJ0OyBpIDwgZW5kOyArK2kpIHtcbiAgICAgIHRoaXNbaV0gPSB2YWxcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdmFyIGJ5dGVzID0gQnVmZmVyLmlzQnVmZmVyKHZhbClcbiAgICAgID8gdmFsXG4gICAgICA6IHV0ZjhUb0J5dGVzKG5ldyBCdWZmZXIodmFsLCBlbmNvZGluZykudG9TdHJpbmcoKSlcbiAgICB2YXIgbGVuID0gYnl0ZXMubGVuZ3RoXG4gICAgZm9yIChpID0gMDsgaSA8IGVuZCAtIHN0YXJ0OyArK2kpIHtcbiAgICAgIHRoaXNbaSArIHN0YXJ0XSA9IGJ5dGVzW2kgJSBsZW5dXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRoaXNcbn1cblxuLy8gSEVMUEVSIEZVTkNUSU9OU1xuLy8gPT09PT09PT09PT09PT09PVxuXG52YXIgSU5WQUxJRF9CQVNFNjRfUkUgPSAvW14rXFwvMC05QS1aYS16LV9dL2dcblxuZnVuY3Rpb24gYmFzZTY0Y2xlYW4gKHN0cikge1xuICAvLyBOb2RlIHN0cmlwcyBvdXQgaW52YWxpZCBjaGFyYWN0ZXJzIGxpa2UgXFxuIGFuZCBcXHQgZnJvbSB0aGUgc3RyaW5nLCBiYXNlNjQtanMgZG9lcyBub3RcbiAgc3RyID0gc3RyaW5ndHJpbShzdHIpLnJlcGxhY2UoSU5WQUxJRF9CQVNFNjRfUkUsICcnKVxuICAvLyBOb2RlIGNvbnZlcnRzIHN0cmluZ3Mgd2l0aCBsZW5ndGggPCAyIHRvICcnXG4gIGlmIChzdHIubGVuZ3RoIDwgMikgcmV0dXJuICcnXG4gIC8vIE5vZGUgYWxsb3dzIGZvciBub24tcGFkZGVkIGJhc2U2NCBzdHJpbmdzIChtaXNzaW5nIHRyYWlsaW5nID09PSksIGJhc2U2NC1qcyBkb2VzIG5vdFxuICB3aGlsZSAoc3RyLmxlbmd0aCAlIDQgIT09IDApIHtcbiAgICBzdHIgPSBzdHIgKyAnPSdcbiAgfVxuICByZXR1cm4gc3RyXG59XG5cbmZ1bmN0aW9uIHN0cmluZ3RyaW0gKHN0cikge1xuICBpZiAoc3RyLnRyaW0pIHJldHVybiBzdHIudHJpbSgpXG4gIHJldHVybiBzdHIucmVwbGFjZSgvXlxccyt8XFxzKyQvZywgJycpXG59XG5cbmZ1bmN0aW9uIHRvSGV4IChuKSB7XG4gIGlmIChuIDwgMTYpIHJldHVybiAnMCcgKyBuLnRvU3RyaW5nKDE2KVxuICByZXR1cm4gbi50b1N0cmluZygxNilcbn1cblxuZnVuY3Rpb24gdXRmOFRvQnl0ZXMgKHN0cmluZywgdW5pdHMpIHtcbiAgdW5pdHMgPSB1bml0cyB8fCBJbmZpbml0eVxuICB2YXIgY29kZVBvaW50XG4gIHZhciBsZW5ndGggPSBzdHJpbmcubGVuZ3RoXG4gIHZhciBsZWFkU3Vycm9nYXRlID0gbnVsbFxuICB2YXIgYnl0ZXMgPSBbXVxuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyArK2kpIHtcbiAgICBjb2RlUG9pbnQgPSBzdHJpbmcuY2hhckNvZGVBdChpKVxuXG4gICAgLy8gaXMgc3Vycm9nYXRlIGNvbXBvbmVudFxuICAgIGlmIChjb2RlUG9pbnQgPiAweEQ3RkYgJiYgY29kZVBvaW50IDwgMHhFMDAwKSB7XG4gICAgICAvLyBsYXN0IGNoYXIgd2FzIGEgbGVhZFxuICAgICAgaWYgKCFsZWFkU3Vycm9nYXRlKSB7XG4gICAgICAgIC8vIG5vIGxlYWQgeWV0XG4gICAgICAgIGlmIChjb2RlUG9pbnQgPiAweERCRkYpIHtcbiAgICAgICAgICAvLyB1bmV4cGVjdGVkIHRyYWlsXG4gICAgICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgICAgICAgY29udGludWVcbiAgICAgICAgfSBlbHNlIGlmIChpICsgMSA9PT0gbGVuZ3RoKSB7XG4gICAgICAgICAgLy8gdW5wYWlyZWQgbGVhZFxuICAgICAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgIH1cblxuICAgICAgICAvLyB2YWxpZCBsZWFkXG4gICAgICAgIGxlYWRTdXJyb2dhdGUgPSBjb2RlUG9pbnRcblxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICAvLyAyIGxlYWRzIGluIGEgcm93XG4gICAgICBpZiAoY29kZVBvaW50IDwgMHhEQzAwKSB7XG4gICAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgICAgICBsZWFkU3Vycm9nYXRlID0gY29kZVBvaW50XG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIC8vIHZhbGlkIHN1cnJvZ2F0ZSBwYWlyXG4gICAgICBjb2RlUG9pbnQgPSAobGVhZFN1cnJvZ2F0ZSAtIDB4RDgwMCA8PCAxMCB8IGNvZGVQb2ludCAtIDB4REMwMCkgKyAweDEwMDAwXG4gICAgfSBlbHNlIGlmIChsZWFkU3Vycm9nYXRlKSB7XG4gICAgICAvLyB2YWxpZCBibXAgY2hhciwgYnV0IGxhc3QgY2hhciB3YXMgYSBsZWFkXG4gICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICB9XG5cbiAgICBsZWFkU3Vycm9nYXRlID0gbnVsbFxuXG4gICAgLy8gZW5jb2RlIHV0ZjhcbiAgICBpZiAoY29kZVBvaW50IDwgMHg4MCkge1xuICAgICAgaWYgKCh1bml0cyAtPSAxKSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKGNvZGVQb2ludClcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA8IDB4ODAwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDIpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDYgfCAweEMwLFxuICAgICAgICBjb2RlUG9pbnQgJiAweDNGIHwgMHg4MFxuICAgICAgKVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50IDwgMHgxMDAwMCkge1xuICAgICAgaWYgKCh1bml0cyAtPSAzKSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHhDIHwgMHhFMCxcbiAgICAgICAgY29kZVBvaW50ID4+IDB4NiAmIDB4M0YgfCAweDgwLFxuICAgICAgICBjb2RlUG9pbnQgJiAweDNGIHwgMHg4MFxuICAgICAgKVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50IDwgMHgxMTAwMDApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gNCkgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChcbiAgICAgICAgY29kZVBvaW50ID4+IDB4MTIgfCAweEYwLFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHhDICYgMHgzRiB8IDB4ODAsXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDYgJiAweDNGIHwgMHg4MCxcbiAgICAgICAgY29kZVBvaW50ICYgMHgzRiB8IDB4ODBcbiAgICAgIClcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGNvZGUgcG9pbnQnKVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBieXRlc1xufVxuXG5mdW5jdGlvbiBhc2NpaVRvQnl0ZXMgKHN0cikge1xuICB2YXIgYnl0ZUFycmF5ID0gW11cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdHIubGVuZ3RoOyArK2kpIHtcbiAgICAvLyBOb2RlJ3MgY29kZSBzZWVtcyB0byBiZSBkb2luZyB0aGlzIGFuZCBub3QgJiAweDdGLi5cbiAgICBieXRlQXJyYXkucHVzaChzdHIuY2hhckNvZGVBdChpKSAmIDB4RkYpXG4gIH1cbiAgcmV0dXJuIGJ5dGVBcnJheVxufVxuXG5mdW5jdGlvbiB1dGYxNmxlVG9CeXRlcyAoc3RyLCB1bml0cykge1xuICB2YXIgYywgaGksIGxvXG4gIHZhciBieXRlQXJyYXkgPSBbXVxuICBmb3IgKHZhciBpID0gMDsgaSA8IHN0ci5sZW5ndGg7ICsraSkge1xuICAgIGlmICgodW5pdHMgLT0gMikgPCAwKSBicmVha1xuXG4gICAgYyA9IHN0ci5jaGFyQ29kZUF0KGkpXG4gICAgaGkgPSBjID4+IDhcbiAgICBsbyA9IGMgJSAyNTZcbiAgICBieXRlQXJyYXkucHVzaChsbylcbiAgICBieXRlQXJyYXkucHVzaChoaSlcbiAgfVxuXG4gIHJldHVybiBieXRlQXJyYXlcbn1cblxuZnVuY3Rpb24gYmFzZTY0VG9CeXRlcyAoc3RyKSB7XG4gIHJldHVybiBiYXNlNjQudG9CeXRlQXJyYXkoYmFzZTY0Y2xlYW4oc3RyKSlcbn1cblxuZnVuY3Rpb24gYmxpdEJ1ZmZlciAoc3JjLCBkc3QsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyArK2kpIHtcbiAgICBpZiAoKGkgKyBvZmZzZXQgPj0gZHN0Lmxlbmd0aCkgfHwgKGkgPj0gc3JjLmxlbmd0aCkpIGJyZWFrXG4gICAgZHN0W2kgKyBvZmZzZXRdID0gc3JjW2ldXG4gIH1cbiAgcmV0dXJuIGlcbn1cblxuZnVuY3Rpb24gaXNuYW4gKHZhbCkge1xuICByZXR1cm4gdmFsICE9PSB2YWwgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby1zZWxmLWNvbXBhcmVcbn1cbiIsImV4cG9ydHMucmVhZCA9IGZ1bmN0aW9uIChidWZmZXIsIG9mZnNldCwgaXNMRSwgbUxlbiwgbkJ5dGVzKSB7XG4gIHZhciBlLCBtXG4gIHZhciBlTGVuID0gbkJ5dGVzICogOCAtIG1MZW4gLSAxXG4gIHZhciBlTWF4ID0gKDEgPDwgZUxlbikgLSAxXG4gIHZhciBlQmlhcyA9IGVNYXggPj4gMVxuICB2YXIgbkJpdHMgPSAtN1xuICB2YXIgaSA9IGlzTEUgPyAobkJ5dGVzIC0gMSkgOiAwXG4gIHZhciBkID0gaXNMRSA/IC0xIDogMVxuICB2YXIgcyA9IGJ1ZmZlcltvZmZzZXQgKyBpXVxuXG4gIGkgKz0gZFxuXG4gIGUgPSBzICYgKCgxIDw8ICgtbkJpdHMpKSAtIDEpXG4gIHMgPj49ICgtbkJpdHMpXG4gIG5CaXRzICs9IGVMZW5cbiAgZm9yICg7IG5CaXRzID4gMDsgZSA9IGUgKiAyNTYgKyBidWZmZXJbb2Zmc2V0ICsgaV0sIGkgKz0gZCwgbkJpdHMgLT0gOCkge31cblxuICBtID0gZSAmICgoMSA8PCAoLW5CaXRzKSkgLSAxKVxuICBlID4+PSAoLW5CaXRzKVxuICBuQml0cyArPSBtTGVuXG4gIGZvciAoOyBuQml0cyA+IDA7IG0gPSBtICogMjU2ICsgYnVmZmVyW29mZnNldCArIGldLCBpICs9IGQsIG5CaXRzIC09IDgpIHt9XG5cbiAgaWYgKGUgPT09IDApIHtcbiAgICBlID0gMSAtIGVCaWFzXG4gIH0gZWxzZSBpZiAoZSA9PT0gZU1heCkge1xuICAgIHJldHVybiBtID8gTmFOIDogKChzID8gLTEgOiAxKSAqIEluZmluaXR5KVxuICB9IGVsc2Uge1xuICAgIG0gPSBtICsgTWF0aC5wb3coMiwgbUxlbilcbiAgICBlID0gZSAtIGVCaWFzXG4gIH1cbiAgcmV0dXJuIChzID8gLTEgOiAxKSAqIG0gKiBNYXRoLnBvdygyLCBlIC0gbUxlbilcbn1cblxuZXhwb3J0cy53cml0ZSA9IGZ1bmN0aW9uIChidWZmZXIsIHZhbHVlLCBvZmZzZXQsIGlzTEUsIG1MZW4sIG5CeXRlcykge1xuICB2YXIgZSwgbSwgY1xuICB2YXIgZUxlbiA9IG5CeXRlcyAqIDggLSBtTGVuIC0gMVxuICB2YXIgZU1heCA9ICgxIDw8IGVMZW4pIC0gMVxuICB2YXIgZUJpYXMgPSBlTWF4ID4+IDFcbiAgdmFyIHJ0ID0gKG1MZW4gPT09IDIzID8gTWF0aC5wb3coMiwgLTI0KSAtIE1hdGgucG93KDIsIC03NykgOiAwKVxuICB2YXIgaSA9IGlzTEUgPyAwIDogKG5CeXRlcyAtIDEpXG4gIHZhciBkID0gaXNMRSA/IDEgOiAtMVxuICB2YXIgcyA9IHZhbHVlIDwgMCB8fCAodmFsdWUgPT09IDAgJiYgMSAvIHZhbHVlIDwgMCkgPyAxIDogMFxuXG4gIHZhbHVlID0gTWF0aC5hYnModmFsdWUpXG5cbiAgaWYgKGlzTmFOKHZhbHVlKSB8fCB2YWx1ZSA9PT0gSW5maW5pdHkpIHtcbiAgICBtID0gaXNOYU4odmFsdWUpID8gMSA6IDBcbiAgICBlID0gZU1heFxuICB9IGVsc2Uge1xuICAgIGUgPSBNYXRoLmZsb29yKE1hdGgubG9nKHZhbHVlKSAvIE1hdGguTE4yKVxuICAgIGlmICh2YWx1ZSAqIChjID0gTWF0aC5wb3coMiwgLWUpKSA8IDEpIHtcbiAgICAgIGUtLVxuICAgICAgYyAqPSAyXG4gICAgfVxuICAgIGlmIChlICsgZUJpYXMgPj0gMSkge1xuICAgICAgdmFsdWUgKz0gcnQgLyBjXG4gICAgfSBlbHNlIHtcbiAgICAgIHZhbHVlICs9IHJ0ICogTWF0aC5wb3coMiwgMSAtIGVCaWFzKVxuICAgIH1cbiAgICBpZiAodmFsdWUgKiBjID49IDIpIHtcbiAgICAgIGUrK1xuICAgICAgYyAvPSAyXG4gICAgfVxuXG4gICAgaWYgKGUgKyBlQmlhcyA+PSBlTWF4KSB7XG4gICAgICBtID0gMFxuICAgICAgZSA9IGVNYXhcbiAgICB9IGVsc2UgaWYgKGUgKyBlQmlhcyA+PSAxKSB7XG4gICAgICBtID0gKHZhbHVlICogYyAtIDEpICogTWF0aC5wb3coMiwgbUxlbilcbiAgICAgIGUgPSBlICsgZUJpYXNcbiAgICB9IGVsc2Uge1xuICAgICAgbSA9IHZhbHVlICogTWF0aC5wb3coMiwgZUJpYXMgLSAxKSAqIE1hdGgucG93KDIsIG1MZW4pXG4gICAgICBlID0gMFxuICAgIH1cbiAgfVxuXG4gIGZvciAoOyBtTGVuID49IDg7IGJ1ZmZlcltvZmZzZXQgKyBpXSA9IG0gJiAweGZmLCBpICs9IGQsIG0gLz0gMjU2LCBtTGVuIC09IDgpIHt9XG5cbiAgZSA9IChlIDw8IG1MZW4pIHwgbVxuICBlTGVuICs9IG1MZW5cbiAgZm9yICg7IGVMZW4gPiAwOyBidWZmZXJbb2Zmc2V0ICsgaV0gPSBlICYgMHhmZiwgaSArPSBkLCBlIC89IDI1NiwgZUxlbiAtPSA4KSB7fVxuXG4gIGJ1ZmZlcltvZmZzZXQgKyBpIC0gZF0gfD0gcyAqIDEyOFxufVxuIiwidmFyIHRvU3RyaW5nID0ge30udG9TdHJpbmc7XG5cbm1vZHVsZS5leHBvcnRzID0gQXJyYXkuaXNBcnJheSB8fCBmdW5jdGlvbiAoYXJyKSB7XG4gIHJldHVybiB0b1N0cmluZy5jYWxsKGFycikgPT0gJ1tvYmplY3QgQXJyYXldJztcbn07XG4iLCIndXNlIHN0cmljdCc7XG4vKiBlc2xpbnQtZGlzYWJsZSBuby11bnVzZWQtdmFycyAqL1xudmFyIGhhc093blByb3BlcnR5ID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eTtcbnZhciBwcm9wSXNFbnVtZXJhYmxlID0gT2JqZWN0LnByb3RvdHlwZS5wcm9wZXJ0eUlzRW51bWVyYWJsZTtcblxuZnVuY3Rpb24gdG9PYmplY3QodmFsKSB7XG5cdGlmICh2YWwgPT09IG51bGwgfHwgdmFsID09PSB1bmRlZmluZWQpIHtcblx0XHR0aHJvdyBuZXcgVHlwZUVycm9yKCdPYmplY3QuYXNzaWduIGNhbm5vdCBiZSBjYWxsZWQgd2l0aCBudWxsIG9yIHVuZGVmaW5lZCcpO1xuXHR9XG5cblx0cmV0dXJuIE9iamVjdCh2YWwpO1xufVxuXG5mdW5jdGlvbiBzaG91bGRVc2VOYXRpdmUoKSB7XG5cdHRyeSB7XG5cdFx0aWYgKCFPYmplY3QuYXNzaWduKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0Ly8gRGV0ZWN0IGJ1Z2d5IHByb3BlcnR5IGVudW1lcmF0aW9uIG9yZGVyIGluIG9sZGVyIFY4IHZlcnNpb25zLlxuXG5cdFx0Ly8gaHR0cHM6Ly9idWdzLmNocm9taXVtLm9yZy9wL3Y4L2lzc3Vlcy9kZXRhaWw/aWQ9NDExOFxuXHRcdHZhciB0ZXN0MSA9IG5ldyBTdHJpbmcoJ2FiYycpOyAgLy8gZXNsaW50LWRpc2FibGUtbGluZVxuXHRcdHRlc3QxWzVdID0gJ2RlJztcblx0XHRpZiAoT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXModGVzdDEpWzBdID09PSAnNScpIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHQvLyBodHRwczovL2J1Z3MuY2hyb21pdW0ub3JnL3AvdjgvaXNzdWVzL2RldGFpbD9pZD0zMDU2XG5cdFx0dmFyIHRlc3QyID0ge307XG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCAxMDsgaSsrKSB7XG5cdFx0XHR0ZXN0MlsnXycgKyBTdHJpbmcuZnJvbUNoYXJDb2RlKGkpXSA9IGk7XG5cdFx0fVxuXHRcdHZhciBvcmRlcjIgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyh0ZXN0MikubWFwKGZ1bmN0aW9uIChuKSB7XG5cdFx0XHRyZXR1cm4gdGVzdDJbbl07XG5cdFx0fSk7XG5cdFx0aWYgKG9yZGVyMi5qb2luKCcnKSAhPT0gJzAxMjM0NTY3ODknKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0Ly8gaHR0cHM6Ly9idWdzLmNocm9taXVtLm9yZy9wL3Y4L2lzc3Vlcy9kZXRhaWw/aWQ9MzA1NlxuXHRcdHZhciB0ZXN0MyA9IHt9O1xuXHRcdCdhYmNkZWZnaGlqa2xtbm9wcXJzdCcuc3BsaXQoJycpLmZvckVhY2goZnVuY3Rpb24gKGxldHRlcikge1xuXHRcdFx0dGVzdDNbbGV0dGVyXSA9IGxldHRlcjtcblx0XHR9KTtcblx0XHRpZiAoT2JqZWN0LmtleXMoT2JqZWN0LmFzc2lnbih7fSwgdGVzdDMpKS5qb2luKCcnKSAhPT1cblx0XHRcdFx0J2FiY2RlZmdoaWprbG1ub3BxcnN0Jykge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdHJldHVybiB0cnVlO1xuXHR9IGNhdGNoIChlKSB7XG5cdFx0Ly8gV2UgZG9uJ3QgZXhwZWN0IGFueSBvZiB0aGUgYWJvdmUgdG8gdGhyb3csIGJ1dCBiZXR0ZXIgdG8gYmUgc2FmZS5cblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBzaG91bGRVc2VOYXRpdmUoKSA/IE9iamVjdC5hc3NpZ24gOiBmdW5jdGlvbiAodGFyZ2V0LCBzb3VyY2UpIHtcblx0dmFyIGZyb207XG5cdHZhciB0byA9IHRvT2JqZWN0KHRhcmdldCk7XG5cdHZhciBzeW1ib2xzO1xuXG5cdGZvciAodmFyIHMgPSAxOyBzIDwgYXJndW1lbnRzLmxlbmd0aDsgcysrKSB7XG5cdFx0ZnJvbSA9IE9iamVjdChhcmd1bWVudHNbc10pO1xuXG5cdFx0Zm9yICh2YXIga2V5IGluIGZyb20pIHtcblx0XHRcdGlmIChoYXNPd25Qcm9wZXJ0eS5jYWxsKGZyb20sIGtleSkpIHtcblx0XHRcdFx0dG9ba2V5XSA9IGZyb21ba2V5XTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scykge1xuXHRcdFx0c3ltYm9scyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMoZnJvbSk7XG5cdFx0XHRmb3IgKHZhciBpID0gMDsgaSA8IHN5bWJvbHMubGVuZ3RoOyBpKyspIHtcblx0XHRcdFx0aWYgKHByb3BJc0VudW1lcmFibGUuY2FsbChmcm9tLCBzeW1ib2xzW2ldKSkge1xuXHRcdFx0XHRcdHRvW3N5bWJvbHNbaV1dID0gZnJvbVtzeW1ib2xzW2ldXTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdHJldHVybiB0bztcbn07XG4iLCJtb2R1bGUuZXhwb3J0cz17XG4gICAgXCJ2ZXJzaW9uXCI6IFwiXCJcbn1cbiIsIi8qKlxuICogRXBpY2VudGVyIEphdmFzY3JpcHQgbGlicmFyaWVzXG4gKiB2PCU9IHZlcnNpb24gJT5cbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9mb3Jpby9lcGljZW50ZXItanMtbGlic1xuICovXG5cbnZhciBGID0ge1xuICAgIHV0aWw6IHt9LFxuICAgIGZhY3Rvcnk6IHt9LFxuICAgIHRyYW5zcG9ydDoge30sXG4gICAgc3RvcmU6IHt9LFxuICAgIHNlcnZpY2U6IHt9LFxuICAgIG1hbmFnZXI6IHtcbiAgICAgICAgc3RyYXRlZ3k6IHt9XG4gICAgfSxcblxufTtcblxuRi5sb2FkID0gcmVxdWlyZSgnLi9lbnYtbG9hZCcpO1xuRi5sb2FkKCk7XG5cbkYudXRpbC5xdWVyeSA9IHJlcXVpcmUoJy4vdXRpbC9xdWVyeS11dGlsJyk7XG5GLnV0aWwubWFrZVNlcXVlbmNlID0gcmVxdWlyZSgnLi91dGlsL21ha2Utc2VxdWVuY2UnKTtcbkYudXRpbC5ydW4gPSByZXF1aXJlKCcuL3V0aWwvcnVuLXV0aWwnKTtcbkYudXRpbC5jbGFzc0Zyb20gPSByZXF1aXJlKCcuL3V0aWwvaW5oZXJpdCcpO1xuXG5GLmZhY3RvcnkuVHJhbnNwb3J0ID0gcmVxdWlyZSgnLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xuRi50cmFuc3BvcnQuQWpheCA9IHJlcXVpcmUoJy4vdHJhbnNwb3J0L2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcblxuRi5zZXJ2aWNlLlVSTCA9IHJlcXVpcmUoJy4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcbkYuc2VydmljZS5Db25maWcgPSByZXF1aXJlKCcuL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuUnVuID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkZpbGUgPSByZXF1aXJlKCcuL3NlcnZpY2UvYWRtaW4tZmlsZS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuVmFyaWFibGVzID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3ZhcmlhYmxlcy1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkRhdGEgPSByZXF1aXJlKCcuL3NlcnZpY2UvZGF0YS1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkF1dGggPSByZXF1aXJlKCcuL3NlcnZpY2UvYXV0aC1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLldvcmxkID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG5GLnNlcnZpY2UuU3RhdGUgPSByZXF1aXJlKCcuL3NlcnZpY2Uvc3RhdGUtYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5Vc2VyID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3VzZXItYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5NZW1iZXIgPSByZXF1aXJlKCcuL3NlcnZpY2UvbWVtYmVyLWFwaS1hZGFwdGVyJyk7XG5GLnNlcnZpY2UuQXNzZXQgPSByZXF1aXJlKCcuL3NlcnZpY2UvYXNzZXQtYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5Hcm91cCA9IHJlcXVpcmUoJy4vc2VydmljZS9ncm91cC1hcGktc2VydmljZScpO1xuXG5GLnN0b3JlLkNvb2tpZSA9IHJlcXVpcmUoJy4vc3RvcmUvY29va2llLXN0b3JlJyk7XG5GLmZhY3RvcnkuU3RvcmUgPSByZXF1aXJlKCcuL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcblxuRi5tYW5hZ2VyLlNjZW5hcmlvTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvc2NlbmFyaW8tbWFuYWdlcicpO1xuRi5tYW5hZ2VyLlJ1bk1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1tYW5hZ2VyJyk7XG5GLm1hbmFnZXIuQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL2F1dGgtbWFuYWdlcicpO1xuRi5tYW5hZ2VyLldvcmxkTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvd29ybGQtbWFuYWdlcicpO1xuXG5GLm1hbmFnZXIuc3RyYXRlZ3lbJ2Fsd2F5cy1uZXcnXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvYWx3YXlzLW5ldy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5Wydjb25kaXRpb25hbC1jcmVhdGlvbiddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5LmlkZW50aXR5ID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9pZGVudGl0eS1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtbWlzc2luZyddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtbWlzc2luZyddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtcGVyc2lzdGVkJ10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1wZXJzaXN0ZWQtc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLWluaXRpYWxpemVkJ10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpO1xuXG5GLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXInKTtcbkYuc2VydmljZS5DaGFubmVsID0gcmVxdWlyZSgnLi9zZXJ2aWNlL2NoYW5uZWwtc2VydmljZScpO1xuXG5GLnZlcnNpb24gPSAnPCU9IHZlcnNpb24gJT4nO1xuRi5hcGkgPSByZXF1aXJlKCcuL2FwaS12ZXJzaW9uLmpzb24nKTtcblxuZ2xvYmFsLkYgPSBGO1xubW9kdWxlLmV4cG9ydHMgPSBGO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgdXJsQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcblxudmFyIGVudkxvYWQgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgICB2YXIgZW52UHJvbWlzZTtcbiAgICB2YXIgaG9zdDtcbiAgICB2YXIgdXJsU2VydmljZSA9IHVybENvbmZpZ1NlcnZpY2UoKTtcbiAgICB2YXIgZW52UGF0aCA9ICcvZXBpY2VudGVyL3YxL2NvbmZpZyc7XG4gICAgaWYgKHVybFNlcnZpY2UuaXNMb2NhbGhvc3QoKSkge1xuICAgICAgICBob3N0ID0gJ2h0dHBzOi8vZm9yaW8uY29tJztcbiAgICB9IGVsc2Uge1xuICAgICAgICBob3N0ID0gJyc7XG4gICAgfVxuICAgIHZhciBpbmZvVXJsID0gaG9zdCArIGVudlBhdGg7XG4gICAgZW52UHJvbWlzZSA9ICQuYWpheCh7IHVybDogaW5mb1VybCwgYXN5bmM6IGZhbHNlIH0pO1xuICAgIGVudlByb21pc2UuZG9uZShmdW5jdGlvbiAocmVzKSB7XG4gICAgICAgIHZhciBhcGkgPSByZXMuYXBpO1xuICAgICAgICAkLmV4dGVuZCh1cmxDb25maWdTZXJ2aWNlLCBhcGkpO1xuICAgIH0pLmZhaWwoZnVuY3Rpb24gKHJlcykge1xuICAgICAgICAvLyBFcGljZW50ZXIvd2Vic2VydmVyIG5vdCBwcm9wZXJseSBjb25maWd1cmVkXG4gICAgICAgIC8vIGZhbGxiYWNrIHRvIGFwaS5mb3Jpby5jb21cbiAgICAgICAgJC5leHRlbmQodXJsQ29uZmlnU2VydmljZSwgeyBwcm90b2NvbDogJ2h0dHBzJywgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH0pO1xuICAgIH0pO1xuICAgIHJldHVybiBlbnZQcm9taXNlLmRvbmUoY2FsbGJhY2spLmZhaWwoY2FsbGJhY2spO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBlbnZMb2FkO1xuIiwiLyoqXG4qICMjIEF1dGhvcml6YXRpb24gTWFuYWdlclxuKlxuKiBUaGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyIHByb3ZpZGVzIGFuIGVhc3kgd2F5IHRvIG1hbmFnZSB1c2VyIGF1dGhlbnRpY2F0aW9uIChsb2dnaW5nIGluIGFuZCBvdXQpIGFuZCBhdXRob3JpemF0aW9uIChrZWVwaW5nIHRyYWNrIG9mIHRva2Vucywgc2Vzc2lvbnMsIGFuZCBncm91cHMpIGZvciBwcm9qZWN0cy5cbipcbiogVGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBpcyBtb3N0IHVzZWZ1bCBmb3IgW3RlYW0gcHJvamVjdHNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN0ZWFtKSB3aXRoIGFuIGFjY2VzcyBsZXZlbCBvZiBbQXV0aGVudGljYXRlZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2FjY2VzcykuIFRoZXNlIHByb2plY3RzIGFyZSBhY2Nlc3NlZCBieSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiBvbmUgb3IgbW9yZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS5cbipcbiogIyMjIyBVc2luZyB0aGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyXG4qXG4qIFRvIHVzZSB0aGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyLCBpbnN0YW50aWF0ZSBpdC4gVGhlbiwgbWFrZSBjYWxscyB0byBhbnkgb2YgdGhlIG1ldGhvZHMgeW91IG5lZWQ6XG4qXG4qICAgICAgIHZhciBhdXRoTWdyID0gbmV3IEYubWFuYWdlci5BdXRoTWFuYWdlcih7XG4qICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgICB1c2VyTmFtZTogJ2VuZHVzZXIxJyxcbiogICAgICAgICAgIHBhc3N3b3JkOiAncGFzc3cwcmQnXG4qICAgICAgIH0pO1xuKiAgICAgICBhdXRoTWdyLmxvZ2luKCkudGhlbihmdW5jdGlvbiAoKSB7XG4qICAgICAgICAgICBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiogICAgICAgfSk7XG4qXG4qXG4qIFRoZSBgb3B0aW9uc2Agb2JqZWN0IHBhc3NlZCB0byB0aGUgYEYubWFuYWdlci5BdXRoTWFuYWdlcigpYCBjYWxsIGNhbiBpbmNsdWRlOlxuKlxuKiAgICogYGFjY291bnRgOiBUaGUgYWNjb3VudCBpZCBmb3IgdGhpcyBgdXNlck5hbWVgLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yIHRoZSAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS5cbiogICAqIGB1c2VyTmFtZWA6IEVtYWlsIG9yIHVzZXJuYW1lIHRvIHVzZSBmb3IgbG9nZ2luZyBpbi5cbiogICAqIGBwYXNzd29yZGA6IFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGUgcHJvamVjdCB0byBsb2cgdGhpcyB1c2VyIGludG8uIE9wdGlvbmFsLlxuKiAgICogYGdyb3VwSWRgOiBJZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggYHVzZXJOYW1lYCBiZWxvbmdzLiBSZXF1aXJlZCBmb3IgZW5kIHVzZXJzIGlmIHRoZSBgcHJvamVjdGAgaXMgc3BlY2lmaWVkLlxuKlxuKiBJZiB5b3UgcHJlZmVyIHN0YXJ0aW5nIGZyb20gYSB0ZW1wbGF0ZSwgdGhlIEVwaWNlbnRlciBKUyBMaWJzIFtMb2dpbiBDb21wb25lbnRdKC4uLy4uLyNjb21wb25lbnRzKSB1c2VzIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIgYXMgd2VsbC4gVGhpcyBzYW1wbGUgSFRNTCBwYWdlIChhbmQgYXNzb2NpYXRlZCBDU1MgYW5kIEpTIGZpbGVzKSBwcm92aWRlcyBhIGxvZ2luIGZvcm0gZm9yIHRlYW0gbWVtYmVycyBhbmQgZW5kIHVzZXJzIG9mIHlvdXIgcHJvamVjdC4gSXQgYWxzbyBpbmNsdWRlcyBhIGdyb3VwIHNlbGVjdG9yIGZvciBlbmQgdXNlcnMgdGhhdCBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBncm91cHMuXG4qL1xuXG4ndXNlIHN0cmljdCc7XG52YXIgQXV0aEFkYXB0ZXIgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL2F1dGgtYXBpLXNlcnZpY2UnKTtcbnZhciBNZW1iZXJBZGFwdGVyID0gcmVxdWlyZSgnLi4vc2VydmljZS9tZW1iZXItYXBpLWFkYXB0ZXInKTtcbnZhciBHcm91cFNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL2dyb3VwLWFwaS1zZXJ2aWNlJyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcbnZhciBCdWZmZXIgPSByZXF1aXJlKCdidWZmZXInKS5CdWZmZXI7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG52YXIgb2JqZWN0QXNzaWduID0gcmVxdWlyZSgnb2JqZWN0LWFzc2lnbicpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgcmVxdWlyZXNHcm91cDogdHJ1ZVxufTtcblxuZnVuY3Rpb24gQXV0aE1hbmFnZXIob3B0aW9ucykge1xuICAgIG9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIob3B0aW9ucyk7XG4gICAgdGhpcy5vcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKCk7XG5cbiAgICB0aGlzLmlzTG9jYWwgPSB0aGlzLm9wdGlvbnMuaXNMb2NhbDtcbiAgICB0aGlzLmF1dGhBZGFwdGVyID0gbmV3IEF1dGhBZGFwdGVyKHRoaXMub3B0aW9ucyk7XG59XG5cbnZhciBfZmluZFVzZXJJbkdyb3VwID0gZnVuY3Rpb24gKG1lbWJlcnMsIGlkKSB7XG4gICAgZm9yICh2YXIgaiA9IDA7IGo8bWVtYmVycy5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAobWVtYmVyc1tqXS51c2VySWQgPT09IGlkKSB7XG4gICAgICAgICAgICByZXR1cm4gbWVtYmVyc1tqXTtcbiAgICAgICAgfVxuICAgIH1cblxuXG4gICAgcmV0dXJuIG51bGw7XG59O1xuXG5BdXRoTWFuYWdlci5wcm90b3R5cGUgPSAkLmV4dGVuZChBdXRoTWFuYWdlci5wcm90b3R5cGUsIHtcblxuICAgIC8qKlxuICAgICogTG9ncyB1c2VyIGluLlxuICAgICpcbiAgICAqICoqRXhhbXBsZSoqXG4gICAgKlxuICAgICogICAgICAgYXV0aE1nci5sb2dpbih7XG4gICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgKiAgICAgICAgICAgdXNlck5hbWU6ICdlbmR1c2VyMScsXG4gICAgKiAgICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCdcbiAgICAqICAgICAgIH0pXG4gICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oc3RhdHVzT2JqKSB7XG4gICAgKiAgICAgICAgICAgICAgIC8vIGlmIGVuZHVzZXIxIGJlbG9uZ3MgdG8gZXhhY3RseSBvbmUgZ3JvdXBcbiAgICAqICAgICAgICAgICAgICAgLy8gKG9yIGlmIHRoZSBsb2dpbigpIGNhbGwgaXMgbW9kaWZpZWQgdG8gaW5jbHVkZSB0aGUgZ3JvdXAgaWQpXG4gICAgKiAgICAgICAgICAgICAgIC8vIGNvbnRpbnVlIGhlcmVcbiAgICAqICAgICAgICAgICB9KVxuICAgICogICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uKHN0YXR1c09iaikge1xuICAgICogICAgICAgICAgICAgICAvLyBpZiBlbmR1c2VyMSBiZWxvbmdzIHRvIG11bHRpcGxlIGdyb3VwcyxcbiAgICAqICAgICAgICAgICAgICAgLy8gdGhlIGxvZ2luKCkgY2FsbCBmYWlsc1xuICAgICogICAgICAgICAgICAgICAvLyBhbmQgcmV0dXJucyBhbGwgZ3JvdXBzIG9mIHdoaWNoIHRoZSB1c2VyIGlzIGEgbWVtYmVyXG4gICAgKiAgICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IHN0YXR1c09iai51c2VyR3JvdXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgKiAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzdGF0dXNPYmoudXNlckdyb3Vwc1tpXS5uYW1lLCBzdGF0dXNPYmoudXNlckdyb3Vwc1tpXS5ncm91cElkKTtcbiAgICAqICAgICAgICAgICAgICAgfVxuICAgICogICAgICAgICAgIH0pO1xuICAgICpcbiAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgKlxuICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLiBJZiBub3QgcGFzc2VkIGluIHdoZW4gY3JlYXRpbmcgYW4gaW5zdGFuY2Ugb2YgdGhlIG1hbmFnZXIgKGBGLm1hbmFnZXIuQXV0aE1hbmFnZXIoKWApLCB0aGVzZSBvcHRpb25zIHNob3VsZCBpbmNsdWRlOlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLmFjY291bnRgIFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLnVzZXJOYW1lYCBFbWFpbCBvciB1c2VybmFtZSB0byB1c2UgZm9yIGxvZ2dpbmcgaW4uXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gYG9wdGlvbnMucGFzc3dvcmRgIFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5wcm9qZWN0YCAoT3B0aW9uYWwpIFRoZSAqKlByb2plY3QgSUQqKiBmb3IgdGhlIHByb2plY3QgdG8gbG9nIHRoaXMgdXNlciBpbnRvLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLmdyb3VwSWRgIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggYHVzZXJOYW1lYCBiZWxvbmdzLiBSZXF1aXJlZCBmb3IgW2VuZCB1c2Vyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSBpZiB0aGUgYHByb2plY3RgIGlzIHNwZWNpZmllZCBhbmQgaWYgdGhlIGVuZCB1c2VycyBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSwgb3RoZXJ3aXNlIG9wdGlvbmFsLlxuICAgICovXG4gICAgbG9naW46IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIHNlc3Npb25NYW5hZ2VyID0gdGhpcy5zZXNzaW9uTWFuYWdlcjtcbiAgICAgICAgdmFyIGFkYXB0ZXJPcHRpb25zID0gc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyh7IHN1Y2Nlc3M6ICQubm9vcCwgZXJyb3I6ICQubm9vcCB9LCBvcHRpb25zKTtcbiAgICAgICAgdmFyIG91dFN1Y2Nlc3MgPSBhZGFwdGVyT3B0aW9ucy5zdWNjZXNzO1xuICAgICAgICB2YXIgb3V0RXJyb3IgPSBhZGFwdGVyT3B0aW9ucy5lcnJvcjtcbiAgICAgICAgdmFyIGdyb3VwSWQgPSBhZGFwdGVyT3B0aW9ucy5ncm91cElkO1xuXG4gICAgICAgIHZhciBkZWNvZGVUb2tlbiA9IGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICAgICAgdmFyIGVuY29kZWQgPSB0b2tlbi5zcGxpdCgnLicpWzFdO1xuICAgICAgICAgICAgd2hpbGUgKGVuY29kZWQubGVuZ3RoICUgNCAhPT0gMCkge1xuICAgICAgICAgICAgICAgIGVuY29kZWQgKz0gJz0nO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZGVjb2RlID0gd2luZG93LmF0b2IgPyB3aW5kb3cuYXRvYiA6IGZ1bmN0aW9uIChlbmNvZGVkKSB7IHJldHVybiBuZXcgQnVmZmVyKGVuY29kZWQsICdiYXNlNjQnKS50b1N0cmluZygnYXNjaWknKTsgfTtcblxuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoZGVjb2RlKGVuY29kZWQpKTtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgaGFuZGxlR3JvdXBFcnJvciA9IGZ1bmN0aW9uIChtZXNzYWdlLCBzdGF0dXNDb2RlLCBkYXRhKSB7XG4gICAgICAgICAgICAvLyBsb2dvdXQgdGhlIHVzZXIgc2luY2UgaXQncyBpbiBhbiBpbnZhbGlkIHN0YXRlIHdpdGggbm8gZ3JvdXAgc2VsZWN0ZWRcbiAgICAgICAgICAgIF90aGlzLmxvZ291dCgpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBlcnJvciA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkYXRhLCB7IHN0YXR1c1RleHQ6IG1lc3NhZ2UsIHN0YXR1czogc3RhdHVzQ29kZSB9KTtcbiAgICAgICAgICAgICAgICAkZC5yZWplY3QoZXJyb3IpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIGhhbmRsZVN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgIC8vanNoaW50IGNhbWVsY2FzZTogZmFsc2VcbiAgICAgICAgICAgIC8vanNjczpkaXNhYmxlXG4gICAgICAgICAgICB2YXIgdG9rZW4gPSByZXNwb25zZS5hY2Nlc3NfdG9rZW47XG4gICAgICAgICAgICB2YXIgdXNlckluZm8gPSBkZWNvZGVUb2tlbih0b2tlbik7XG4gICAgICAgICAgICB2YXIgb2xkR3JvdXBzID0gc2Vzc2lvbk1hbmFnZXIuZ2V0U2Vzc2lvbigpLmdyb3VwcyB8fCB7fTtcbiAgICAgICAgICAgIHZhciB1c2VyR3JvdXBPcHRzID0gJC5leHRlbmQodHJ1ZSwge30sIGFkYXB0ZXJPcHRpb25zLCB7IHN1Y2Nlc3M6ICQubm9vcCB9KTtcbiAgICAgICAgICAgIHZhciBkYXRhID0geyBhdXRoOiByZXNwb25zZSwgdXNlcjogdXNlckluZm8gfTtcbiAgICAgICAgICAgIHZhciBwcm9qZWN0ID0gYWRhcHRlck9wdGlvbnMucHJvamVjdDtcbiAgICAgICAgICAgIHZhciBpc1RlYW1NZW1iZXIgPSB1c2VySW5mby5wYXJlbnRfYWNjb3VudF9pZCA9PT0gbnVsbDtcbiAgICAgICAgICAgIHZhciByZXF1aXJlc0dyb3VwID0gYWRhcHRlck9wdGlvbnMucmVxdWlyZXNHcm91cCAmJiBwcm9qZWN0O1xuXG4gICAgICAgICAgICB2YXIgc2Vzc2lvbkluZm8gPSB7XG4gICAgICAgICAgICAgICAgJ2F1dGhfdG9rZW4nOiB0b2tlbixcbiAgICAgICAgICAgICAgICAnYWNjb3VudCc6IGFkYXB0ZXJPcHRpb25zLmFjY291bnQsXG4gICAgICAgICAgICAgICAgJ3Byb2plY3QnOiBwcm9qZWN0LFxuICAgICAgICAgICAgICAgICd1c2VySWQnOiB1c2VySW5mby51c2VyX2lkLFxuICAgICAgICAgICAgICAgICdncm91cHMnOiBvbGRHcm91cHMsXG4gICAgICAgICAgICAgICAgJ2lzVGVhbU1lbWJlcic6IGlzVGVhbU1lbWJlclxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIC8vIFRoZSBncm91cCBpcyBub3QgcmVxdWlyZWQgaWYgdGhlIHVzZXIgaXMgbm90IGxvZ2dpbmcgaW50byBhIHByb2plY3RcbiAgICAgICAgICAgIGlmICghcmVxdWlyZXNHcm91cCkge1xuICAgICAgICAgICAgICAgIHNlc3Npb25NYW5hZ2VyLnNhdmVTZXNzaW9uKHNlc3Npb25JbmZvKTtcbiAgICAgICAgICAgICAgICBvdXRTdWNjZXNzLmFwcGx5KHRoaXMsIFtkYXRhXSk7XG4gICAgICAgICAgICAgICAgJGQucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBoYW5kbGVHcm91cExpc3QgPSBmdW5jdGlvbiAoZ3JvdXBMaXN0KSB7XG4gICAgICAgICAgICAgICAgZGF0YS51c2VyR3JvdXBzID0gZ3JvdXBMaXN0O1xuXG4gICAgICAgICAgICAgICAgdmFyIGdyb3VwID0gbnVsbDtcbiAgICAgICAgICAgICAgICBpZiAoZ3JvdXBMaXN0Lmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICBoYW5kbGVHcm91cEVycm9yKCdUaGUgdXNlciBoYXMgbm8gZ3JvdXBzIGFzc29jaWF0ZWQgaW4gdGhpcyBhY2NvdW50JywgNDAxLCBkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoZ3JvdXBMaXN0Lmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBTZWxlY3QgdGhlIG9ubHkgZ3JvdXBcbiAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBncm91cExpc3RbMF07XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChncm91cExpc3QubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZ3JvdXBJZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZpbHRlcmVkR3JvdXBzID0gJC5ncmVwKGdyb3VwTGlzdCwgZnVuY3Rpb24gKHJlc0dyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc0dyb3VwLmdyb3VwSWQgPT09IGdyb3VwSWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gZmlsdGVyZWRHcm91cHMubGVuZ3RoID09PSAxID8gZmlsdGVyZWRHcm91cHNbMF0gOiBudWxsO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIEEgdGVhbSBtZW1iZXIgZG9lcyBub3QgZ2V0IHRoZSBncm91cCBtZW1iZXJzIGJlY2F1c2UgaXMgY2FsbGluZyB0aGUgR3JvdXAgQVBJXG4gICAgICAgICAgICAgICAgICAgIC8vIGJ1dCBpdCdzIGF1dG9tYXRpY2FsbHkgYSBmYWMgdXNlclxuICAgICAgICAgICAgICAgICAgICB2YXIgaXNGYWMgPSBpc1RlYW1NZW1iZXIgPyB0cnVlIDogX2ZpbmRVc2VySW5Hcm91cChncm91cC5tZW1iZXJzLCB1c2VySW5mby51c2VyX2lkKS5yb2xlID09PSAnZmFjaWxpdGF0b3InO1xuICAgICAgICAgICAgICAgICAgICB2YXIgZ3JvdXBEYXRhID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogZ3JvdXAuZ3JvdXBJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwTmFtZTogZ3JvdXAubmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzRmFjOiBpc0ZhY1xuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICB2YXIgc2Vzc2lvbkluZm9XaXRoR3JvdXAgPSBvYmplY3RBc3NpZ24oe30sIHNlc3Npb25JbmZvLCBncm91cERhdGEpO1xuICAgICAgICAgICAgICAgICAgICBzZXNzaW9uSW5mby5ncm91cHNbcHJvamVjdF0gPSBncm91cERhdGE7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLnNlc3Npb25NYW5hZ2VyLnNhdmVTZXNzaW9uKHNlc3Npb25JbmZvV2l0aEdyb3VwLCBhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW2RhdGFdKTtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBoYW5kbGVHcm91cEVycm9yKCdUaGlzIHVzZXIgaXMgYXNzb2NpYXRlZCB3aXRoIG1vcmUgdGhhbiBvbmUgZ3JvdXAuIFBsZWFzZSBzcGVjaWZ5IGEgZ3JvdXAgaWQgdG8gbG9nIGludG8gYW5kIHRyeSBhZ2FpbicsIDQwMywgZGF0YSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKCFpc1RlYW1NZW1iZXIpIHtcbiAgICAgICAgICAgICAgICBfdGhpcy5nZXRVc2VyR3JvdXBzKHsgdXNlcklkOiB1c2VySW5mby51c2VyX2lkLCB0b2tlbjogdG9rZW4gfSwgdXNlckdyb3VwT3B0cylcbiAgICAgICAgICAgICAgICAgICAgLnRoZW4oaGFuZGxlR3JvdXBMaXN0LCAkZC5yZWplY3QpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB2YXIgb3B0cyA9IG9iamVjdEFzc2lnbih7fSwgdXNlckdyb3VwT3B0cywgeyB0b2tlbjogdG9rZW4gfSk7XG4gICAgICAgICAgICAgICAgdmFyIGdyb3VwU2VydmljZSA9IG5ldyBHcm91cFNlcnZpY2Uob3B0cyk7XG4gICAgICAgICAgICAgICAgZ3JvdXBTZXJ2aWNlLmdldEdyb3Vwcyh7IGFjY291bnQ6IGFkYXB0ZXJPcHRpb25zLmFjY291bnQsIHByb2plY3Q6IHByb2plY3QgfSlcbiAgICAgICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKGdyb3Vwcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gR3JvdXAgQVBJIHJldHVybnMgaWQgaW5zdGVhZCBvZiBncm91cElkXG4gICAgICAgICAgICAgICAgICAgICAgICBncm91cHMuZm9yRWFjaChmdW5jdGlvbiAoZ3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cC5ncm91cElkID0gZ3JvdXAuaWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGhhbmRsZUdyb3VwTGlzdChncm91cHMpO1xuICAgICAgICAgICAgICAgICAgICB9LCAkZC5yZWplY3QpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3MgPSBoYW5kbGVTdWNjZXNzO1xuICAgICAgICBhZGFwdGVyT3B0aW9ucy5lcnJvciA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgaWYgKGFkYXB0ZXJPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgICAgICAgICAvLyBUcnkgdG8gbG9naW4gYXMgYSBzeXN0ZW0gdXNlclxuICAgICAgICAgICAgICAgIGFkYXB0ZXJPcHRpb25zLmFjY291bnQgPSBudWxsO1xuICAgICAgICAgICAgICAgIGFkYXB0ZXJPcHRpb25zLmVycm9yID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICBvdXRFcnJvci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAkZC5yZWplY3QocmVzcG9uc2UpO1xuICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICBfdGhpcy5hdXRoQWRhcHRlci5sb2dpbihhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBvdXRFcnJvci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgJGQucmVqZWN0KHJlc3BvbnNlKTtcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLmF1dGhBZGFwdGVyLmxvZ2luKGFkYXB0ZXJPcHRpb25zKTtcbiAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgKiBMb2dzIHVzZXIgb3V0IGJ5IGNsZWFyaW5nIGFsbCBzZXNzaW9uIGluZm9ybWF0aW9uLlxuICAgICpcbiAgICAqICoqRXhhbXBsZSoqXG4gICAgKlxuICAgICogICAgICAgYXV0aE1nci5sb2dvdXQoKTtcbiAgICAqXG4gICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICpcbiAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAqL1xuICAgIGxvZ291dDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIGFkYXB0ZXJPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciByZW1vdmVDb29raWVGbiA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgX3RoaXMuc2Vzc2lvbk1hbmFnZXIucmVtb3ZlU2Vzc2lvbigpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiB0aGlzLmF1dGhBZGFwdGVyLmxvZ291dChhZGFwdGVyT3B0aW9ucykuZG9uZShyZW1vdmVDb29raWVGbik7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGV4aXN0aW5nIHVzZXIgYWNjZXNzIHRva2VuIGlmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluLiBPdGhlcndpc2UsIGxvZ3MgdGhlIHVzZXIgaW4sIGNyZWF0aW5nIGEgbmV3IHVzZXIgYWNjZXNzIHRva2VuLCBhbmQgcmV0dXJucyB0aGUgbmV3IHRva2VuLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBhdXRoTWdyLmdldFRva2VuKClcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgKiAgICAgICAgICAgICAgY29uc29sZS5sb2coJ015IHRva2VuIGlzICcsIHRva2VuKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldFRva2VuOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMob3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldFNlc3Npb24oKTtcbiAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAvL2pzaGludCBjYW1lbGNhc2U6IGZhbHNlXG4gICAgICAgIC8vanNjczpkaXNhYmxlXG4gICAgICAgIGlmIChzZXNzaW9uLmF1dGhfdG9rZW4pIHtcbiAgICAgICAgICAgICRkLnJlc29sdmUoc2Vzc2lvbi5hdXRoX3Rva2VuKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMubG9naW4oaHR0cE9wdGlvbnMpLnRoZW4oJGQucmVzb2x2ZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhbiBhcnJheSBvZiBncm91cCByZWNvcmRzLCBvbmUgZm9yIGVhY2ggZ3JvdXAgb2Ygd2hpY2ggdGhlIGN1cnJlbnQgdXNlciBpcyBhIG1lbWJlci4gRWFjaCBncm91cCByZWNvcmQgaW5jbHVkZXMgdGhlIGdyb3VwIGBuYW1lYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgZ3JvdXBJZGAuXG4gICAgICpcbiAgICAgKiBJZiBzb21lIGVuZCB1c2VycyBpbiB5b3VyIHByb2plY3QgYXJlIG1lbWJlcnMgb2YgbXVsdGlwbGUgZ3JvdXBzLCB0aGlzIGlzIGEgdXNlZnVsIG1ldGhvZCB0byBjYWxsIG9uIHlvdXIgcHJvamVjdCdzIGxvZ2luIHBhZ2UuIFdoZW4gdGhlIHVzZXIgYXR0ZW1wdHMgdG8gbG9nIGluLCB5b3UgY2FuIHVzZSB0aGlzIHRvIGRpc3BsYXkgdGhlIGdyb3VwcyBvZiB3aGljaCB0aGUgdXNlciBpcyBtZW1iZXIsIGFuZCBoYXZlIHRoZSB1c2VyIHNlbGVjdCB0aGUgY29ycmVjdCBncm91cCB0byBsb2cgaW4gdG8gZm9yIHRoaXMgc2Vzc2lvbi5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIGN1cnJlbnQgdXNlclxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKiAgICAgIGF1dGhNZ3IuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogc2Vzc2lvbk9iai51c2VySWQsIHRva2VuOiBzZXNzaW9uT2JqLmF1dGhfdG9rZW4gfSlcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAoZ3JvdXBzKSB7XG4gICAgICogICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IGdyb3Vwcy5sZW5ndGg7IGkrKylcbiAgICAgKiAgICAgICAgICAgICAgICAgIHsgY29uc29sZS5sb2coZ3JvdXBzW2ldLm5hbWUpOyB9XG4gICAgICogICAgICAgICAgfSk7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIHBhcnRpY3VsYXIgdXNlclxuICAgICAqICAgICAgYXV0aE1nci5nZXRVc2VyR3JvdXBzKHt1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB0b2tlbjogc2F2ZWRQcm9qQWNjZXNzVG9rZW4gfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgcGFyYW1zYCBPYmplY3Qgd2l0aCBhIHVzZXJJZCBhbmQgdG9rZW4gcHJvcGVydGllcy5cbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gYHBhcmFtcy51c2VySWRgIFRoZSB1c2VySWQuIElmIGxvb2tpbmcgdXAgZ3JvdXBzIGZvciB0aGUgY3VycmVudGx5IGxvZ2dlZCBpbiB1c2VyLCB0aGlzIGlzIGluIHRoZSBzZXNzaW9uIGluZm9ybWF0aW9uLiBPdGhlcndpc2UsIHBhc3MgYSBzdHJpbmcuXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IGBwYXJhbXMudG9rZW5gIFRoZSBhdXRob3JpemF0aW9uIGNyZWRlbnRpYWxzIChhY2Nlc3MgdG9rZW4pIHRvIHVzZSBmb3IgY2hlY2tpbmcgdGhlIGdyb3VwcyBmb3IgdGhpcyB1c2VyLiBJZiBsb29raW5nIHVwIGdyb3VwcyBmb3IgdGhlIGN1cnJlbnRseSBsb2dnZWQgaW4gdXNlciwgdGhpcyBpcyBpbiB0aGUgc2Vzc2lvbiBpbmZvcm1hdGlvbi4gQSB0ZWFtIG1lbWJlcidzIHRva2VuIG9yIGEgcHJvamVjdCBhY2Nlc3MgdG9rZW4gY2FuIGFjY2VzcyBhbGwgdGhlIGdyb3VwcyBmb3IgYWxsIGVuZCB1c2VycyBpbiB0aGUgdGVhbSBvciBwcm9qZWN0LlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgKi9cbiAgICBnZXRVc2VyR3JvdXBzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBhZGFwdGVyT3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyh7IHN1Y2Nlc3M6ICQubm9vcCB9LCBvcHRpb25zKTtcbiAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgb3V0U3VjY2VzcyA9IGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3M7XG5cbiAgICAgICAgYWRhcHRlck9wdGlvbnMuc3VjY2VzcyA9IGZ1bmN0aW9uIChtZW1iZXJJbmZvKSB7XG4gICAgICAgICAgICAvLyBUaGUgbWVtYmVyIEFQSSBpcyBhdCB0aGUgYWNjb3VudCBzY29wZSwgd2UgZmlsdGVyIGJ5IHByb2plY3RcbiAgICAgICAgICAgIGlmIChhZGFwdGVyT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgbWVtYmVySW5mbyA9ICQuZ3JlcChtZW1iZXJJbmZvLCBmdW5jdGlvbiAoZ3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGdyb3VwLnByb2plY3QgPT09IGFkYXB0ZXJPcHRpb25zLnByb2plY3Q7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW21lbWJlckluZm9dKTtcbiAgICAgICAgICAgICRkLnJlc29sdmUobWVtYmVySW5mbyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIG1lbWJlckFkYXB0ZXIgPSBuZXcgTWVtYmVyQWRhcHRlcih7IHRva2VuOiBwYXJhbXMudG9rZW4gfSk7XG4gICAgICAgIG1lbWJlckFkYXB0ZXIuZ2V0R3JvdXBzRm9yVXNlcihwYXJhbXMsIGFkYXB0ZXJPcHRpb25zKS5mYWlsKCRkLnJlamVjdCk7XG4gICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgc2Vzc2lvbiBpbmZvcm1hdGlvbiBmb3IgdGhlIGN1cnJlbnQgdXNlciwgaW5jbHVkaW5nIHRoZSBgdXNlcklkYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGBncm91cElkYCwgYGdyb3VwTmFtZWAsIGBpc0ZhY2AgKHdoZXRoZXIgdGhlIGVuZCB1c2VyIGlzIGEgZmFjaWxpdGF0b3Igb2YgdGhpcyBncm91cCksIGFuZCBgYXV0aF90b2tlbmAgKHVzZXIgYWNjZXNzIHRva2VuKS5cbiAgICAgKlxuICAgICAqICpJbXBvcnRhbnQqOiBUaGlzIG1ldGhvZCBpcyBzeW5jaHJvbm91cy4gVGhlIHNlc3Npb24gaW5mb3JtYXRpb24gaXMgcmV0dXJuZWQgaW1tZWRpYXRlbHkgaW4gYW4gb2JqZWN0OyBubyBjYWxsYmFja3Mgb3IgcHJvbWlzZXMgYXJlIG5lZWRlZC5cbiAgICAgKlxuICAgICAqIFNlc3Npb24gaW5mb3JtYXRpb24gaXMgc3RvcmVkIGluIGEgY29va2llIGluIHRoZSBicm93c2VyLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm86IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldFNlc3Npb24ob3B0aW9ucyk7XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogQWRkcyBvbmUgb3IgbW9yZSBncm91cHMgdG8gdGhlIGN1cnJlbnQgc2Vzc2lvbi4gXG4gICAgICpcbiAgICAgKiBUaGlzIG1ldGhvZCBhc3N1bWVzIHRoYXQgdGhlIHByb2plY3QgYW5kIGdyb3VwIGV4aXN0IGFuZCB0aGUgdXNlciBzcGVjaWZpZWQgaW4gdGhlIHNlc3Npb24gaXMgcGFydCBvZiB0aGlzIHByb2plY3QgYW5kIGdyb3VwLlxuICAgICAqXG4gICAgICogUmV0dXJucyB0aGUgbmV3IHNlc3Npb24gb2JqZWN0LlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgYXV0aE1nci5hZGRHcm91cHMoeyBwcm9qZWN0OiAnaGVsbG8td29ybGQnLCBncm91cE5hbWU6ICdncm91cE5hbWUnLCBncm91cElkOiAnZ3JvdXBJZCcgfSk7XG4gICAgICogICAgICBhdXRoTWdyLmFkZEdyb3VwcyhbeyBwcm9qZWN0OiAnaGVsbG8td29ybGQnLCBncm91cE5hbWU6ICdncm91cE5hbWUnLCBncm91cElkOiAnZ3JvdXBJZCcgfSwgeyBwcm9qZWN0OiAnaGVsbG8td29ybGQnLCBncm91cE5hbWU6ICcuLi4nIH1dKTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtvYmplY3R8YXJyYXl9IGBncm91cHNgIChSZXF1aXJlZCkgVGhlIGdyb3VwIG9iamVjdCBtdXN0IGNvbnRhaW4gdGhlIGBwcm9qZWN0YCAoKipQcm9qZWN0IElEKiopIGFuZCBgZ3JvdXBOYW1lYCBwcm9wZXJ0aWVzLiBJZiBwYXNzaW5nIGFuIGFycmF5IG9mIHN1Y2ggb2JqZWN0cywgYWxsIG9mIHRoZSBvYmplY3RzIG11c3QgY29udGFpbiAqZGlmZmVyZW50KiBgcHJvamVjdGAgKCoqUHJvamVjdCBJRCoqKSB2YWx1ZXM6IGFsdGhvdWdoIGVuZCB1c2VycyBtYXkgYmUgbG9nZ2VkIGluIHRvIG11bHRpcGxlIHByb2plY3RzIGF0IG9uY2UsIHRoZXkgbWF5IG9ubHkgYmUgbG9nZ2VkIGluIHRvIG9uZSBncm91cCBwZXIgcHJvamVjdCBhdCBhIHRpbWUuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBncm91cC5pc0ZhY2AgKG9wdGlvbmFsKSBEZWZhdWx0cyB0byBgZmFsc2VgLiBTZXQgdG8gYHRydWVgIGlmIHRoZSB1c2VyIGluIHRoZSBzZXNzaW9uIHNob3VsZCBiZSBhIGZhY2lsaXRhdG9yIGluIHRoaXMgZ3JvdXAuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBncm91cC5ncm91cElkYCAob3B0aW9uYWwpIERlZmF1bHRzIHRvIHVuZGVmaW5lZC4gTmVlZGVkIG1vc3RseSBmb3IgdGhlIE1lbWJlcnMgQVBJLlxuICAgICovXG4gICAgYWRkR3JvdXBzOiBmdW5jdGlvbiAoZ3JvdXBzKSB7XG4gICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgIHZhciBpc0FycmF5ID0gQXJyYXkuaXNBcnJheShncm91cHMpO1xuICAgICAgICBncm91cHMgPSBpc0FycmF5ID8gZ3JvdXBzIDogW2dyb3Vwc107XG5cbiAgICAgICAgJC5lYWNoKGdyb3VwcywgZnVuY3Rpb24gKGluZGV4LCBncm91cCkge1xuICAgICAgICAgICAgdmFyIGV4dGVuZGVkR3JvdXAgPSAkLmV4dGVuZCh7fSwgeyBpc0ZhYzogZmFsc2UgfSwgZ3JvdXApO1xuICAgICAgICAgICAgdmFyIHByb2plY3QgPSBleHRlbmRlZEdyb3VwLnByb2plY3Q7XG4gICAgICAgICAgICB2YXIgdmFsaWRQcm9wcyA9IFsnZ3JvdXBOYW1lJywgJ2dyb3VwSWQnLCAnaXNGYWMnXTtcbiAgICAgICAgICAgIGlmICghcHJvamVjdCB8fCAhZXh0ZW5kZWRHcm91cC5ncm91cE5hbWUpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIHByb2plY3Qgb3IgZ3JvdXBOYW1lIHNwZWNpZmllZC4nKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIGZpbHRlciBvYmplY3RcbiAgICAgICAgICAgIGV4dGVuZGVkR3JvdXAgPSBfcGljayhleHRlbmRlZEdyb3VwLCB2YWxpZFByb3BzKTtcbiAgICAgICAgICAgIHNlc3Npb24uZ3JvdXBzW3Byb2plY3RdID0gZXh0ZW5kZWRHcm91cDtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIuc2F2ZVNlc3Npb24oc2Vzc2lvbik7XG4gICAgICAgIHJldHVybiBzZXNzaW9uO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEF1dGhNYW5hZ2VyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ2hhbm5lbCA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlJyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcblxuLyoqXG4gKiAjIyBDaGFubmVsIE1hbmFnZXJcbiAqXG4gKiBUaGVyZSBhcmUgdHdvIG1haW4gdXNlIGNhc2VzIGZvciB0aGUgY2hhbm5lbDogZXZlbnQgbm90aWZpY2F0aW9ucyBhbmQgY2hhdCBtZXNzYWdlcy5cbiAqXG4gKiBUaGUgQ2hhbm5lbCBNYW5hZ2VyIGlzIGEgd3JhcHBlciBhcm91bmQgdGhlIGRlZmF1bHQgW2NvbWV0ZCBKYXZhU2NyaXB0IGxpYnJhcnldKGh0dHA6Ly9kb2NzLmNvbWV0ZC5vcmcvMi9yZWZlcmVuY2UvamF2YXNjcmlwdC5odG1sKSwgYCQuY29tZXRkYC4gSXQgcHJvdmlkZXMgYSBmZXcgbmljZSBmZWF0dXJlcyB0aGF0IGAkLmNvbWV0ZGAgZG9lc24ndCwgaW5jbHVkaW5nOlxuICpcbiAqICogQXV0b21hdGljIHJlLXN1YnNjcmlwdGlvbiB0byBjaGFubmVscyBpZiB5b3UgbG9zZSB5b3VyIGNvbm5lY3Rpb25cbiAqICogT25saW5lIC8gT2ZmbGluZSBub3RpZmljYXRpb25zXG4gKiAqICdFdmVudHMnIGZvciBjb21ldGQgbm90aWZpY2F0aW9ucyAoaW5zdGVhZCBvZiBoYXZpbmcgdG8gbGlzdGVuIG9uIHNwZWNpZmljIG1ldGEgY2hhbm5lbHMpXG4gKlxuICogV2hpbGUgeW91IGNhbiB3b3JrIGRpcmVjdGx5IHdpdGggdGhlIENoYW5uZWwgTWFuYWdlciB0aHJvdWdoIE5vZGUuanMgKGZvciBleGFtcGxlLCBgcmVxdWlyZSgnbWFuYWdlci9jaGFubmVsLW1hbmFnZXInKWApIC0tIG9yIGV2ZW4gd29yayBkaXJlY3RseSB3aXRoIGAkLmNvbWV0ZGAgYW5kIEVwaWNlbnRlcidzIHVuZGVybHlpbmcgW1B1c2ggQ2hhbm5lbCBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLykgLS0gbW9zdCBvZnRlbiBpdCB3aWxsIGJlIGVhc2llc3QgdG8gd29yayB3aXRoIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pLiBUaGUgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpcyBhIHdyYXBwZXIgdGhhdCBpbnN0YW50aWF0ZXMgYSBDaGFubmVsIE1hbmFnZXIgd2l0aCBFcGljZW50ZXItc3BlY2lmaWMgZGVmYXVsdHMuXG4gKlxuICogWW91J2xsIG5lZWQgdG8gaW5jbHVkZSB0aGUgYGVwaWNlbnRlci1tdWx0aXBsYXllci1kZXBlbmRlbmNpZXMuanNgIGxpYnJhcnkgaW4gYWRkaXRpb24gdG8gdGhlIGBlcGljZW50ZXIuanNgIGxpYnJhcnkgaW4geW91ciBwcm9qZWN0IHRvIHVzZSB0aGUgQ2hhbm5lbCBNYW5hZ2VyLiAoU2VlIFtJbmNsdWRpbmcgRXBpY2VudGVyLmpzXSguLi8uLi8jaW5jbHVkZSkuKVxuICpcbiAqIFRvIHVzZSB0aGUgQ2hhbm5lbCBNYW5hZ2VyIGluIGNsaWVudC1zaWRlIEphdmFTY3JpcHQsIGluc3RhbnRpYXRlIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pLCBnZXQgdGhlIGNoYW5uZWwsIHRoZW4gdXNlIHRoZSBjaGFubmVsJ3MgYHN1YnNjcmliZSgpYCBhbmQgYHB1Ymxpc2goKWAgbWV0aG9kcyB0byBzdWJzY3JpYmUgdG8gdG9waWNzIG9yIHB1Ymxpc2ggZGF0YSB0byB0b3BpY3MuXG4gKlxuICogICAgICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAqICAgICAgICB2YXIgY2hhbm5lbCA9IGNtLmdldENoYW5uZWwoKTtcbiAqXG4gKiAgICAgICAgY2hhbm5lbC5zdWJzY3JpYmUoJ3RvcGljJywgY2FsbGJhY2spO1xuICogICAgICAgIGNoYW5uZWwucHVibGlzaCgndG9waWMnLCB7IG15RGF0YTogMTAwIH0pO1xuICpcbiAqIFRoZSBwYXJhbWV0ZXJzIGZvciBpbnN0YW50aWF0aW5nIGEgQ2hhbm5lbCBNYW5hZ2VyIGluY2x1ZGU6XG4gKlxuICogKiBgb3B0aW9uc2AgVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGUgQ2hhbm5lbCBNYW5hZ2VyLiBCZXNpZGVzIHRoZSBjb21tb24gb3B0aW9ucyBsaXN0ZWQgaGVyZSwgc2VlIGh0dHA6Ly9kb2NzLmNvbWV0ZC5vcmcvcmVmZXJlbmNlL2phdmFzY3JpcHQuaHRtbCBmb3Igb3RoZXIgc3VwcG9ydGVkIG9wdGlvbnMuXG4gKiAqIGBvcHRpb25zLnVybGAgVGhlIENvbWV0ZCBlbmRwb2ludCBVUkwuXG4gKiAqIGBvcHRpb25zLndlYnNvY2tldEVuYWJsZWRgIFdoZXRoZXIgd2Vic29ja2V0IHN1cHBvcnQgaXMgYWN0aXZlIChib29sZWFuKS5cbiAqICogYG9wdGlvbnMuY2hhbm5lbGAgT3RoZXIgZGVmYXVsdHMgdG8gcGFzcyBvbiB0byBpbnN0YW5jZXMgb2YgdGhlIHVuZGVybHlpbmcgQ2hhbm5lbCBTZXJ2aWNlLiBTZWUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykgZm9yIGRldGFpbHMuXG4gKlxuICovXG52YXIgQ2hhbm5lbE1hbmFnZXIgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIGlmICghJC5jb21ldGQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb21ldGQgbGlicmFyeSBub3QgZm91bmQuIFBsZWFzZSBpbmNsdWRlIGVwaWNlbnRlci1tdWx0aXBsYXllci1kZXBlbmRlbmNpZXMuanMnKTtcbiAgICB9XG4gICAgaWYgKCFvcHRpb25zIHx8ICFvcHRpb25zLnVybCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwcm92aWRlIGFuIHVybCBmb3IgdGhlIGNvbWV0ZCBzZXJ2ZXInKTtcbiAgICB9XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgQ29tZXRkIGVuZHBvaW50IFVSTC5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVybDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBsb2cgbGV2ZWwgZm9yIHRoZSBjaGFubmVsIChsb2dzIHRvIGNvbnNvbGUpLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgbG9nTGV2ZWw6ICdpbmZvJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogV2hldGhlciB3ZWJzb2NrZXQgc3VwcG9ydCBpcyBhY3RpdmUuIERlZmF1bHRzIHRvIGBmYWxzZWA7IEVwaWNlbnRlciBkb2Vzbid0IGN1cnJlbnRseSBzdXBwb3J0IGNvbW11bmljYXRpb24gdGhyb3VnaCB3ZWJzb2NrZXRzLlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn1cbiAgICAgICAgICovXG4gICAgICAgIHdlYnNvY2tldEVuYWJsZWQ6IGZhbHNlLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBJZiBmYWxzZSBlYWNoIGluc3RhbmNlIG9mIENoYW5uZWwgd2lsbCBoYXZlIGEgc2VwYXJhdGUgY29tZXRkIGNvbm5lY3Rpb24gdG8gc2VydmVyLCB3aGljaCBjb3VsZCBiZSBub2lzeS4gU2V0IHRvIHRydWUgdG8gcmUtdXNlIHRoZSBzYW1lIGNvbm5lY3Rpb24gYWNyb3NzIGluc3RhbmNlcy5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBzaGFyZUNvbm5lY3Rpb246IGZhbHNlLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPdGhlciBkZWZhdWx0cyB0byBwYXNzIG9uIHRvIGluc3RhbmNlcyBvZiB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSwgd2hpY2ggYXJlIGNyZWF0ZWQgdGhyb3VnaCBgZ2V0Q2hhbm5lbCgpYC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIGNoYW5uZWw6IHtcblxuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3MgdG8gdGhlIGNoYW5uZWwgaGFuZHNoYWtlLlxuICAgICAgICAgKlxuICAgICAgICAgKiBGb3IgZXhhbXBsZSwgdGhlIFtFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLykgcGFzc2VzIGBleHRgIGFuZCBhdXRob3JpemF0aW9uIGluZm9ybWF0aW9uLiBNb3JlIGluZm9ybWF0aW9uIG9uIHBvc3NpYmxlIG9wdGlvbnMgaXMgaW4gdGhlIGRldGFpbHMgb2YgdGhlIHVuZGVybHlpbmcgW1B1c2ggQ2hhbm5lbCBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLykuXG4gICAgICAgICAqXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBoYW5kc2hha2U6IHVuZGVmaW5lZFxuICAgIH07XG4gICAgdGhpcy5zZXNzaW9uTWFuYWdlciA9IG5ldyBTZXNzaW9uTWFuYWdlcigpO1xuICAgIHZhciBkZWZhdWx0Q29tZXRPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICB0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zID0gW107XG4gICAgdGhpcy5vcHRpb25zID0gZGVmYXVsdENvbWV0T3B0aW9ucztcblxuICAgIGlmIChkZWZhdWx0Q29tZXRPcHRpb25zLnNoYXJlQ29ubmVjdGlvbiAmJiBDaGFubmVsTWFuYWdlci5wcm90b3R5cGUuX2NvbWV0ZCkge1xuICAgICAgICB0aGlzLmNvbWV0ZCA9IENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZS5fY29tZXRkO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG4gICAgdmFyIGNvbWV0ZCA9IG5ldyAkLkNvbWV0ZCgpO1xuICAgIENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZS5fY29tZXRkID0gY29tZXRkO1xuXG4gICAgY29tZXRkLndlYnNvY2tldEVuYWJsZWQgPSBkZWZhdWx0Q29tZXRPcHRpb25zLndlYnNvY2tldEVuYWJsZWQ7XG5cbiAgICB0aGlzLmlzQ29ubmVjdGVkID0gZmFsc2U7XG4gICAgdmFyIGNvbm5lY3Rpb25Ccm9rZW4gPSBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIoJ2Rpc2Nvbm5lY3QnLCBtZXNzYWdlKTtcbiAgICB9O1xuICAgIHZhciBjb25uZWN0aW9uU3VjY2VlZGVkID0gZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyKCdjb25uZWN0JywgbWVzc2FnZSk7XG4gICAgfTtcbiAgICB2YXIgbWUgPSB0aGlzO1xuXG4gICAgY29tZXRkLmNvbmZpZ3VyZShkZWZhdWx0Q29tZXRPcHRpb25zKTtcblxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvY29ubmVjdCcsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgIHZhciB3YXNDb25uZWN0ZWQgPSB0aGlzLmlzQ29ubmVjdGVkO1xuICAgICAgICB0aGlzLmlzQ29ubmVjdGVkID0gKG1lc3NhZ2Uuc3VjY2Vzc2Z1bCA9PT0gdHJ1ZSk7XG4gICAgICAgIGlmICghd2FzQ29ubmVjdGVkICYmIHRoaXMuaXNDb25uZWN0ZWQpIHsgLy9Db25uZWN0aW5nIGZvciB0aGUgZmlyc3QgdGltZVxuICAgICAgICAgICAgY29ubmVjdGlvblN1Y2NlZWRlZC5jYWxsKHRoaXMsIG1lc3NhZ2UpO1xuICAgICAgICB9IGVsc2UgaWYgKHdhc0Nvbm5lY3RlZCAmJiAhdGhpcy5pc0Nvbm5lY3RlZCkgeyAvL09ubHkgdGhyb3cgZGlzY29ubmVjdGVkIG1lc3NhZ2UgZnJvIHRoZSBmaXJzdCBkaXNjb25uZWN0LCBub3Qgb25jZSBwZXIgdHJ5XG4gICAgICAgICAgICBjb25uZWN0aW9uQnJva2VuLmNhbGwodGhpcywgbWVzc2FnZSk7XG4gICAgICAgIH1cbiAgICB9LmJpbmQodGhpcykpO1xuXG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9kaXNjb25uZWN0JywgY29ubmVjdGlvbkJyb2tlbik7XG5cbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL2hhbmRzaGFrZScsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgIGlmIChtZXNzYWdlLnN1Y2Nlc3NmdWwpIHtcbiAgICAgICAgICAgIC8vaHR0cDovL2RvY3MuY29tZXRkLm9yZy9yZWZlcmVuY2UvamF2YXNjcmlwdF9zdWJzY3JpYmUuaHRtbCNqYXZhc2NyaXB0X3N1YnNjcmliZV9tZXRhX2NoYW5uZWxzXG4gICAgICAgICAgICAvLyBeIFwiZHluYW1pYyBzdWJzY3JpcHRpb25zIGFyZSBjbGVhcmVkIChsaWtlIGFueSBvdGhlciBzdWJzY3JpcHRpb24pIGFuZCB0aGUgYXBwbGljYXRpb24gbmVlZHMgdG8gZmlndXJlIG91dCB3aGljaCBkeW5hbWljIHN1YnNjcmlwdGlvbiBtdXN0IGJlIHBlcmZvcm1lZCBhZ2FpblwiXG4gICAgICAgICAgICBjb21ldGQuYmF0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICQobWUuY3VycmVudFN1YnNjcmlwdGlvbnMpLmVhY2goZnVuY3Rpb24gKGluZGV4LCBzdWJzKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbWV0ZC5yZXN1YnNjcmliZShzdWJzKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICAvL090aGVyIGludGVyZXN0aW5nIGV2ZW50cyBmb3IgcmVmZXJlbmNlXG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9zdWJzY3JpYmUnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKG1lKS50cmlnZ2VyKCdzdWJzY3JpYmUnLCBtZXNzYWdlKTtcbiAgICB9KTtcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3Vuc3Vic2NyaWJlJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJChtZSkudHJpZ2dlcigndW5zdWJzY3JpYmUnLCBtZXNzYWdlKTtcbiAgICB9KTtcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3B1Ymxpc2gnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKG1lKS50cmlnZ2VyKCdwdWJsaXNoJywgbWVzc2FnZSk7XG4gICAgfSk7XG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS91bnN1Y2Nlc3NmdWwnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKG1lKS50cmlnZ2VyKCdlcnJvcicsIG1lc3NhZ2UpO1xuICAgIH0pO1xuXG4gICAgY29tZXRkLmhhbmRzaGFrZShkZWZhdWx0Q29tZXRPcHRpb25zLmhhbmRzaGFrZSk7XG5cbiAgICB0aGlzLmNvbWV0ZCA9IGNvbWV0ZDtcbn07XG5cblxuQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlID0gJC5leHRlbmQoQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLCB7XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgY2hhbm5lbCwgdGhhdCBpcywgYW4gaW5zdGFuY2Ugb2YgYSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgIHZhciBjaGFubmVsID0gY20uZ2V0Q2hhbm5lbCgpO1xuICAgICAqXG4gICAgICogICAgICBjaGFubmVsLnN1YnNjcmliZSgndG9waWMnLCBjYWxsYmFjayk7XG4gICAgICogICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBJZiBzdHJpbmcsIGFzc3VtZWQgdG8gYmUgdGhlIGJhc2UgY2hhbm5lbCB1cmwuIElmIG9iamVjdCwgYXNzdW1lZCB0byBiZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjb25zdHJ1Y3Rvci5cbiAgICAgKi9cbiAgICBnZXRDaGFubmVsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvL0lmIHlvdSBqdXN0IHdhbnQgdG8gcGFzcyBpbiBhIHN0cmluZ1xuICAgICAgICBpZiAob3B0aW9ucyAmJiAhJC5pc1BsYWluT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgICAgICAgICBvcHRpb25zID0ge1xuICAgICAgICAgICAgICAgIGJhc2U6IG9wdGlvbnNcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAgICAgdHJhbnNwb3J0OiB0aGlzLmNvbWV0ZFxuICAgICAgICB9O1xuICAgICAgICB2YXIgY2hhbm5lbCA9IG5ldyBDaGFubmVsKCQuZXh0ZW5kKHRydWUsIHt9LCB0aGlzLm9wdGlvbnMuY2hhbm5lbCwgZGVmYXVsdHMsIG9wdGlvbnMpKTtcblxuXG4gICAgICAgIC8vV3JhcCBzdWJzIGFuZCB1bnN1YnMgc28gd2UgY2FuIHVzZSBpdCB0byByZS1hdHRhY2ggaGFuZGxlcnMgYWZ0ZXIgYmVpbmcgZGlzY29ubmVjdGVkXG4gICAgICAgIHZhciBzdWJzID0gY2hhbm5lbC5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHN1YmlkID0gc3Vicy5hcHBseShjaGFubmVsLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucyAgPSB0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zLmNvbmNhdChzdWJpZCk7XG4gICAgICAgICAgICByZXR1cm4gc3ViaWQ7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuXG4gICAgICAgIHZhciB1bnN1YnMgPSBjaGFubmVsLnVuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnVuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJlbW92ZWQgPSB1bnN1YnMuYXBwbHkoY2hhbm5lbCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zW2ldLmlkID09PSByZW1vdmVkLmlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMuc3BsaWNlKGksIDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZW1vdmVkO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0YXJ0IGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqXG4gICAgICogU3VwcG9ydGVkIGV2ZW50cyBhcmU6IGBjb25uZWN0YCwgYGRpc2Nvbm5lY3RgLCBgc3Vic2NyaWJlYCwgYHVuc3Vic2NyaWJlYCwgYHB1Ymxpc2hgLCBgZXJyb3JgLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29uLy5cbiAgICAgKi9cbiAgICBvbjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub24uYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RvcCBsaXN0ZW5pbmcgZm9yIGV2ZW50cyBvbiB0aGlzIGluc3RhbmNlLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKi9cbiAgICBvZmY6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLm9mZi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUcmlnZ2VyIGV2ZW50cyBhbmQgZXhlY3V0ZSBoYW5kbGVycy4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKi9cbiAgICB0cmlnZ2VyOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuICogIyMgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlclxuICpcbiAqIFRoZSBFcGljZW50ZXIgcGxhdGZvcm0gcHJvdmlkZXMgYSBwdXNoIGNoYW5uZWwsIHdoaWNoIGFsbG93cyB5b3UgdG8gcHVibGlzaCBhbmQgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzIHdpdGhpbiBhIFtwcm9qZWN0XSguLi8uLi8uLi9nbG9zc2FyeS8jcHJvamVjdHMpLCBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvciBbbXVsdGlwbGF5ZXIgd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuIFRoZXJlIGFyZSB0d28gbWFpbiB1c2UgY2FzZXMgZm9yIHRoZSBjaGFubmVsOiBldmVudCBub3RpZmljYXRpb25zIGFuZCBjaGF0IG1lc3NhZ2VzLlxuICpcbiAqIFRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIGEgd3JhcHBlciBhcm91bmQgdGhlIChtb3JlIGdlbmVyaWMpIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pLCB0byBpbnN0YW50aWF0ZSBpdCB3aXRoIEVwaWNlbnRlci1zcGVjaWZpYyBkZWZhdWx0cy4gSWYgeW91IGFyZSBpbnRlcmVzdGVkIGluIGluY2x1ZGluZyBhIG5vdGlmaWNhdGlvbiBvciBjaGF0IGZlYXR1cmUgaW4geW91ciBwcm9qZWN0LCB1c2luZyBhbiBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIHByb2JhYmx5IHRoZSBlYXNpZXN0IHdheSB0byBnZXQgc3RhcnRlZC5cbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyLiBTZWUgW0luY2x1ZGluZyBFcGljZW50ZXIuanNdKC4uLy4uLyNpbmNsdWRlKS5cbiAqXG4gKiBUbyB1c2UgdGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXI6IGluc3RhbnRpYXRlIGl0LCBnZXQgdGhlIGNoYW5uZWwgb2YgdGhlIHNjb3BlIHlvdSB3YW50IChbdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgW3dvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLCBvciBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpKSwgdGhlbiB1c2UgdGhlIGNoYW5uZWwncyBgc3Vic2NyaWJlKClgIGFuZCBgcHVibGlzaCgpYCBtZXRob2RzIHRvIHN1YnNjcmliZSB0byB0b3BpY3Mgb3IgcHVibGlzaCBkYXRhIHRvIHRvcGljcy5cbiAqXG4gKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICogICAgIHZhciBnYyA9IGNtLmdldEdyb3VwQ2hhbm5lbCgpO1xuICogICAgIGdjLnN1YnNjcmliZSgnYnJvYWRjYXN0cycsIGNhbGxiYWNrKTtcbiAqXG4gKiBGb3IgYWRkaXRpb25hbCBiYWNrZ3JvdW5kIG9uIEVwaWNlbnRlcidzIHB1c2ggY2hhbm5lbCwgc2VlIHRoZSBpbnRyb2R1Y3Rvcnkgbm90ZXMgb24gdGhlIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIHBhZ2UuXG4gKlxuICogVGhlIHBhcmFtZXRlcnMgZm9yIGluc3RhbnRpYXRpbmcgYW4gRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIE9iamVjdCB3aXRoIGRldGFpbHMgYWJvdXQgdGhlIEVwaWNlbnRlciBwcm9qZWN0IGZvciB0aGlzIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaW5zdGFuY2UuXG4gKiAqIGBvcHRpb25zLmFjY291bnRgIFRoZSBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gKiAqIGBvcHRpb25zLnByb2plY3RgIEVwaWNlbnRlciBwcm9qZWN0IGlkLlxuICogKiBgb3B0aW9ucy51c2VyTmFtZWAgRXBpY2VudGVyIHVzZXJOYW1lIHVzZWQgZm9yIGF1dGhlbnRpY2F0aW9uLlxuICogKiBgb3B0aW9ucy51c2VySWRgIEVwaWNlbnRlciB1c2VyIGlkIHVzZWQgZm9yIGF1dGhlbnRpY2F0aW9uLiBPcHRpb25hbDsgYG9wdGlvbnMudXNlck5hbWVgIGlzIHByZWZlcnJlZC5cbiAqICogYG9wdGlvbnMudG9rZW5gIEVwaWNlbnRlciB0b2tlbiB1c2VkIGZvciBhdXRoZW50aWNhdGlvbi4gKFlvdSBjYW4gcmV0cmlldmUgdGhpcyB1c2luZyBgYXV0aE1hbmFnZXIuZ2V0VG9rZW4oKWAgZnJvbSB0aGUgW0F1dGhvcml6YXRpb24gTWFuYWdlcl0oLi4vYXV0aC1tYW5hZ2VyLykuKVxuICogKiBgb3B0aW9ucy5hbGxvd0FsbENoYW5uZWxzYCBJZiBub3QgaW5jbHVkZWQgb3IgaWYgc2V0IHRvIGBmYWxzZWAsIGFsbCBjaGFubmVsIHBhdGhzIGFyZSB2YWxpZGF0ZWQ7IGlmIHlvdXIgcHJvamVjdCByZXF1aXJlcyBbUHVzaCBDaGFubmVsIEF1dGhvcml6YXRpb25dKC4uLy4uLy4uL3VwZGF0aW5nX3lvdXJfc2V0dGluZ3MvKSwgeW91IHNob3VsZCB1c2UgdGhpcyBvcHRpb24uIElmIHlvdSB3YW50IHRvIGFsbG93IG90aGVyIGNoYW5uZWwgcGF0aHMsIHNldCB0byBgdHJ1ZWA7IHRoaXMgaXMgbm90IGNvbW1vbi5cbiAqL1xuXG52YXIgQ2hhbm5lbE1hbmFnZXIgPSByZXF1aXJlKCcuL2NoYW5uZWwtbWFuYWdlcicpO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIHVybFNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3VybC1jb25maWctc2VydmljZScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG5cbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciB2YWxpZFR5cGVzID0ge1xuICAgIHByb2plY3Q6IHRydWUsXG4gICAgZ3JvdXA6IHRydWUsXG4gICAgd29ybGQ6IHRydWUsXG4gICAgdXNlcjogdHJ1ZSxcbiAgICBkYXRhOiB0cnVlLFxuICAgIGdlbmVyYWw6IHRydWUsXG4gICAgY2hhdDogdHJ1ZVxufTtcbnZhciBzZXNzaW9uID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG52YXIgZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvciA9IGZ1bmN0aW9uICh2YWx1ZSwgc2Vzc2lvbktleU5hbWUsIHNldHRpbmdzKSB7XG4gICAgaWYgKCF2YWx1ZSkge1xuICAgICAgICB2YXIgdXNlckluZm8gPSBzZXNzaW9uLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgaWYgKHNldHRpbmdzICYmIHNldHRpbmdzW3Nlc3Npb25LZXlOYW1lXSkge1xuICAgICAgICAgICAgdmFsdWUgPSBzZXR0aW5nc1tzZXNzaW9uS2V5TmFtZV07XG4gICAgICAgIH0gZWxzZSBpZiAodXNlckluZm9bc2Vzc2lvbktleU5hbWVdKSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHVzZXJJbmZvW3Nlc3Npb25LZXlOYW1lXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihzZXNzaW9uS2V5TmFtZSArICcgbm90IGZvdW5kLiBQbGVhc2UgbG9nLWluIGFnYWluLCBvciBzcGVjaWZ5ICcgKyBzZXNzaW9uS2V5TmFtZSArICcgZXhwbGljaXRseScpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZTtcbn07XG52YXIgX19zdXBlciA9IENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZTtcbnZhciBFcGljZW50ZXJDaGFubmVsTWFuYWdlciA9IGNsYXNzRnJvbShDaGFubmVsTWFuYWdlciwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG4gICAgICAgIHZhciBkZWZhdWx0Q29tZXRPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciB1cmxPcHRzID0gdXJsU2VydmljZShkZWZhdWx0Q29tZXRPcHRpb25zLnNlcnZlcik7XG4gICAgICAgIGlmICghZGVmYXVsdENvbWV0T3B0aW9ucy51cmwpIHtcbiAgICAgICAgICAgIC8vRGVmYXVsdCBlcGljZW50ZXIgY29tZXRkIGVuZHBvaW50XG4gICAgICAgICAgICBkZWZhdWx0Q29tZXRPcHRpb25zLnVybCA9IHVybE9wdHMucHJvdG9jb2wgKyAnOi8vJyArIHVybE9wdHMuaG9zdCArICcvY2hhbm5lbC9zdWJzY3JpYmUnO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGRlZmF1bHRDb21ldE9wdGlvbnMuaGFuZHNoYWtlID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHZhciB1c2VyTmFtZSA9IGRlZmF1bHRDb21ldE9wdGlvbnMudXNlck5hbWU7XG4gICAgICAgICAgICB2YXIgdXNlcklkID0gZGVmYXVsdENvbWV0T3B0aW9ucy51c2VySWQ7XG4gICAgICAgICAgICB2YXIgdG9rZW4gPSBkZWZhdWx0Q29tZXRPcHRpb25zLnRva2VuO1xuICAgICAgICAgICAgaWYgKCh1c2VyTmFtZSB8fCB1c2VySWQpICYmIHRva2VuKSB7XG4gICAgICAgICAgICAgICAgdmFyIHVzZXJQcm9wID0gdXNlck5hbWUgPyAndXNlck5hbWUnIDogJ3VzZXJJZCc7XG4gICAgICAgICAgICAgICAgdmFyIGV4dCA9IHtcbiAgICAgICAgICAgICAgICAgICAgYXV0aG9yaXphdGlvbjogJ0JlYXJlciAnICsgdG9rZW5cbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIGV4dFt1c2VyUHJvcF0gPSB1c2VyTmFtZSA/IHVzZXJOYW1lIDogdXNlcklkO1xuXG4gICAgICAgICAgICAgICAgZGVmYXVsdENvbWV0T3B0aW9ucy5oYW5kc2hha2UgPSB7XG4gICAgICAgICAgICAgICAgICAgIGV4dDogZXh0XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMub3B0aW9ucyA9IGRlZmF1bHRDb21ldE9wdGlvbnM7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgZGVmYXVsdENvbWV0T3B0aW9ucyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW5kIHJldHVybnMgYSBjaGFubmVsLCB0aGF0IGlzLCBhbiBpbnN0YW5jZSBvZiBhIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pLlxuICAgICAqXG4gICAgICogVGhpcyBtZXRob2QgZW5mb3JjZXMgRXBpY2VudGVyLXNwZWNpZmljIGNoYW5uZWwgbmFtaW5nOiBhbGwgY2hhbm5lbHMgcmVxdWVzdGVkIG11c3QgYmUgaW4gdGhlIGZvcm0gYC97dHlwZX0ve2FjY291bnQgaWR9L3twcm9qZWN0IGlkfS97Li4ufWAsIHdoZXJlIGB0eXBlYCBpcyBvbmUgb2YgYHJ1bmAsIGBkYXRhYCwgYHVzZXJgLCBgd29ybGRgLCBvciBgY2hhdGAuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkVwaWNlbnRlckNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgICB2YXIgY2hhbm5lbCA9IGNtLmdldENoYW5uZWwoJy9ncm91cC9hY21lL3N1cHBseS1jaGFpbi1nYW1lLycpO1xuICAgICAqXG4gICAgICogICAgICBjaGFubmVsLnN1YnNjcmliZSgndG9waWMnLCBjYWxsYmFjayk7XG4gICAgICogICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBJZiBzdHJpbmcsIGFzc3VtZWQgdG8gYmUgdGhlIGJhc2UgY2hhbm5lbCB1cmwuIElmIG9iamVjdCwgYXNzdW1lZCB0byBiZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjb25zdHJ1Y3Rvci5cbiAgICAgKi9cbiAgICBnZXRDaGFubmVsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICBpZiAob3B0aW9ucyAmJiB0eXBlb2Ygb3B0aW9ucyAhPT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSB7XG4gICAgICAgICAgICAgICAgYmFzZTogb3B0aW9uc1xuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgY2hhbm5lbE9wdHMgPSAkLmV4dGVuZCh7fSwgdGhpcy5vcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyIGJhc2UgPSBjaGFubmVsT3B0cy5iYXNlO1xuICAgICAgICBpZiAoIWJhc2UpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gYmFzZSB0b3BpYyB3YXMgcHJvdmlkZWQnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghY2hhbm5lbE9wdHMuYWxsb3dBbGxDaGFubmVscykge1xuICAgICAgICAgICAgdmFyIGJhc2VQYXJ0cyA9IGJhc2Uuc3BsaXQoJy8nKTtcbiAgICAgICAgICAgIHZhciBjaGFubmVsVHlwZSA9IGJhc2VQYXJ0c1sxXTtcbiAgICAgICAgICAgIGlmIChiYXNlUGFydHMubGVuZ3RoIDwgNCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBjaGFubmVsIGJhc2UgbmFtZSwgaXQgbXVzdCBiZSBpbiB0aGUgZm9ybSAve3R5cGV9L3thY2NvdW50IGlkfS97cHJvamVjdCBpZH0vey4uLn0nKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghdmFsaWRUeXBlc1tjaGFubmVsVHlwZV0pIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgY2hhbm5lbCB0eXBlJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgZ2l2ZW4gW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS4gVGhlIGdyb3VwIG11c3QgZXhpc3QgaW4gdGhlIGFjY291bnQgKHRlYW0pIGFuZCBwcm9qZWN0IHByb3ZpZGVkLlxuICAgICAqXG4gICAgICogVGhlcmUgYXJlIG5vIG5vdGlmaWNhdGlvbnMgZnJvbSBFcGljZW50ZXIgb24gdGhpcyBjaGFubmVsOyBhbGwgbWVzc2FnZXMgYXJlIHVzZXItb3JpZ2luYXRlZC5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgZ2MgPSBjbS5nZXRHcm91cENoYW5uZWwoKTtcbiAgICAgKiAgICAgZ2Muc3Vic2NyaWJlKCdicm9hZGNhc3RzJywgY2FsbGJhY2spO1xuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGBncm91cE5hbWVgIChPcHRpb25hbCkgR3JvdXAgdG8gYnJvYWRjYXN0IHRvLiBJZiBub3QgcHJvdmlkZWQsIHBpY2tzIHVwIGdyb3VwIGZyb20gY3VycmVudCBzZXNzaW9uIGlmIGVuZCB1c2VyIGlzIGxvZ2dlZCBpbi5cbiAgICAgKi9cbiAgICBnZXRHcm91cENoYW5uZWw6IGZ1bmN0aW9uIChncm91cE5hbWUpIHtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcihncm91cE5hbWUsICdncm91cE5hbWUnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2dyb3VwJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lXS5qb2luKCcvJyk7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIFt3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS5cbiAgICAgKlxuICAgICAqIFRoaXMgaXMgdHlwaWNhbGx5IHVzZWQgdG9nZXRoZXIgd2l0aCB0aGUgW1dvcmxkIE1hbmFnZXJdKC4uL3dvcmxkLW1hbmFnZXIpLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciB3b3JsZE1hbmFnZXIgPSBuZXcgRi5tYW5hZ2VyLldvcmxkTWFuYWdlcih7XG4gICAgICogICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICogICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAqICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gICAgICogICAgICAgICBydW46IHsgbW9kZWw6ICdtb2RlbC5lcW4nIH1cbiAgICAgKiAgICAgfSk7XG4gICAgICogICAgIHdvcmxkTWFuYWdlci5nZXRDdXJyZW50V29ybGQoKS50aGVuKGZ1bmN0aW9uICh3b3JsZE9iamVjdCwgd29ybGRBZGFwdGVyKSB7XG4gICAgICogICAgICAgICB2YXIgd29ybGRDaGFubmVsID0gY20uZ2V0V29ybGRDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHdvcmxkQ2hhbm5lbC5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICogICAgICAgICAgICAgY29uc29sZS5sb2coZGF0YSk7XG4gICAgICogICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSBgd29ybGRgIFRoZSB3b3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFdvcmxkQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCBncm91cE5hbWUpIHtcbiAgICAgICAgdmFyIHdvcmxkaWQgPSAoJC5pc1BsYWluT2JqZWN0KHdvcmxkKSAmJiB3b3JsZC5pZCkgPyB3b3JsZC5pZCA6IHdvcmxkO1xuICAgICAgICBpZiAoIXdvcmxkaWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHNwZWNpZnkgYSB3b3JsZCBpZCcpO1xuICAgICAgICB9XG4gICAgICAgIGdyb3VwTmFtZSA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIGFjY291bnQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAnYWNjb3VudCcsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIHZhciBwcm9qZWN0ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ3Byb2plY3QnLCB0aGlzLm9wdGlvbnMpO1xuXG4gICAgICAgIHZhciBiYXNlVG9waWMgPSBbJy93b3JsZCcsIGFjY291bnQsIHByb2plY3QsIGdyb3VwTmFtZSwgd29ybGRpZF0uam9pbignLycpO1xuICAgICAgICByZXR1cm4gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhbmQgcmV0dXJuIGEgcHVibGlzaC9zdWJzY3JpYmUgY2hhbm5lbCAoZnJvbSB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSkgZm9yIHRoZSBjdXJyZW50IFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSBpbiB0aGF0IHVzZXIncyBjdXJyZW50IFt3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS5cbiAgICAgKlxuICAgICAqIFRoaXMgaXMgdHlwaWNhbGx5IHVzZWQgdG9nZXRoZXIgd2l0aCB0aGUgW1dvcmxkIE1hbmFnZXJdKC4uL3dvcmxkLW1hbmFnZXIpLiBOb3RlIHRoYXQgdGhpcyBjaGFubmVsIG9ubHkgZ2V0cyBub3RpZmljYXRpb25zIGZvciB3b3JsZHMgY3VycmVudGx5IGluIG1lbW9yeS4gKFNlZSBtb3JlIGJhY2tncm91bmQgb24gW3BlcnNpc3RlbmNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UpLilcbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgd29ybGRNYW5hZ2VyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuICAgICAqICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAqICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgKiAgICAgICAgIGdyb3VwOiAndGVhbTEnLFxuICAgICAqICAgICAgICAgcnVuOiB7IG1vZGVsOiAnbW9kZWwuZXFuJyB9XG4gICAgICogICAgIH0pO1xuICAgICAqICAgICB3b3JsZE1hbmFnZXIuZ2V0Q3VycmVudFdvcmxkKCkudGhlbihmdW5jdGlvbiAod29ybGRPYmplY3QsIHdvcmxkQWRhcHRlcikge1xuICAgICAqICAgICAgICAgdmFyIHVzZXJDaGFubmVsID0gY20uZ2V0VXNlckNoYW5uZWwod29ybGRPYmplY3QpO1xuICAgICAqICAgICAgICAgdXNlckNoYW5uZWwuc3Vic2NyaWJlKCcnLCBmdW5jdGlvbiAoZGF0YSkge1xuICAgICAqICAgICAgICAgICAgIGNvbnNvbGUubG9nKGRhdGEpO1xuICAgICAqICAgICAgICAgfSk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSBgd29ybGRgIFdvcmxkIG9iamVjdCBvciBpZC5cbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSBgdXNlcmAgKE9wdGlvbmFsKSBVc2VyIG9iamVjdCBvciBpZC4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCB1c2VyIGlkIGZyb20gY3VycmVudCBzZXNzaW9uIGlmIGVuZCB1c2VyIGlzIGxvZ2dlZCBpbi5cbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGBncm91cE5hbWVgIChPcHRpb25hbCkgR3JvdXAgdGhlIHdvcmxkIGV4aXN0cyBpbi4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCBncm91cCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICovXG4gICAgZ2V0VXNlckNoYW5uZWw6IGZ1bmN0aW9uICh3b3JsZCwgdXNlciwgZ3JvdXBOYW1lKSB7XG4gICAgICAgIHZhciB3b3JsZGlkID0gKCQuaXNQbGFpbk9iamVjdCh3b3JsZCkgJiYgd29ybGQuaWQpID8gd29ybGQuaWQgOiB3b3JsZDtcbiAgICAgICAgaWYgKCF3b3JsZGlkKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBzcGVjaWZ5IGEgd29ybGQgaWQnKTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgdXNlcmlkID0gKCQuaXNQbGFpbk9iamVjdCh1c2VyKSAmJiB1c2VyLmlkKSA/IHVzZXIuaWQgOiB1c2VyO1xuICAgICAgICB1c2VyaWQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKHVzZXJpZCwgJ3VzZXJJZCcsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIGdyb3VwTmFtZSA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3VzZXInLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWUsIHdvcmxkaWQsIHVzZXJpZF0uam9pbignLycpO1xuICAgICAgICByZXR1cm4gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhbmQgcmV0dXJuIGEgcHVibGlzaC9zdWJzY3JpYmUgY2hhbm5lbCAoZnJvbSB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSkgdGhhdCBhdXRvbWF0aWNhbGx5IHRyYWNrcyB0aGUgcHJlc2VuY2Ugb2YgYW4gW2VuZCB1c2VyXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpLCB0aGF0IGlzLCB3aGV0aGVyIHRoZSBlbmQgdXNlciBpcyBjdXJyZW50bHkgb25saW5lIGluIHRoaXMgZ3JvdXAgYW5kIHdvcmxkLiBOb3RpZmljYXRpb25zIGFyZSBhdXRvbWF0aWNhbGx5IHNlbnQgd2hlbiB0aGUgZW5kIHVzZXIgY29tZXMgb25saW5lLCBhbmQgd2hlbiB0aGUgZW5kIHVzZXIgZ29lcyBvZmZsaW5lIChub3QgcHJlc2VudCBmb3IgbW9yZSB0aGFuIDIgbWludXRlcykuIFVzZWZ1bCBpbiBtdWx0aXBsYXllciBnYW1lcyBmb3IgbGV0dGluZyBlYWNoIGVuZCB1c2VyIGtub3cgd2hldGhlciBvdGhlciB1c2VycyBpbiB0aGVpciBzaGFyZWQgd29ybGQgYXJlIGFsc28gb25saW5lLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciB3b3JsZE1hbmFnZXIgPSBuZXcgRi5tYW5hZ2VyLldvcmxkTWFuYWdlcih7XG4gICAgICogICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICogICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAqICAgICAgICAgbW9kZWw6ICdtb2RlbC5lcW4nXG4gICAgICogICAgIH0pO1xuICAgICAqICAgICB3b3JsZE1hbmFnZXIuZ2V0Q3VycmVudFdvcmxkKCkudGhlbihmdW5jdGlvbiAod29ybGRPYmplY3QsIHdvcmxkU2VydmljZSkge1xuICAgICAqICAgICAgICAgdmFyIHByZXNlbmNlQ2hhbm5lbCA9IGNtLmdldFByZXNlbmNlQ2hhbm5lbCh3b3JsZE9iamVjdCk7XG4gICAgICogICAgICAgICBwcmVzZW5jZUNoYW5uZWwub24oJ3ByZXNlbmNlJywgZnVuY3Rpb24gKGV2dCwgbm90aWZpY2F0aW9uKSB7XG4gICAgICogICAgICAgICAgICAgIGNvbnNvbGUubG9nKG5vdGlmaWNhdGlvbi5vbmxpbmUsIG5vdGlmaWNhdGlvbi51c2VySWQpO1xuICAgICAqICAgICAgICAgIH0pO1xuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHdvcmxkYCBXb3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHVzZXJpZGAgKE9wdGlvbmFsKSBVc2VyIG9iamVjdCBvciBpZC4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCB1c2VyIGlkIGZyb20gY3VycmVudCBzZXNzaW9uIGlmIGVuZCB1c2VyIGlzIGxvZ2dlZCBpbi5cbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGBncm91cE5hbWVgIChPcHRpb25hbCkgR3JvdXAgdGhlIHdvcmxkIGV4aXN0cyBpbi4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCBncm91cCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICovXG4gICAgZ2V0UHJlc2VuY2VDaGFubmVsOiBmdW5jdGlvbiAod29ybGQsIHVzZXJpZCwgZ3JvdXBOYW1lKSB7XG4gICAgICAgIHZhciB3b3JsZGlkID0gKCQuaXNQbGFpbk9iamVjdCh3b3JsZCkgJiYgd29ybGQuaWQpID8gd29ybGQuaWQgOiB3b3JsZDtcbiAgICAgICAgaWYgKCF3b3JsZGlkKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBzcGVjaWZ5IGEgd29ybGQgaWQnKTtcbiAgICAgICAgfVxuICAgICAgICB1c2VyaWQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKHVzZXJpZCwgJ3VzZXJJZCcsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIGdyb3VwTmFtZSA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3VzZXInLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWUsIHdvcmxkaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgdmFyIGNoYW5uZWwgPSBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcblxuICAgICAgICB2YXIgbGFzdFBpbmdUaW1lID0geyB9O1xuXG4gICAgICAgIHZhciBQSU5HX0lOVEVSVkFMID0gNjAwMDtcbiAgICAgICAgY2hhbm5lbC5zdWJzY3JpYmUoJ2ludGVybmFsLXBpbmctY2hhbm5lbCcsIGZ1bmN0aW9uIChub3RpZmljYXRpb24pIHtcbiAgICAgICAgICAgIHZhciBpbmNvbWluZ1VzZXJJZCA9IG5vdGlmaWNhdGlvbi5kYXRhLnVzZXI7XG4gICAgICAgICAgICBpZiAoIWxhc3RQaW5nVGltZVtpbmNvbWluZ1VzZXJJZF0gJiYgaW5jb21pbmdVc2VySWQgIT09IHVzZXJpZCkge1xuICAgICAgICAgICAgICAgIGNoYW5uZWwudHJpZ2dlci5jYWxsKGNoYW5uZWwsICdwcmVzZW5jZScsIHsgdXNlcklkOiBpbmNvbWluZ1VzZXJJZCwgb25saW5lOiB0cnVlIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbGFzdFBpbmdUaW1lW2luY29taW5nVXNlcklkXSA9IChuZXcgRGF0ZSgpKS52YWx1ZU9mKCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHNldEludGVydmFsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGNoYW5uZWwucHVibGlzaCgnaW50ZXJuYWwtcGluZy1jaGFubmVsJywgeyB1c2VyOiB1c2VyaWQgfSk7XG5cbiAgICAgICAgICAgICQuZWFjaChsYXN0UGluZ1RpbWUsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgdmFyIG5vdyA9IChuZXcgRGF0ZSgpKS52YWx1ZU9mKCk7XG4gICAgICAgICAgICAgICAgaWYgKHZhbHVlICYmIHZhbHVlICsgKFBJTkdfSU5URVJWQUwgKiAyKSA8IG5vdykge1xuICAgICAgICAgICAgICAgICAgICBsYXN0UGluZ1RpbWVba2V5XSA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIGNoYW5uZWwudHJpZ2dlci5jYWxsKGNoYW5uZWwsICdwcmVzZW5jZScsIHsgdXNlcklkOiBrZXksIG9ubGluZTogZmFsc2UgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sIFBJTkdfSU5URVJWQUwpO1xuXG4gICAgICAgIHJldHVybiBjaGFubmVsO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgZ2l2ZW4gY29sbGVjdGlvbi4gKFRoZSBjb2xsZWN0aW9uIG5hbWUgaXMgc3BlY2lmaWVkIGluIHRoZSBgcm9vdGAgYXJndW1lbnQgd2hlbiB0aGUgW0RhdGEgU2VydmljZV0oLi4vZGF0YS1hcGktc2VydmljZS8pIGlzIGluc3RhbnRpYXRlZC4pIE11c3QgYmUgb25lIG9mIHRoZSBjb2xsZWN0aW9ucyBpbiB0aGlzIGFjY291bnQgKHRlYW0pIGFuZCBwcm9qZWN0LlxuICAgICAqXG4gICAgICogVGhlcmUgYXJlIGF1dG9tYXRpYyBub3RpZmljYXRpb25zIGZyb20gRXBpY2VudGVyIG9uIHRoaXMgY2hhbm5lbCB3aGVuIGRhdGEgaXMgY3JlYXRlZCwgdXBkYXRlZCwgb3IgZGVsZXRlZCBpbiB0aGlzIGNvbGxlY3Rpb24uIFNlZSBtb3JlIG9uIFthdXRvbWF0aWMgbWVzc2FnZXMgdG8gdGhlIGRhdGEgY2hhbm5lbF0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL2NoYW5uZWwvI2RhdGEtbWVzc2FnZXMpLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciBkYyA9IGNtLmdldERhdGFDaGFubmVsKCdzdXJ2ZXktcmVzcG9uc2VzJyk7XG4gICAgICogICAgIGRjLnN1YnNjcmliZSgnJywgZnVuY3Rpb24oZGF0YSwgbWV0YSkge1xuICAgICAqICAgICAgICAgIGNvbnNvbGUubG9nKGRhdGEpO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gbWV0YS5kYXRlIGlzIHRpbWUgb2YgY2hhbmdlLFxuICAgICAqICAgICAgICAgIC8vIG1ldGEuc3ViVHlwZSBpcyB0aGUga2luZCBvZiBjaGFuZ2U6IG5ldywgdXBkYXRlLCBvciBkZWxldGVcbiAgICAgKiAgICAgICAgICAvLyBtZXRhLnBhdGggaXMgdGhlIGZ1bGwgcGF0aCB0byB0aGUgY2hhbmdlZCBkYXRhXG4gICAgICogICAgICAgICAgY29uc29sZS5sb2cobWV0YSk7XG4gICAgICogICAgIH0pO1xuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGBjb2xsZWN0aW9uYCBOYW1lIG9mIGNvbGxlY3Rpb24gd2hvc2UgYXV0b21hdGljIG5vdGlmaWNhdGlvbnMgeW91IHdhbnQgdG8gcmVjZWl2ZS5cbiAgICAgKi9cbiAgICBnZXREYXRhQ2hhbm5lbDogZnVuY3Rpb24gKGNvbGxlY3Rpb24pIHtcbiAgICAgICAgaWYgKCFjb2xsZWN0aW9uKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBzcGVjaWZ5IGEgY29sbGVjdGlvbiB0byBsaXN0ZW4gb24uJyk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGFjY291bnQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAnYWNjb3VudCcsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIHZhciBwcm9qZWN0ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ3Byb2plY3QnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvZGF0YScsIGFjY291bnQsIHByb2plY3QsIGNvbGxlY3Rpb25dLmpvaW4oJy8nKTtcbiAgICAgICAgdmFyIGNoYW5uZWwgPSBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcblxuICAgICAgICAvL1RPRE86IEZpeCBhZnRlciBFcGljZW50ZXIgYnVnIGlzIHJlc29sdmVkXG4gICAgICAgIHZhciBvbGRzdWJzID0gY2hhbm5lbC5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlID0gZnVuY3Rpb24gKHRvcGljLCBjYWxsYmFjaywgY29udGV4dCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNhbGxiYWNrV2l0aENsZWFuRGF0YSA9IGZ1bmN0aW9uIChwYXlsb2FkKSB7XG4gICAgICAgICAgICAgICAgdmFyIG1ldGEgPSB7XG4gICAgICAgICAgICAgICAgICAgIHBhdGg6IHBheWxvYWQuY2hhbm5lbCxcbiAgICAgICAgICAgICAgICAgICAgc3ViVHlwZTogcGF5bG9hZC5kYXRhLnN1YlR5cGUsXG4gICAgICAgICAgICAgICAgICAgIGRhdGU6IHBheWxvYWQuZGF0YS5kYXRlXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB2YXIgYWN0dWFsRGF0YSA9IHBheWxvYWQuZGF0YS5kYXRhO1xuICAgICAgICAgICAgICAgIGlmIChhY3R1YWxEYXRhLmRhdGEpIHsgLy9EZWxldGUgbm90aWZpY2F0aW9ucyBhcmUgb25lIGRhdGEtbGV2ZWwgYmVoaW5kIG9mIGNvdXJzZVxuICAgICAgICAgICAgICAgICAgICBhY3R1YWxEYXRhID0gYWN0dWFsRGF0YS5kYXRhO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGNhbGxiYWNrLmNhbGwoY29udGV4dCwgYWN0dWFsRGF0YSwgbWV0YSk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgcmV0dXJuIG9sZHN1YnMuY2FsbChjaGFubmVsLCB0b3BpYywgY2FsbGJhY2tXaXRoQ2xlYW5EYXRhLCBjb250ZXh0LCBvcHRpb25zKTtcbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gY2hhbm5lbDtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBFcGljZW50ZXJDaGFubmVsTWFuYWdlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgRVBJX1NFU1NJT05fS0VZOiAnZXBpY2VudGVyanMuc2Vzc2lvbicsXG4gICAgU1RSQVRFR1lfU0VTU0lPTl9LRVk6ICdlcGljZW50ZXItc2NlbmFyaW8nXG59OyIsIi8qKlxuKiAjIyBSdW4gTWFuYWdlclxuKlxuKiBUaGUgUnVuIE1hbmFnZXIgZ2l2ZXMgeW91IGFjY2VzcyB0byBydW5zIGZvciB5b3VyIHByb2plY3QuIFRoaXMgYWxsb3dzIHlvdSB0byByZWFkIGFuZCB1cGRhdGUgdmFyaWFibGVzLCBjYWxsIG9wZXJhdGlvbnMsIGV0Yy4gQWRkaXRpb25hbGx5LCB0aGUgUnVuIE1hbmFnZXIgZ2l2ZXMgeW91IGNvbnRyb2wgb3ZlciBydW4gY3JlYXRpb24gZGVwZW5kaW5nIG9uIHJ1biBzdGF0ZXMuIFNwZWNpZmljYWxseSwgeW91IGNhbiBzZWxlY3QgW3J1biBjcmVhdGlvbiBzdHJhdGVnaWVzIChydWxlcyldKC4uLy4uL3N0cmF0ZWd5LykgZm9yIHdoaWNoIHJ1bnMgZW5kIHVzZXJzIG9mIHlvdXIgcHJvamVjdCB3b3JrIHdpdGggd2hlbiB0aGV5IGxvZyBpbiB0byB5b3VyIHByb2plY3QuXG4qXG4qIFRoZXJlIGFyZSBtYW55IHdheXMgdG8gY3JlYXRlIG5ldyBydW5zLCBpbmNsdWRpbmcgdGhlIEVwaWNlbnRlci5qcyBbUnVuIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLCB0aGUgUkVTRlRmdWwgW1J1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9hZ2dyZWdhdGVfcnVuX2FwaSkgYW5kIHRoZSBbTW9kZWwgUnVuIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL290aGVyX2FwaXMvbW9kZWxfYXBpcy9ydW4vKS4gSG93ZXZlciwgZm9yIHNvbWUgcHJvamVjdHMgaXQgbWFrZXMgbW9yZSBzZW5zZSB0byBwaWNrIHVwIHdoZXJlIHRoZSB1c2VyIGxlZnQgb2ZmLCB1c2luZyBhbiBleGlzdGluZyBydW4uIEFuZCBpbiBzb21lIHByb2plY3RzLCB3aGV0aGVyIHRvIGNyZWF0ZSBhIG5ldyBydW4gb3IgdXNlIGFuIGV4aXN0aW5nIG9uZSBpcyBjb25kaXRpb25hbCwgZm9yIGV4YW1wbGUgYmFzZWQgb24gY2hhcmFjdGVyaXN0aWNzIG9mIHRoZSBleGlzdGluZyBydW4gb3IgeW91ciBvd24ga25vd2xlZGdlIGFib3V0IHRoZSBtb2RlbC4gVGhlIFJ1biBNYW5hZ2VyIHByb3ZpZGVzIHRoaXMgbGV2ZWwgb2YgY29udHJvbDogeW91ciBjYWxsIHRvIGBnZXRSdW4oKWAsIHJhdGhlciB0aGFuIGFsd2F5cyByZXR1cm5pbmcgYSBuZXcgcnVuLCByZXR1cm5zIGEgcnVuIGJhc2VkIG9uIHRoZSBzdHJhdGVneSB5b3UndmUgc3BlY2lmaWVkLiAoTm90ZSB0aGF0IG1hbnkgb2YgdGhlIEVwaWNlbnRlciBzYW1wbGUgcHJvamVjdHMgdXNlIGEgUnVuIFNlcnZpY2UgZGlyZWN0bHksIGJlY2F1c2UgZ2VuZXJhbGx5IHRoZSBzYW1wbGUgcHJvamVjdHMgYXJlIHBsYXllZCBpbiBvbmUgZW5kIHVzZXIgc2Vzc2lvbiBhbmQgZG9uJ3QgY2FyZSBhYm91dCBydW4gc3RhdGVzIG9yIHJ1biBzdHJhdGVnaWVzLilcbipcbipcbiogIyMjIFVzaW5nIHRoZSBSdW4gTWFuYWdlciB0byBjcmVhdGUgYW5kIGFjY2VzcyBydW5zXG4qXG4qIFRvIHVzZSB0aGUgUnVuIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0IGJ5IHBhc3NpbmcgaW46XG4qXG4qICAgKiBgcnVuYDogKHJlcXVpcmVkKSBSdW4gb2JqZWN0LiBNdXN0IGNvbnRhaW46XG4qICAgICAgICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4qICAgICAgICogYHByb2plY3RgOiBFcGljZW50ZXIgcHJvamVjdCBpZC5cbiogICAgICAgKiBgbW9kZWxgOiBUaGUgbmFtZSBvZiB5b3VyIHByaW1hcnkgbW9kZWwgZmlsZS4gKFNlZSBtb3JlIG9uIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pLilcbiogICAgICAgKiBgc2NvcGVgOiAob3B0aW9uYWwpIFNjb3BlIG9iamVjdCBmb3IgdGhlIHJ1biwgZm9yIGV4YW1wbGUgYHNjb3BlLmdyb3VwYCB3aXRoIHZhbHVlIG9mIHRoZSBuYW1lIG9mIHRoZSBncm91cC5cbiogICAgICAgKiBgc2VydmVyYDogKG9wdGlvbmFsKSBBbiBvYmplY3Qgd2l0aCBvbmUgZmllbGQsIGBob3N0YC4gVGhlIHZhbHVlIG9mIGBob3N0YCBpcyB0aGUgc3RyaW5nIGBhcGkuZm9yaW8uY29tYCwgdGhlIFVSSSBvZiB0aGUgRm9yaW8gc2VydmVyLiBUaGlzIGlzIGF1dG9tYXRpY2FsbHkgc2V0LCBidXQgeW91IGNhbiBwYXNzIGl0IGV4cGxpY2l0bHkgaWYgZGVzaXJlZC4gSXQgaXMgbW9zdCBjb21tb25seSB1c2VkIGZvciBjbGFyaXR5IHdoZW4geW91IGFyZSBbaG9zdGluZyBhbiBFcGljZW50ZXIgcHJvamVjdCBvbiB5b3VyIG93biBzZXJ2ZXJdKC4uLy4uLy4uL2hvd190by9zZWxmX2hvc3RpbmcvKS5cbiogICAgICAgKiBgZmlsZXNgOiAob3B0aW9uYWwpIElmIGFuZCBvbmx5IGlmIHlvdSBhcmUgdXNpbmcgYSBWZW5zaW0gbW9kZWwgYW5kIHlvdSBoYXZlIGFkZGl0aW9uYWwgZGF0YSB0byBwYXNzIGluIHRvIHlvdXIgbW9kZWwsIHlvdSBjYW4gcGFzcyBhIGBmaWxlc2Agb2JqZWN0IHdpdGggdGhlIG5hbWVzIG9mIHRoZSBmaWxlcywgZm9yIGV4YW1wbGU6IGBcImZpbGVzXCI6IHtcImRhdGFcIjogXCJteUV4dHJhRGF0YS54bHNcIn1gLiAoTm90ZSB0aGF0IHlvdSdsbCBhbHNvIG5lZWQgdG8gYWRkIHRoaXMgc2FtZSBmaWxlcyBvYmplY3QgdG8geW91ciBWZW5zaW0gW2NvbmZpZ3VyYXRpb24gZmlsZV0oLi4vLi4vLi4vbW9kZWxfY29kZS92ZW5zaW0vKS4pIFNlZSB0aGUgW3VuZGVybHlpbmcgTW9kZWwgUnVuIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL290aGVyX2FwaXMvbW9kZWxfYXBpcy9ydW4vI3Bvc3QtY3JlYXRpbmctYS1uZXctcnVuLWZvci10aGlzLXByb2plY3QpIGZvciBhZGRpdGlvbmFsIGluZm9ybWF0aW9uLlxuKlxuKiAgICogYHN0cmF0ZWd5YDogKG9wdGlvbmFsKSBSdW4gY3JlYXRpb24gc3RyYXRlZ3kgZm9yIHdoZW4gdG8gY3JlYXRlIGEgbmV3IHJ1biBhbmQgd2hlbiB0byByZXVzZSBhbiBlbmQgdXNlcidzIGV4aXN0aW5nIHJ1bi4gU2VlIFtSdW4gTWFuYWdlciBTdHJhdGVnaWVzXSguLi8uLi9zdHJhdGVneS8pIGZvciBkZXRhaWxzLiBEZWZhdWx0cyB0byBgbmV3LWlmLWluaXRpYWxpemVkYC5cbipcbiogICAqIGBzZXNzaW9uS2V5YDogKG9wdGlvbmFsKSBOYW1lIG9mIGJyb3dzZXIgY29va2llIGluIHdoaWNoIHRvIHN0b3JlIHJ1biBpbmZvcm1hdGlvbiwgaW5jbHVkaW5nIHJ1biBpZC4gTWFueSBjb25kaXRpb25hbCBzdHJhdGVnaWVzLCBpbmNsdWRpbmcgdGhlIHByb3ZpZGVkIHN0cmF0ZWdpZXMsIHJlbHkgb24gdGhpcyBicm93c2VyIGNvb2tpZSB0byBzdG9yZSB0aGUgcnVuIGlkIGFuZCBoZWxwIG1ha2UgdGhlIGRlY2lzaW9uIG9mIHdoZXRoZXIgdG8gY3JlYXRlIGEgbmV3IHJ1biBvciB1c2UgYW4gZXhpc3Rpbmcgb25lLiBUaGUgbmFtZSBvZiB0aGlzIGNvb2tpZSBkZWZhdWx0cyB0byBgZXBpY2VudGVyLXNjZW5hcmlvYCBhbmQgY2FuIGJlIHNldCB3aXRoIHRoZSBgc2Vzc2lvbktleWAgcGFyYW1ldGVyLlxuKlxuKlxuKiBBZnRlciBpbnN0YW50aWF0aW5nIGEgUnVuIE1hbmFnZXIsIG1ha2UgYSBjYWxsIHRvIGBnZXRSdW4oKWAgd2hlbmV2ZXIgeW91IG5lZWQgdG8gYWNjZXNzIGEgcnVuIGZvciB0aGlzIGVuZCB1c2VyLiBUaGUgYFJ1bk1hbmFnZXIucnVuYCBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFtSdW4gU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykuIFRoZSBSdW4gU2VydmljZSBhbGxvd3MgeW91IHRvIGFjY2VzcyB2YXJpYWJsZXMsIGNhbGwgb3BlcmF0aW9ucywgZXRjLlxuKlxuKiAqKkV4YW1wbGUqKlxuKlxuKiAgICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuKiAgICAgICAgICAgcnVuOiB7XG4qICAgICAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4qICAgICAgICAgICAgICAgbW9kZWw6ICdzdXBwbHktY2hhaW4tbW9kZWwuamwnLFxuKiAgICAgICAgICAgICAgIHNlcnZlcjogeyBob3N0OiAnYXBpLmZvcmlvLmNvbScgfVxuKiAgICAgICAgICAgfSxcbiogICAgICAgICAgIHN0cmF0ZWd5OiAnYWx3YXlzLW5ldycsXG4qICAgICAgICAgICBzZXNzaW9uS2V5OiAnZXBpY2VudGVyLXNlc3Npb24nXG4qICAgICAgIH0pO1xuKiAgICAgICBybS5nZXRSdW4oKVxuKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24ocnVuKSB7XG4qICAgICAgICAgICAgICAgLy8gdGhlIHJldHVybiB2YWx1ZSBvZiBnZXRSdW4oKSBpcyBhIHJ1biBvYmplY3RcbiogICAgICAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuKiAgICAgICAgICAgICAgIC8vIHRoZSBSdW5NYW5hZ2VyLnJ1biBhbHNvIGNvbnRhaW5zIHRoZSBpbnN0YW50aWF0ZWQgUnVuIFNlcnZpY2UsXG4qICAgICAgICAgICAgICAgLy8gc28gYW55IFJ1biBTZXJ2aWNlIG1ldGhvZCBpcyB2YWxpZCBoZXJlXG4qICAgICAgICAgICAgICAgcm0ucnVuLmRvKCdydW5Nb2RlbCcpO1xuKiAgICAgICB9KVxuKlxuKi9cblxuJ3VzZSBzdHJpY3QnO1xudmFyIHN0cmF0ZWdpZXNNYXAgPSByZXF1aXJlKCcuL3J1bi1zdHJhdGVnaWVzL3N0cmF0ZWdpZXMtbWFwJyk7XG52YXIgc3BlY2lhbE9wZXJhdGlvbnMgPSByZXF1aXJlKCcuL3NwZWNpYWwtb3BlcmF0aW9ucycpO1xudmFyIFJ1blNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuXG5cbmZ1bmN0aW9uIHBhdGNoUnVuU2VydmljZShzZXJ2aWNlLCBtYW5hZ2VyKSB7XG4gICAgaWYgKHNlcnZpY2UucGF0Y2hlZCkge1xuICAgICAgICByZXR1cm4gc2VydmljZTtcbiAgICB9XG5cbiAgICB2YXIgb3JpZyA9IHNlcnZpY2UuZG87XG4gICAgc2VydmljZS5kbyA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICB2YXIgcmVzZXJ2ZWRPcHMgPSBPYmplY3Qua2V5cyhzcGVjaWFsT3BlcmF0aW9ucyk7XG4gICAgICAgIGlmIChyZXNlcnZlZE9wcy5pbmRleE9mKG9wZXJhdGlvbikgPT09IC0xKSB7XG4gICAgICAgICAgICByZXR1cm4gb3JpZy5hcHBseShzZXJ2aWNlLCBhcmd1bWVudHMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHNwZWNpYWxPcGVyYXRpb25zW29wZXJhdGlvbl0uY2FsbChzZXJ2aWNlLCBwYXJhbXMsIG9wdGlvbnMsIG1hbmFnZXIpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHNlcnZpY2UucGF0Y2hlZCA9IHRydWU7XG5cbiAgICByZXR1cm4gc2VydmljZTtcbn1cblxuXG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgICAvKipcbiAgICAgKiBSdW4gY3JlYXRpb24gc3RyYXRlZ3kgZm9yIHdoZW4gdG8gY3JlYXRlIGEgbmV3IHJ1biBhbmQgd2hlbiB0byByZXVzZSBhbiBlbmQgdXNlcidzIGV4aXN0aW5nIHJ1bi4gU2VlIFtSdW4gTWFuYWdlciBTdHJhdGVnaWVzXSguLi8uLi9zdHJhdGVneS8pIGZvciBkZXRhaWxzLiBEZWZhdWx0cyB0byBgbmV3LWlmLWluaXRpYWxpemVkYC5cbiAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAqL1xuXG4gICAgc3RyYXRlZ3k6ICduZXctaWYtaW5pdGlhbGl6ZWQnXG59O1xuXG5mdW5jdGlvbiBSdW5NYW5hZ2VyKG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuXG4gICAgaWYgKHRoaXMub3B0aW9ucy5ydW4gaW5zdGFuY2VvZiBSdW5TZXJ2aWNlKSB7XG4gICAgICAgIHRoaXMucnVuID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnJ1biA9IG5ldyBSdW5TZXJ2aWNlKHRoaXMub3B0aW9ucy5ydW4pO1xuICAgIH1cblxuICAgIHBhdGNoUnVuU2VydmljZSh0aGlzLnJ1biwgdGhpcyk7XG5cbiAgICB2YXIgU3RyYXRlZ3lDdG9yID0gdHlwZW9mIHRoaXMub3B0aW9ucy5zdHJhdGVneSA9PT0gJ2Z1bmN0aW9uJyA/IHRoaXMub3B0aW9ucy5zdHJhdGVneSA6IHN0cmF0ZWdpZXNNYXBbdGhpcy5vcHRpb25zLnN0cmF0ZWd5XTtcblxuICAgIGlmICghU3RyYXRlZ3lDdG9yKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignU3BlY2lmaWVkIHJ1biBjcmVhdGlvbiBzdHJhdGVneSB3YXMgaW52YWxpZDonLCB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kpO1xuICAgIH1cblxuICAgIHRoaXMuc3RyYXRlZ3kgPSBuZXcgU3RyYXRlZ3lDdG9yKHRoaXMucnVuLCB0aGlzLm9wdGlvbnMpO1xufVxuXG5SdW5NYW5hZ2VyLnByb3RvdHlwZSA9IHtcbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBydW4gb2JqZWN0IGZvciBhICdnb29kJyBydW4uXG4gICAgICpcbiAgICAgKiBBIGdvb2QgcnVuIGlzIGRlZmluZWQgYnkgdGhlIHN0cmF0ZWd5LiBGb3IgZXhhbXBsZSwgaWYgdGhlIHN0cmF0ZWd5IGlzIGBhbHdheXMtbmV3YCwgdGhlIGNhbGxcbiAgICAgKiB0byBgZ2V0UnVuKClgIGFsd2F5cyByZXR1cm5zIGEgbmV3bHkgY3JlYXRlZCBydW47IGlmIHRoZSBzdHJhdGVneSBpcyBgbmV3LWlmLXBlcnNpc3RlZGAsXG4gICAgICogYGdldFJ1bigpYCBjcmVhdGVzIGEgbmV3IHJ1biBpZiB0aGUgcHJldmlvdXMgcnVuIGlzIGluIGEgcGVyc2lzdGVkIHN0YXRlLCBvdGhlcndpc2VcbiAgICAgKiBpdCByZXR1cm5zIHRoZSBwcmV2aW91cyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgbW9yZSBvbiBzdHJhdGVnaWVzLlxuICAgICAqXG4gICAgICogICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIHJtLmdldFJ1bigpLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAqICAgICAgICAgIC8vIHVzZSB0aGUgcnVuIG9iamVjdFxuICAgICAqICAgICAgICAgIHZhciB0aGlzUnVuSWQgPSBydW4uaWQ7XG4gICAgICpcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIFJ1biBTZXJ2aWNlIG9iamVjdFxuICAgICAqICAgICAgICAgIHJtLnJ1bi5kbygncnVuTW9kZWwnKTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogQHJldHVybiB7JHByb21pc2V9IFByb21pc2UgdG8gY29tcGxldGUgdGhlIGNhbGwuXG4gICAgICovXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0cmF0ZWd5XG4gICAgICAgICAgICAgICAgLmdldFJ1bigpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBydW4gb2JqZWN0IGZvciBhIG5ldyBydW4sIHJlZ2FyZGxlc3Mgb2Ygc3RyYXRlZ3k6IGZvcmNlIGNyZWF0aW9uIG9mIGEgbmV3IHJ1bi5cbiAgICAgKlxuICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBybS5yZXNldCgpLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAqICAgICAgICAgIC8vIHVzZSB0aGUgKG5ldykgcnVuIG9iamVjdFxuICAgICAqICAgICAgICAgIHZhciB0aGlzUnVuSWQgPSBydW4uaWQ7XG4gICAgICpcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIFJ1biBTZXJ2aWNlIG9iamVjdFxuICAgICAqICAgICAgICAgIHJtLnJ1bi5kbygncnVuTW9kZWwnKTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gYHJ1blNlcnZpY2VPcHRpb25zYCBUaGUgb3B0aW9ucyBvYmplY3QgdG8gY29uZmlndXJlIHRoZSBSdW4gU2VydmljZS4gU2VlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pIGZvciBtb3JlLlxuICAgICAqL1xuICAgIHJlc2V0OiBmdW5jdGlvbiAocnVuU2VydmljZU9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RyYXRlZ3kucmVzZXQocnVuU2VydmljZU9wdGlvbnMpO1xuICAgIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUnVuTWFuYWdlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgLy8gYWx3YXlzIGNyZWF0ZSBhIG5ldyBydW4hXG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgbWFrZVNlcSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvbWFrZS1zZXF1ZW5jZScpO1xudmFyIEJhc2UgPSByZXF1aXJlKCcuL2lkZW50aXR5LXN0cmF0ZWd5Jyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi8uLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4uL2F1dGgtbWFuYWdlcicpO1xuXG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuLi9rZXktbmFtZXMnKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHNlc3Npb25LZXk6IGtleU5hbWVzLlNUUkFURUdZX1NFU1NJT05fS0VZLFxuICAgIHBhdGg6ICcnXG59O1xuXG5mdW5jdGlvbiBzZXRSdW5JblNlc3Npb24oc2Vzc2lvbktleSwgcnVuLCBzZXNzaW9uTWFuYWdlcikge1xuICAgIHNlc3Npb25NYW5hZ2VyLmdldFN0b3JlKCkuc2V0KHNlc3Npb25LZXksIEpTT04uc3RyaW5naWZ5KHsgcnVuSWQ6IHJ1bi5pZCB9KSk7XG59XG5cbi8qKlxuKiBDb25kaXRpb25hbCBDcmVhdGlvbiBTdHJhdGVneVxuKiBUaGlzIHN0cmF0ZWd5IHdpbGwgdHJ5IHRvIGdldCB0aGUgcnVuIHN0b3JlZCBpbiB0aGUgY29va2llIGFuZFxuKiBldmFsdWF0ZSBpZiBuZWVkcyB0byBjcmVhdGUgYSBuZXcgcnVuIGJ5IGNhbGxpbmcgdGhlICdjb25kaXRpb24nIGZ1bmN0aW9uXG4qL1xuXG4vKiBqc2hpbnQgZXFudWxsOiB0cnVlICovXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQmFzZSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiBTdHJhdGVneShydW5TZXJ2aWNlLCBjb25kaXRpb24sIG9wdGlvbnMpIHtcblxuICAgICAgICBpZiAoY29uZGl0aW9uID09IG51bGwpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignQ29uZGl0aW9uYWwgc3RyYXRlZ3kgbmVlZHMgYSBjb25kaXRpb24gdG8gY3JlYXRldGUgYSBydW4nKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuX2F1dGggPSBuZXcgQXV0aE1hbmFnZXIoKTtcbiAgICAgICAgdGhpcy5ydW4gPSBtYWtlU2VxKHJ1blNlcnZpY2UpO1xuICAgICAgICB0aGlzLmNvbmRpdGlvbiA9IHR5cGVvZiBjb25kaXRpb24gIT09ICdmdW5jdGlvbicgPyBmdW5jdGlvbiAoKSB7IHJldHVybiBjb25kaXRpb247IH0gOiBjb25kaXRpb247XG4gICAgICAgIHRoaXMub3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgb3B0aW9ucyk7XG4gICAgICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIob3B0aW9ucyk7XG4gICAgICAgIHRoaXMucnVuT3B0aW9ucyA9IHRoaXMub3B0aW9ucy5ydW47XG4gICAgfSxcblxuICAgIHJ1bk9wdGlvbnNXaXRoU2NvcGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHVzZXJTZXNzaW9uID0gdGhpcy5fYXV0aC5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgIHJldHVybiAkLmV4dGVuZCh7XG4gICAgICAgICAgICBzY29wZTogeyBncm91cDogdXNlclNlc3Npb24uZ3JvdXBOYW1lIH1cbiAgICAgICAgfSwgdGhpcy5ydW5PcHRpb25zKTtcbiAgICB9LFxuXG4gICAgcmVzZXQ6IGZ1bmN0aW9uIChydW5TZXJ2aWNlT3B0aW9ucykge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB2YXIgb3B0ID0gdGhpcy5ydW5PcHRpb25zV2l0aFNjb3BlKCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuXG4gICAgICAgICAgICAgICAgLmNyZWF0ZShvcHQsIHJ1blNlcnZpY2VPcHRpb25zKVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIHNldFJ1bkluU2Vzc2lvbihfdGhpcy5vcHRpb25zLnNlc3Npb25LZXksIHJ1biwgX3RoaXMuc2Vzc2lvbk1hbmFnZXIpO1xuICAgICAgICAgICAgICAgIHJ1bi5mcmVzaGx5Q3JlYXRlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuc3RhcnQoKTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBzZXNzaW9uU3RvcmUgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldFN0b3JlKCk7XG4gICAgICAgIHZhciBydW5TZXNzaW9uID0gSlNPTi5wYXJzZShzZXNzaW9uU3RvcmUuZ2V0KHRoaXMub3B0aW9ucy5zZXNzaW9uS2V5KSk7XG5cbiAgICAgICAgaWYgKHJ1blNlc3Npb24gJiYgcnVuU2Vzc2lvbi5ydW5JZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2xvYWRBbmRDaGVjayhydW5TZXNzaW9uKS5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5yZXNldCgpOyAvL2lmIGl0IGdvdCB0aGUgd3JvbmcgY29va2llIGZvciBlLmcuXG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMucmVzZXQoKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBfbG9hZEFuZENoZWNrOiBmdW5jdGlvbiAocnVuU2Vzc2lvbikge1xuICAgICAgICB2YXIgc2hvdWxkQ3JlYXRlID0gZmFsc2U7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuXG4gICAgICAgICAgICAubG9hZChydW5TZXNzaW9uLnJ1bklkLCBudWxsLCB7XG4gICAgICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKHJ1biwgbXNnLCBoZWFkZXJzKSB7XG4gICAgICAgICAgICAgICAgICAgIHNob3VsZENyZWF0ZSA9IF90aGlzLmNvbmRpdGlvbi5jYWxsKF90aGlzLCBydW4sIGhlYWRlcnMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgaWYgKHNob3VsZENyZWF0ZSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgb3B0ID0gX3RoaXMucnVuT3B0aW9uc1dpdGhTY29wZSgpO1xuICAgICAgICAgICAgICAgICAgICAvLyB3ZSBuZWVkIHRvIGRvIHRoaXMsIG9uIHRoZSBvcmlnaW5hbCBydW5TZXJ2aWNlIChpZSBub3Qgc2VxdWVuY2lhbGl6ZWQpXG4gICAgICAgICAgICAgICAgICAgIC8vIHNvIHdlIGRvbid0IGdldCBpbiB0aGUgbWlkZGxlIG9mIHRoZSBxdWV1ZVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gX3RoaXMucnVuLm9yaWdpbmFsLmNyZWF0ZShvcHQpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNldFJ1bkluU2Vzc2lvbihfdGhpcy5vcHRpb25zLnNlc3Npb25LZXksIHJ1biwgX3RoaXMuc2Vzc2lvbk1hbmFnZXIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnN0YXJ0KCk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0ge307XG5cbi8vIEludGVyZmFjZSB0aGF0IGFsbCBzdHJhdGVnaWVzIG5lZWQgdG8gaW1wbGVtZW50XG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuU2VydmljZSAgPSBydW5TZXJ2aWNlO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSBuZXdseSBjcmVhdGVkIHJ1blxuICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlc29sdmUoKS5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSB1c2FibGUgcnVuXG4gICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVzb2x2ZSh0aGlzLnJ1blNlcnZpY2UpLnByb21pc2UoKTtcbiAgICB9XG59KTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xuXG52YXIgSWRlbnRpdHlTdHJhdGVneSA9IHJlcXVpcmUoJy4vaWRlbnRpdHktc3RyYXRlZ3knKTtcbnZhciBXb3JsZEFwaUFkYXB0ZXIgPSByZXF1aXJlKCcuLi8uLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuLi9hdXRoLW1hbmFnZXInKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHN0b3JlOiB7XG4gICAgICAgIHN5bmNocm9ub3VzOiB0cnVlXG4gICAgfVxufTtcblxudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKElkZW50aXR5U3RyYXRlZ3ksIHtcblxuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICB0aGlzLnJ1blNlcnZpY2UgPSBydW5TZXJ2aWNlO1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMud29ybGRBcGkgPSBuZXcgV29ybGRBcGlBZGFwdGVyKHRoaXMub3B0aW9ucy5ydW4pO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICB2YXIgY3VyVXNlcklkID0gc2Vzc2lvbi51c2VySWQ7XG4gICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaVxuICAgICAgICAgICAgLmdldEN1cnJlbnRXb3JsZEZvclVzZXIoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaS5uZXdSdW5Gb3JXb3JsZCh3b3JsZC5pZCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIGN1clVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICB2YXIgY3VyR3JvdXBOYW1lID0gc2Vzc2lvbi5ncm91cE5hbWU7XG4gICAgICAgIHZhciB3b3JsZEFwaSA9IHRoaXMud29ybGRBcGk7XG4gICAgICAgIHZhciBtb2RlbCA9IHRoaXMub3B0aW9ucy5tb2RlbDtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcblxuICAgICAgICBpZiAoIWN1clVzZXJJZCkge1xuICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDAsIGVycm9yOiAnV2UgbmVlZCBhbiBhdXRoZW50aWNhdGVkIHVzZXIgdG8gam9pbiBhIG11bHRpcGxheWVyIHdvcmxkLiAoRVJSOiBubyB1c2VySWQgaW4gc2Vzc2lvbiknIH0sIHNlc3Npb24pLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBsb2FkUnVuRnJvbVdvcmxkID0gZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICBpZiAoIXdvcmxkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDQsIGVycm9yOiAnVGhlIHVzZXIgaXMgbm90IGluIGFueSB3b3JsZC4nIH0sIHsgb3B0aW9uczogdGhpcy5vcHRpb25zLCBzZXNzaW9uOiBzZXNzaW9uIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gd29ybGRBcGkuZ2V0Q3VycmVudFJ1bklkKHsgbW9kZWw6IG1vZGVsLCBmaWx0ZXI6IHdvcmxkLmlkIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oX3RoaXMuX2xvYWRSdW4pXG4gICAgICAgICAgICAgICAgLnRoZW4oZHRkLnJlc29sdmUpXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHNlcnZlckVycm9yID0gZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAvLyBpcyB0aGlzIHBvc3NpYmxlP1xuICAgICAgICAgICAgZHRkLnJlamVjdChlcnJvciwgc2Vzc2lvbiwgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLndvcmxkQXBpXG4gICAgICAgICAgICAuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcihjdXJVc2VySWQsIGN1ckdyb3VwTmFtZSlcbiAgICAgICAgICAgIC50aGVuKGxvYWRSdW5Gcm9tV29ybGQpXG4gICAgICAgICAgICAuZmFpbChzZXJ2ZXJFcnJvcik7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIF9sb2FkUnVuOiBmdW5jdGlvbiAoaWQsIG9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5sb2FkKGlkLCBudWxsLCBvcHRpb25zKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIHJldHVybiBoZWFkZXJzLmdldFJlc3BvbnNlSGVhZGVyKCdwcmFnbWEnKSA9PT0gJ3BlcnNpc3RlbnQnIHx8IHJ1bi5pbml0aWFsaXplZDtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbi8qXG4qICBjcmVhdGUgYSBuZXcgcnVuIG9ubHkgaWYgbm90aGluZyBpcyBzdG9yZWQgaW4gdGhlIGNvb2tpZVxuKiAgdGhpcyBpcyB1c2VmdWwgZm9yIGJhc2VSdW5zLlxuKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgLy8gaWYgd2UgYXJlIGhlcmUsIGl0IG1lYW5zIHRoYXQgdGhlIHJ1biBleGlzdHMuLi4gc28gd2UgZG9uJ3QgbmVlZCBhIG5ldyBvbmVcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgcmV0dXJuIGhlYWRlcnMuZ2V0UmVzcG9uc2VIZWFkZXIoJ3ByYWdtYScpID09PSAncGVyc2lzdGVudCc7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBJZGVudGl0eVN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIFN0YXRlQXBpID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xudmFyIEF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4uL2tleS1uYW1lcycpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgc3RvcmU6IHtcbiAgICAgICAgc3luY2hyb25vdXM6IHRydWVcbiAgICB9XG59O1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oSWRlbnRpdHlTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiBTdHJhdGVneShydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICAgICAgdGhpcy5fc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkodGhpcy5vcHRpb25zLnN0b3JlKTtcbiAgICAgICAgdGhpcy5zdGF0ZUFwaSA9IG5ldyBTdGF0ZUFwaSgpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG5cbiAgICAgICAgdGhpcy5fbG9hZEFuZENoZWNrID0gdGhpcy5fbG9hZEFuZENoZWNrLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX3Jlc3RvcmVSdW4gPSB0aGlzLl9yZXN0b3JlUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2dldEFsbFJ1bnMgPSB0aGlzLl9nZXRBbGxSdW5zLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAocnVuU2VydmljZU9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiBzZXNzaW9uLmdyb3VwTmFtZSB9XG4gICAgICAgIH0sIHRoaXMucnVuT3B0aW9ucyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuXG4gICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0QWxsUnVucygpXG4gICAgICAgICAgICAudGhlbih0aGlzLl9sb2FkQW5kQ2hlY2spO1xuICAgIH0sXG5cbiAgICBfZ2V0QWxsUnVuczogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IEpTT04ucGFyc2UodGhpcy5fc3RvcmUuZ2V0KGtleU5hbWVzLkVQSV9TRVNTSU9OX0tFWSkgfHwgJ3t9Jyk7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5xdWVyeSh7XG4gICAgICAgICAgICAndXNlci5pZCc6IHNlc3Npb24udXNlcklkIHx8ICcwMDAwJyxcbiAgICAgICAgICAgICdzY29wZS5ncm91cCc6IHNlc3Npb24uZ3JvdXBOYW1lXG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICBfbG9hZEFuZENoZWNrOiBmdW5jdGlvbiAocnVucykge1xuICAgICAgICBpZiAoIXJ1bnMgfHwgIXJ1bnMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yZXNldCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGRhdGVDb21wID0gZnVuY3Rpb24gKGEsIGIpIHsgcmV0dXJuIG5ldyBEYXRlKGIuZGF0ZSkgLSBuZXcgRGF0ZShhLmRhdGUpOyB9O1xuICAgICAgICB2YXIgbGF0ZXN0UnVuID0gcnVucy5zb3J0KGRhdGVDb21wKVswXTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIHNob3VsZFJlcGxheSA9IGZhbHNlO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5sb2FkKGxhdGVzdFJ1bi5pZCwgbnVsbCwge1xuICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKHJ1biwgbXNnLCBoZWFkZXJzKSB7XG4gICAgICAgICAgICAgICAgc2hvdWxkUmVwbGF5ID0gaGVhZGVycy5nZXRSZXNwb25zZUhlYWRlcigncHJhZ21hJykgPT09ICdwZXJzaXN0ZW50JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSkudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICByZXR1cm4gc2hvdWxkUmVwbGF5ID8gX3RoaXMuX3Jlc3RvcmVSdW4ocnVuLmlkKSA6IHJ1bjtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIF9yZXN0b3JlUnVuOiBmdW5jdGlvbiAocnVuSWQpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGVBcGkucmVwbGF5KHsgcnVuSWQ6IHJ1bklkIH0pXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzcCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5fbG9hZFJ1bihyZXNwLnJ1bik7XG4gICAgICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgX2xvYWRSdW46IGZ1bmN0aW9uIChpZCwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5ydW4ubG9hZChpZCwgbnVsbCwgb3B0aW9ucyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIm1vZHVsZS5leHBvcnRzID0ge1xuICAgICduZXctaWYtaW5pdGlhbGl6ZWQnOiByZXF1aXJlKCcuL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpLFxuICAgICduZXctaWYtcGVyc2lzdGVkJzogcmVxdWlyZSgnLi9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5JyksXG4gICAgJ25ldy1pZi1taXNzaW5nJzogcmVxdWlyZSgnLi9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpLFxuICAgICdhbHdheXMtbmV3JzogcmVxdWlyZSgnLi9hbHdheXMtbmV3LXN0cmF0ZWd5JyksXG4gICAgJ211bHRpcGxheWVyJzogcmVxdWlyZSgnLi9tdWx0aXBsYXllci1zdHJhdGVneScpLFxuICAgICdwZXJzaXN0ZW50LXNpbmdsZS1wbGF5ZXInOiByZXF1aXJlKCcuL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneScpLFxuICAgICdub25lJzogcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpXG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIFJ1blNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgdmFsaWRGaWx0ZXI6IHsgc2F2ZWQ6IHRydWUgfVxufTtcblxuZnVuY3Rpb24gU2NlbmFyaW9NYW5hZ2VyKG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMucnVuU2VydmljZSA9IHRoaXMub3B0aW9ucy5ydW4gfHwgbmV3IFJ1blNlcnZpY2UodGhpcy5vcHRpb25zKTtcbn1cblxuU2NlbmFyaW9NYW5hZ2VyLnByb3RvdHlwZSA9IHtcbiAgICBnZXRSdW5zOiBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgIHRoaXMuZmlsdGVyID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMub3B0aW9ucy52YWxpZEZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5xdWVyeSh0aGlzLmZpbHRlcik7XG4gICAgfSxcblxuICAgIGxvYWRWYXJpYWJsZXM6IGZ1bmN0aW9uICh2YXJzKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1blNlcnZpY2UucXVlcnkodGhpcy5maWx0ZXIsIHsgaW5jbHVkZTogdmFycyB9KTtcbiAgICB9LFxuXG4gICAgc2F2ZTogZnVuY3Rpb24gKHJ1biwgbWV0YSkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0U2VydmljZShydW4pLnNhdmUoJC5leHRlbmQodHJ1ZSwge30sIHsgc2F2ZWQ6IHRydWUgfSwgbWV0YSkpO1xuICAgIH0sXG5cbiAgICBhcmNoaXZlOiBmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9nZXRTZXJ2aWNlKHJ1bikuc2F2ZSh7IHNhdmVkOiBmYWxzZSB9KTtcbiAgICB9LFxuXG4gICAgX2dldFNlcnZpY2U6IGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW4gfSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdvYmplY3QnICYmIHJ1biBpbnN0YW5jZW9mIFJ1blNlcnZpY2UpIHtcbiAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgIH1cblxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NhdmUgbWV0aG9kIHJlcXVpcmVzIGEgcnVuIHNlcnZpY2Ugb3IgYSBydW5JZCcpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW5JZCB9KSk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTY2VuYXJpb01hbmFnZXI7XG5cbiIsIid1c2Ugc3RyaWN0JztcblxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICByZXNldDogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucywgbWFuYWdlcikge1xuICAgICAgICByZXR1cm4gbWFuYWdlci5yZXNldChvcHRpb25zKTtcbiAgICB9XG59O1xuIiwiLyoqXG4qICMjIFdvcmxkIE1hbmFnZXJcbipcbiogQXMgZGlzY3Vzc2VkIHVuZGVyIHRoZSBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLyksIGEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsLiBGb3IgYnVpbGRpbmcgbXVsdGlwbGF5ZXIgc2ltdWxhdGlvbnMgeW91IHR5cGljYWxseSB3YW50IG11bHRpcGxlIGVuZCB1c2VycyB0byBzaGFyZSB0aGUgc2FtZSBzZXQgb2YgaW50ZXJhY3Rpb25zLCBhbmQgd29yayB3aXRoaW4gYSBjb21tb24gc3RhdGUuIEVwaWNlbnRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSBcIndvcmxkc1wiIHRvIGhhbmRsZSBzdWNoIGNhc2VzLlxuKlxuKiBUaGUgV29ybGQgTWFuYWdlciBwcm92aWRlcyBhbiBlYXN5IHdheSB0byB0cmFjayBhbmQgYWNjZXNzIHRoZSBjdXJyZW50IHdvcmxkIGFuZCBydW4gZm9yIHBhcnRpY3VsYXIgZW5kIHVzZXJzLiBJdCBpcyB0eXBpY2FsbHkgdXNlZCBpbiBwYWdlcyB0aGF0IGVuZCB1c2VycyB3aWxsIGludGVyYWN0IHdpdGguIChUaGUgcmVsYXRlZCBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLykgaGFuZGxlcyBjcmVhdGluZyBtdWx0aXBsYXllciB3b3JsZHMsIGFuZCBhZGRpbmcgYW5kIHJlbW92aW5nIGVuZCB1c2VycyBhbmQgcnVucyBmcm9tIGEgd29ybGQuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4pXG4qXG4qICMjIyBVc2luZyB0aGUgV29ybGQgTWFuYWdlclxuKlxuKiBUbyB1c2UgdGhlIFdvcmxkIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LiBUaGVuLCBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbipcbiogV2hlbiB5b3UgaW5zdGFudGlhdGUgYSBXb3JsZCBNYW5hZ2VyLCB0aGUgd29ybGQncyBhY2NvdW50IGlkLCBwcm9qZWN0IGlkLCBhbmQgZ3JvdXAgYXJlIGF1dG9tYXRpY2FsbHkgdGFrZW4gZnJvbSB0aGUgc2Vzc2lvbiAodGhhbmtzIHRvIHRoZSBbQXV0aGVudGljYXRpb24gU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZSkpLlxuKlxuKiBOb3RlIHRoYXQgdGhlIFdvcmxkIE1hbmFnZXIgZG9lcyAqbm90KiBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkuIChUaGlzIGlzIGRpZmZlcmVudCB0aGFuIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyKS4pIEhvd2V2ZXIsIHlvdSBjYW4gcGFzcyBpbiBzcGVjaWZpYyBvcHRpb25zIHRvIGFueSBydW5zIGNyZWF0ZWQgYnkgdGhlIG1hbmFnZXIsIHVzaW5nIGEgYHJ1bmAgb2JqZWN0LlxuKlxuKiBUaGUgcGFyYW1ldGVycyBmb3IgY3JlYXRpbmcgYSBXb3JsZCBNYW5hZ2VyIGFyZTpcbipcbiogICAqIGBhY2NvdW50YDogVGhlICoqVGVhbSBJRCoqIGluIHRoZSBFcGljZW50ZXIgdXNlciBpbnRlcmZhY2UgZm9yIHRoaXMgcHJvamVjdC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGlzIHByb2plY3QuXG4qICAgKiBgZ3JvdXBgOiBUaGUgKipHcm91cCBOYW1lKiogZm9yIHRoaXMgd29ybGQuXG4qICAgKiBgcnVuYDogT3B0aW9ucyB0byB1c2Ugd2hlbiBjcmVhdGluZyBuZXcgcnVucyB3aXRoIHRoZSBtYW5hZ2VyLCBlLmcuIGBydW46IHsgZmlsZXM6IFsnZGF0YS54bHMnXSB9YC5cbiogICAqIGBydW4ubW9kZWxgOiBUaGUgbmFtZSBvZiB0aGUgcHJpbWFyeSBtb2RlbCBmaWxlIGZvciB0aGlzIHByb2plY3QuIFJlcXVpcmVkIGlmIHlvdSBoYXZlIG5vdCBhbHJlYWR5IHBhc3NlZCBpdCBpbiBhcyBwYXJ0IG9mIHRoZSBgb3B0aW9uc2AgcGFyYW1ldGVyIGZvciBhbiBlbmNsb3NpbmcgY2FsbC5cbipcbiogRm9yIGV4YW1wbGU6XG4qXG4qICAgICAgIHZhciB3TWdyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4qICAgICAgICAgIHJ1bjogeyBtb2RlbDogJ3N1cHBseS1jaGFpbi5weScgfSxcbiogICAgICAgICAgZ3JvdXA6ICd0ZWFtMSdcbiogICAgICAgfSk7XG4qXG4qICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bigpO1xuKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgV29ybGRBcGkgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgUnVuTWFuYWdlciA9ICByZXF1aXJlKCcuL3J1bi1tYW5hZ2VyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL2F1dGgtbWFuYWdlcicpO1xudmFyIHdvcmxkQXBpO1xuXG4vLyB2YXIgZGVmYXVsdHMgPSB7XG4vLyAgYWNjb3VudDogJycsXG4vLyAgcHJvamVjdDogJycsXG4vLyAgZ3JvdXA6ICcnLFxuLy8gIHRyYW5zcG9ydDoge1xuLy8gIH1cbi8vIH07XG5cblxuZnVuY3Rpb24gYnVpbGRTdHJhdGVneSh3b3JsZElkLCBkdGQpIHtcblxuICAgIHJldHVybiBmdW5jdGlvbiBDdG9yKHJ1blNlcnZpY2UsIG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5ydW5TZXJ2aWNlID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcblxuICAgICAgICAkLmV4dGVuZCh0aGlzLCB7XG4gICAgICAgICAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbm90IGltcGxlbWVudGQuIE5lZWQgYXBpIGNoYW5nZXMnKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgICAgICAgICAgLy9nZXQgb3IgY3JlYXRlIVxuICAgICAgICAgICAgICAgIC8vIE1vZGVsIGlzIHJlcXVpcmVkIGluIHRoZSBvcHRpb25zXG4gICAgICAgICAgICAgICAgdmFyIG1vZGVsID0gdGhpcy5vcHRpb25zLnJ1bi5tb2RlbCB8fCB0aGlzLm9wdGlvbnMubW9kZWw7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHdvcmxkQXBpLmdldEN1cnJlbnRSdW5JZCh7IG1vZGVsOiBtb2RlbCwgZmlsdGVyOiB3b3JsZElkIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1blNlcnZpY2UubG9hZChydW5JZCk7XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlLmNhbGwodGhpcywgcnVuLCBfdGhpcy5ydW5TZXJ2aWNlKTtcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH07XG59XG5cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnMgfHwgeyBydW46IHt9LCB3b3JsZDoge30gfTtcblxuICAgICQuZXh0ZW5kKHRydWUsIHRoaXMub3B0aW9ucywgdGhpcy5vcHRpb25zLnJ1bik7XG4gICAgJC5leHRlbmQodHJ1ZSwgdGhpcy5vcHRpb25zLCB0aGlzLm9wdGlvbnMud29ybGQpO1xuXG4gICAgd29ybGRBcGkgPSBuZXcgV29ybGRBcGkodGhpcy5vcHRpb25zKTtcbiAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgIHZhciBhcGkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0dXJucyB0aGUgY3VycmVudCB3b3JsZCAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtXb3JsZCBBUEkgQWRhcHRlcl0oLi4vd29ybGQtYXBpLWFkYXB0ZXIvKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB3TWdyLmdldEN1cnJlbnRXb3JsZCgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkLCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdvcmxkQWRhcHRlci5nZXRDdXJyZW50UnVuSWQoKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgdXNlcklkYCAoT3B0aW9uYWwpIFRoZSBpZCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZCBpcyBiZWluZyBhY2Nlc3NlZC4gRGVmYXVsdHMgdG8gdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgZ3JvdXAgd2hvc2Ugd29ybGQgaXMgYmVpbmcgYWNjZXNzZWQuIERlZmF1bHRzIHRvIHRoZSBncm91cCBmb3IgdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFdvcmxkOiBmdW5jdGlvbiAodXNlcklkLCBncm91cE5hbWUpIHtcbiAgICAgICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5fYXV0aC5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgICAgICBpZiAoIXVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFncm91cE5hbWUpIHtcbiAgICAgICAgICAgICAgICBncm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB3b3JsZEFwaS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKHVzZXJJZCwgZ3JvdXBOYW1lKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHJ1biAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bih7bW9kZWw6ICdteU1vZGVsLnB5J30pXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1biwgcnVuU2VydmljZSkge1xuICAgICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2cocnVuLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHJ1blNlcnZpY2UuZG8oJ3N0YXJ0R2FtZScpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBtb2RlbGAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgbW9kZWwgZmlsZS4gUmVxdWlyZWQgaWYgbm90IGFscmVhZHkgcGFzc2VkIGluIGFzIGBydW4ubW9kZWxgIHdoZW4gdGhlIFdvcmxkIE1hbmFnZXIgaXMgY3JlYXRlZC5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFJ1bjogZnVuY3Rpb24gKG1vZGVsKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgICAgIHZhciBjdXJVc2VySWQgPSBzZXNzaW9uLnVzZXJJZDtcbiAgICAgICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICAgICAgZnVuY3Rpb24gZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bih3b3JsZCkge1xuICAgICAgICAgICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBlcnJvcjogJ1RoZSB1c2VyIGlzIG5vdCBwYXJ0IG9mIGFueSB3b3JsZCEnIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBjdXJyZW50V29ybGRJZCA9IHdvcmxkLmlkO1xuICAgICAgICAgICAgICAgIHZhciBydW5PcHRzID0gJC5leHRlbmQodHJ1ZSwgX3RoaXMub3B0aW9ucywgeyBtb2RlbDogbW9kZWwgfSk7XG4gICAgICAgICAgICAgICAgdmFyIHN0cmF0ZWd5ID0gYnVpbGRTdHJhdGVneShjdXJyZW50V29ybGRJZCwgZHRkKTtcbiAgICAgICAgICAgICAgICB2YXIgb3B0ID0gJC5leHRlbmQodHJ1ZSwge30sIHtcbiAgICAgICAgICAgICAgICAgICAgc3RyYXRlZ3k6IHN0cmF0ZWd5LFxuICAgICAgICAgICAgICAgICAgICBydW46IHJ1bk9wdHNcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB2YXIgcm0gPSBuZXcgUnVuTWFuYWdlcihvcHQpO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJtLmdldFJ1bigpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHJ1biwgcm0ucnVuU2VydmljZSwgcm0pO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5nZXRDdXJyZW50V29ybGQoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAgICAgLnRoZW4oZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bik7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIGFwaSk7XG59O1xuIiwiLyoqXG4gKiAjIyBGaWxlIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhpcyBpcyB1c2VkIHRvIHVwbG9hZC9kb3dubG9hZCBmaWxlcyBkaXJlY3RseSBvbnRvIEVwaWNlbnRlciwgYW5hbG9nb3VzIHRvIHVzaW5nIHRoZSBGaWxlIE1hbmFnZXIgVUkgaW4gRXBpY2VudGVyIGRpcmVjdGx5IG9yIFNGVFBpbmcgZmlsZXMgaW4uIFRoZSBBc3NldCBBUEkgaXMgdHlwaWNhbGx5IHVzZWQgZm9yIGFsbCBwcm9qZWN0IHVzZS1jYXNlcywgYW5kIGl0J3MgdW5saWtlbHkgdGhpcyBGaWxlIFNlcnZpY2Ugd2lsbCBiZSB1c2VkIGRpcmVjdGx5IGV4Y2VwdCBieSBBZG1pbiB0b29scyAoZS5nLiBGbG93IEluc3BlY3RvcikuXG4gKlxuICogUGFydGlhbGx5IGltcGxlbWVudGVkLlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRva2VuOiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBmb2xkZXIgdHlwZS4gIE9uZSBvZiBNb2RlbHxTdGF0aWN8Tm9kZVxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZm9sZGVyVHlwZTogJ3N0YXRpYycsXG5cblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9XG4gICAgfTtcblxuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHVybENvbmZpZy5hY2NvdW50UGF0aCA9IHNlcnZpY2VPcHRpb25zLmFjY291bnQ7XG4gICAgfVxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHVybENvbmZpZy5wcm9qZWN0UGF0aCA9IHNlcnZpY2VPcHRpb25zLnByb2plY3Q7XG4gICAgfVxuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdmaWxlJylcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBc3luY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBhIGRpcmVjdG9yeSBsaXN0aW5nLCBvciBjb250ZW50cyBvZiBhIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBgZmlsZVBhdGhgICAgUGF0aCB0byB0aGUgZmlsZVxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgZ2V0Q29udGVudHM6IGZ1bmN0aW9uIChmaWxlUGF0aCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhdGggPSBzZXJ2aWNlT3B0aW9ucy5mb2xkZXJUeXBlICsgJy8nICsgZmlsZVBhdGg7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdmaWxlJykgKyBwYXRoXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldCgnJywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBXcml0ZXMgdG8gdGhlIGdpdmVuIGZpbGUgcGF0aDsgcmVwbGFjZXMgdGhlIGV4aXN0aW5nIGZpbGUgaWYgaXQgZXhpc3RzXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGZpbGVQYXRoYCBQYXRoIHRvIHRoZSBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGNvbnRlbnRzYCBDb250ZW50cyB0byB3cml0ZSB0byBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gYG9wdGlvbnNgICAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAgICAgICAqL1xuICAgICAgICB3cml0ZVRvRmlsZTogZnVuY3Rpb24gKGZpbGVQYXRoLCBjb250ZW50cywgb3B0aW9ucykge1xuICAgICAgICAgICAgZmlsZVBhdGggPSBmaWxlUGF0aC5zcGxpdCgnLycpO1xuICAgICAgICAgICAgdmFyIGZpbGVOYW1lID0gZmlsZVBhdGgucG9wKCk7XG4gICAgICAgICAgICBmaWxlUGF0aCA9IGZpbGVQYXRoLmpvaW4oJy8nKTtcbiAgICAgICAgICAgIHZhciBwYXRoID0gc2VydmljZU9wdGlvbnMuZm9sZGVyVHlwZSArICcvJyArIGZpbGVQYXRoO1xuICAgICAgICAgICAgdmFyIGJvdW5kYXJ5ID0gJy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLTdkYTI0ZjJlNTAwNDYnO1xuXG4gICAgICAgICAgICB2YXIgYm9keSA9ICctLScgKyBib3VuZGFyeSArICdcXHJcXG4nICtcbiAgICAgICAgICAgICAgICAnQ29udGVudC1EaXNwb3NpdGlvbjogZm9ybS1kYXRhOyBuYW1lPVwiZmlsZVwiOycgK1xuICAgICAgICAgICAgICAgICdmaWxlbmFtZT1cIicgKyBmaWxlTmFtZSArICdcIlxcclxcbicgK1xuICAgICAgICAgICAgICAgICdDb250ZW50LXR5cGU6IHRleHQvaHRtbFxcclxcblxcclxcbicgK1xuICAgICAgICAgICAgICAgIGNvbnRlbnRzICsgJ1xcclxcbicgK1xuICAgICAgICAgICAgICAgICctLScgKyBib3VuZGFyeSArICctLSc7XG5cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2ZpbGUnKSArIHBhdGgsXG4gICAgICAgICAgICAgICAgZGF0YTogYm9keSxcbiAgICAgICAgICAgICAgICBjb250ZW50VHlwZTogJ211bHRpcGFydC9mb3JtLWRhdGE7IGJvdW5kYXJ5PScgKyBib3VuZGFyeVxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnB1dChib2R5LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMgdGhlIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBgZmlsZVBhdGhgIFBhdGggdG8gdGhlIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBgb3B0aW9uc2AgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnNcbiAgICAgICAgICovXG4gICAgICAgIHJlbW92ZTogZnVuY3Rpb24gKGZpbGVQYXRoLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHNlcnZpY2VPcHRpb25zLmZvbGRlclR5cGUgKyAnLycgKyBmaWxlUGF0aDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2ZpbGUnKSArIHBhdGhcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVuYW1lIHRoZSBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gZmlsZVBhdGggUGF0aCB0byB0aGUgZmlsZVxuICAgICAgICAgKiBAcGFyYW0gIHtTdGlybmd9IG5ld05hbWUgIE5ldyBuYW1lIG9mIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBvcHRpb25zICAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAgICAgICAqL1xuICAgICAgICByZW5hbWU6IGZ1bmN0aW9uIChmaWxlUGF0aCwgbmV3TmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhdGggPSBzZXJ2aWNlT3B0aW9ucy5mb2xkZXJUeXBlICsgJy8nICsgZmlsZVBhdGg7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdmaWxlJykgKyBwYXRoXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKHsgJ25hbWUnOiBuZXdOYW1lIH0sIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBc3luY0FQSSk7XG59O1xuIiwiLyoqXG4gKiAjIyBBc3NldCBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBBc3NldCBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHN0b3JlIGFzc2V0cyAtLSByZXNvdXJjZXMgb3IgZmlsZXMgb2YgYW55IGtpbmQgLS0gdXNlZCBieSBhIHByb2plY3Qgd2l0aCBhIHNjb3BlIHRoYXQgaXMgc3BlY2lmaWMgdG8gcHJvamVjdCwgZ3JvdXAsIG9yIGVuZCB1c2VyLlxuICpcbiAqIEFzc2V0cyBhcmUgdXNlZCB3aXRoIFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9wcm9qZWN0X2FkbWluLyN0ZWFtKS4gT25lIGNvbW1vbiB1c2UgY2FzZSBpcyBoYXZpbmcgZW5kIHVzZXJzIGluIGEgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSBvciBpbiBhIFttdWx0aXBsYXllciB3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKSB1cGxvYWQgZGF0YSAtLSB2aWRlb3MgY3JlYXRlZCBkdXJpbmcgZ2FtZSBwbGF5LCBwcm9maWxlIHBpY3R1cmVzIGZvciBjdXN0b21pemluZyB0aGVpciBleHBlcmllbmNlLCBldGMuIC0tIGFzIHBhcnQgb2YgcGxheWluZyB0aHJvdWdoIHRoZSBwcm9qZWN0LlxuICpcbiAqIFJlc291cmNlcyBjcmVhdGVkIHVzaW5nIHRoZSBBc3NldCBBZGFwdGVyIGFyZSBzY29wZWQ6XG4gKlxuICogICogUHJvamVjdCBhc3NldHMgYXJlIHdyaXRhYmxlIG9ubHkgYnkgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pLCB0aGF0IGlzLCBFcGljZW50ZXIgYXV0aG9ycy5cbiAqICAqIEdyb3VwIGFzc2V0cyBhcmUgd3JpdGFibGUgYnkgYW55b25lIHdpdGggYWNjZXNzIHRvIHRoZSBwcm9qZWN0IHRoYXQgaXMgcGFydCBvZiB0aGF0IHBhcnRpY3VsYXIgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS4gVGhpcyBpbmNsdWRlcyBhbGwgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIChFcGljZW50ZXIgYXV0aG9ycykgYW5kIGFueSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiB0aGUgZ3JvdXAgLS0gYm90aCBmYWNpbGl0YXRvcnMgYW5kIHN0YW5kYXJkIGVuZCB1c2Vycy5cbiAqICAqIFVzZXIgYXNzZXRzIGFyZSB3cml0YWJsZSBieSB0aGUgc3BlY2lmaWMgZW5kIHVzZXIsIGFuZCBieSB0aGUgZmFjaWxpdGF0b3Igb2YgdGhlIGdyb3VwLlxuICogICogQWxsIGFzc2V0cyBhcmUgcmVhZGFibGUgYnkgYW55b25lIHdpdGggdGhlIGV4YWN0IFVSSS5cbiAqXG4gKiBUbyB1c2UgdGhlIEFzc2V0IEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSkgYW5kIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKS4gVGhlIGdyb3VwIG5hbWUgaXMgcmVxdWlyZWQgZm9yIGFzc2V0cyB3aXRoIGEgZ3JvdXAgc2NvcGUsIGFuZCB0aGUgZ3JvdXAgbmFtZSBhbmQgdXNlcklkIGFyZSByZXF1aXJlZCBmb3IgYXNzZXRzIHdpdGggYSB1c2VyIHNjb3BlLiBJZiBub3QgaW5jbHVkZWQsIHRoZXkgYXJlIHRha2VuIGZyb20gdGhlIGxvZ2dlZCBpbiB1c2VyJ3Mgc2Vzc2lvbiBpbmZvcm1hdGlvbiBpZiBuZWVkZWQuXG4gKlxuICogV2hlbiBjcmVhdGluZyBhbiBhc3NldCwgeW91IGNhbiBwYXNzIGluIHRleHQgKGVuY29kZWQgZGF0YSkgdG8gdGhlIGBjcmVhdGUoKWAgY2FsbC4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBtYWtlIHRoZSBgY3JlYXRlKClgIGNhbGwgYXMgcGFydCBvZiBhbiBIVE1MIGZvcm0gYW5kIHBhc3MgaW4gYSBmaWxlIHVwbG9hZGVkIHZpYSB0aGUgZm9ybS5cbiAqXG4gKiAgICAgICAvLyBpbnN0YW50aWF0ZSB0aGUgQXNzZXQgQWRhcHRlclxuICogICAgICAgdmFyIGFhID0gbmV3IEYuc2VydmljZS5Bc3NldCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gKiAgICAgICAgICB1c2VySWQ6ICcxMjM0NSdcbiAqICAgICAgIH0pO1xuICpcbiAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAqICAgICAgIGFhLmNyZWF0ZSgndGVzdC50eHQnLCB7XG4gKiAgICAgICAgICAgZW5jb2Rpbmc6ICdCQVNFXzY0JyxcbiAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICogICAgICAgfSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICpcbiAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAqICAgICAgIC8vIHRoaXMgc2FtcGxlIGNvZGUgZ29lcyB3aXRoIGFuIGh0bWwgZm9ybSB0aGF0IGxvb2tzIGxpa2UgdGhpczpcbiAqICAgICAgIC8vXG4gKiAgICAgICAvLyA8Zm9ybSBpZD1cInVwbG9hZC1maWxlXCI+XG4gKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlVwbG9hZCBteUZpbGU8L2J1dHRvbj5cbiAqICAgICAgIC8vIDwvZm9ybT5cbiAqICAgICAgIC8vXG4gKiAgICAgICAkKCcjdXBsb2FkLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAqICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAqXG4gKiAgICAgICAgICBhYS5jcmVhdGUoZmlsZW5hbWUsIGRhdGEsIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAqICAgICAgIH0pO1xuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xuXG52YXIgYXBpRW5kcG9pbnQgPSAnYXNzZXQnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcHJvamVjdCBpZC4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBncm91cCBuYW1lLiBEZWZhdWx0cyB0byBzZXNzaW9uJ3MgYGdyb3VwTmFtZWAuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBncm91cDogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHVzZXIgaWQuIERlZmF1bHRzIHRvIHNlc3Npb24ncyBgdXNlcklkYC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHNjb3BlIGZvciB0aGUgYXNzZXQuIFZhbGlkIHZhbHVlcyBhcmU6IGB1c2VyYCwgYGdyb3VwYCwgYW5kIGBwcm9qZWN0YC4gU2VlIGFib3ZlIGZvciB0aGUgcmVxdWlyZWQgcGVybWlzc2lvbnMgdG8gd3JpdGUgdG8gZWFjaCBzY29wZS4gRGVmYXVsdHMgdG8gYHVzZXJgLCBtZWFuaW5nIHRoZSBjdXJyZW50IGVuZCB1c2VyIG9yIGEgZmFjaWxpdGF0b3IgaW4gdGhlIGVuZCB1c2VyJ3MgZ3JvdXAgY2FuIGVkaXQgdGhlIGFzc2V0LlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgc2NvcGU6ICd1c2VyJyxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIERldGVybWluZXMgaWYgYSByZXF1ZXN0IHRvIGxpc3QgdGhlIGFzc2V0cyBpbiBhIHNjb3BlIGluY2x1ZGVzIHRoZSBjb21wbGV0ZSBVUkwgZm9yIGVhY2ggYXNzZXQgKGB0cnVlYCksIG9yIG9ubHkgdGhlIGZpbGUgbmFtZXMgb2YgdGhlIGFzc2V0cyAoYGZhbHNlYCkuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBmdWxsVXJsOiB0cnVlLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHRyYW5zcG9ydCBvYmplY3QgY29udGFpbnMgdGhlIG9wdGlvbnMgcGFzc2VkIHRvIHRoZSBYSFIgcmVxdWVzdC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge1xuICAgICAgICAgICAgcHJvY2Vzc0RhdGE6IGZhbHNlXG4gICAgICAgIH1cbiAgICB9O1xuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuXG4gICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLmFjY291bnQgPSB1cmxDb25maWcuYWNjb3VudFBhdGg7XG4gICAgfVxuXG4gICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLnByb2plY3QgPSB1cmxDb25maWcucHJvamVjdFBhdGg7XG4gICAgfVxuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgYXNzZXRBcGlQYXJhbXMgPSBbJ2VuY29kaW5nJywgJ2RhdGEnLCAnY29udGVudFR5cGUnXTtcbiAgICB2YXIgc2NvcGVDb25maWcgPSB7XG4gICAgICAgIHVzZXI6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJywgJ3VzZXJJZCddLFxuICAgICAgICBncm91cDogWydzY29wZScsICdhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSxcbiAgICAgICAgcHJvamVjdDogWydzY29wZScsICdhY2NvdW50JywgJ3Byb2plY3QnXSxcbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlRmlsZW5hbWUgPSBmdW5jdGlvbiAoZmlsZW5hbWUpIHtcbiAgICAgICAgaWYgKCFmaWxlbmFtZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdmaWxlbmFtZSBpcyBuZWVkZWQuJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlVXJsUGFyYW1zID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHBhcnRLZXlzID0gc2NvcGVDb25maWdbb3B0aW9ucy5zY29wZV07XG4gICAgICAgIGlmICghcGFydEtleXMpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignc2NvcGUgcGFyYW1ldGVyIGlzIG5lZWRlZC4nKTtcbiAgICAgICAgfVxuXG4gICAgICAgICQuZWFjaChwYXJ0S2V5cywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKCFvcHRpb25zW3RoaXNdKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHRoaXMgKyAnIHBhcmFtZXRlciBpcyBuZWVkZWQuJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICB2YXIgYnVpbGRVcmwgPSBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFsaWRhdGVVcmxQYXJhbXMob3B0aW9ucyk7XG4gICAgICAgIHZhciBwYXJ0S2V5cyA9IHNjb3BlQ29uZmlnW29wdGlvbnMuc2NvcGVdO1xuICAgICAgICB2YXIgcGFydHMgPSAkLm1hcChwYXJ0S2V5cywgZnVuY3Rpb24gKGtleSkge1xuICAgICAgICAgICAgcmV0dXJuIG9wdGlvbnNba2V5XTtcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChmaWxlbmFtZSkge1xuICAgICAgICAgICAgLy8gVGhpcyBwcmV2ZW50cyBhZGRpbmcgYSB0cmFpbGluZyAvIGluIHRoZSBVUkwgYXMgdGhlIEFzc2V0IEFQSVxuICAgICAgICAgICAgLy8gZG9lcyBub3Qgd29yayBjb3JyZWN0bHkgd2l0aCBpdFxuICAgICAgICAgICAgZmlsZW5hbWUgPSAnLycgKyBmaWxlbmFtZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcGFydHMuam9pbignLycpICsgZmlsZW5hbWU7XG4gICAgfTtcblxuICAgIC8vIFByaXZhdGUgZnVuY3Rpb24sIGFsbCByZXF1ZXN0cyBmb2xsb3cgYSBtb3JlIG9yIGxlc3Mgc2FtZSBhcHByb2FjaCB0b1xuICAgIC8vIHVzZSB0aGUgQXNzZXQgQVBJIGFuZCB0aGUgZGlmZmVyZW5jZSBpcyB0aGUgSFRUUCB2ZXJiXG4gICAgLy9cbiAgICAvLyBAcGFyYW0ge3N0cmluZ30gYG1ldGhvZGAgKFJlcXVpcmVkKSBIVFRQIHZlcmJcbiAgICAvLyBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gZGVsZXRlL3JlcGxhY2UvY3JlYXRlXG4gICAgLy8gQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSVxuICAgIC8vIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICB2YXIgdXBsb2FkID0gZnVuY3Rpb24gKG1ldGhvZCwgZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICB2YWxpZGF0ZUZpbGVuYW1lKGZpbGVuYW1lKTtcbiAgICAgICAgLy8gbWFrZSBzdXJlIHRoZSBwYXJhbWV0ZXIgaXMgY2xlYW5cbiAgICAgICAgbWV0aG9kID0gbWV0aG9kLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIHZhciBjb250ZW50VHlwZSA9IHBhcmFtcyBpbnN0YW5jZW9mIEZvcm1EYXRhID09PSB0cnVlID8gZmFsc2UgOiAnYXBwbGljYXRpb24vanNvbic7XG4gICAgICAgIGlmIChjb250ZW50VHlwZSA9PT0gJ2FwcGxpY2F0aW9uL2pzb24nKSB7XG4gICAgICAgICAgICAvLyB3aGl0ZWxpc3QgdGhlIGZpZWxkcyB0aGF0IHdlIGFjdHVhbGx5IGNhbiBzZW5kIHRvIHRoZSBhcGlcbiAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgYXNzZXRBcGlQYXJhbXMpO1xuICAgICAgICB9IGVsc2UgeyAvLyBlbHNlIHdlJ3JlIHNlbmRpbmcgZm9ybSBkYXRhIHdoaWNoIGdvZXMgZGlyZWN0bHkgaW4gcmVxdWVzdCBib2R5XG4gICAgICAgICAgICAvLyBGb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSB1cGxvYWRzIHRoZSBmaWxlbmFtZSBpcyBub3Qgc2V0IGluIHRoZSBVUkwsXG4gICAgICAgICAgICAvLyBpdCdzIGdldHRpbmcgcGlja2VkIGJ5IHRoZSBGb3JtRGF0YSBmaWVsZCBmaWxlbmFtZS5cbiAgICAgICAgICAgIGZpbGVuYW1lID0gbWV0aG9kID09PSAncG9zdCcgfHwgbWV0aG9kID09PSAncHV0JyA/ICcnIDogZmlsZW5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICB2YXIgdXJsID0gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICB2YXIgY3JlYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsLCBjb250ZW50VHlwZTogY29udGVudFR5cGUgfSk7XG5cbiAgICAgICAgcmV0dXJuIGh0dHBbbWV0aG9kXShwYXJhbXMsIGNyZWF0ZU9wdGlvbnMpO1xuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICAvKipcbiAgICAgICAgKiBDcmVhdGVzIGEgZmlsZSBpbiB0aGUgQXNzZXQgQVBJLiBUaGUgc2VydmVyIHJldHVybnMgYW4gZXJyb3IgKHN0YXR1cyBjb2RlIGA0MDlgLCBjb25mbGljdCkgaWYgdGhlIGZpbGUgYWxyZWFkeSBleGlzdHMsIHNvXG4gICAgICAgICogY2hlY2sgZmlyc3Qgd2l0aCBhIGBsaXN0KClgIG9yIGEgYGdldCgpYC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIGFhID0gbmV3IEYuc2VydmljZS5Bc3NldCh7XG4gICAgICAgICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gICAgICAgICogICAgICAgICAgdXNlcklkOiAnJ1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgLy8gY3JlYXRlIGEgbmV3IGFzc2V0IHVzaW5nIGVuY29kZWQgdGV4dFxuICAgICAgICAqICAgICAgIGFhLmNyZWF0ZSgndGVzdC50eHQnLCB7XG4gICAgICAgICogICAgICAgICAgIGVuY29kaW5nOiAnQkFTRV82NCcsXG4gICAgICAgICogICAgICAgICAgIGRhdGE6ICdWR2hwY3lCcGN5QmhJSFJsYzNRZ1ptbHNaUzQ9JyxcbiAgICAgICAgKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICAgICAgICAqICAgICAgIH0sIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAgICAgICAgKiAgICAgICAvLyB0aGlzIHNhbXBsZSBjb2RlIGdvZXMgd2l0aCBhbiBodG1sIGZvcm0gdGhhdCBsb29rcyBsaWtlIHRoaXM6XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAvLyA8Zm9ybSBpZD1cInVwbG9hZC1maWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlXCIgdHlwZT1cImZpbGVcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVuYW1lXCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cIm15RmlsZS50eHRcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlVwbG9hZCBteUZpbGU8L2J1dHRvbj5cbiAgICAgICAgKiAgICAgICAvLyA8L2Zvcm0+XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAkKCcjdXBsb2FkLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgKiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGZpbGVuYW1lID0gJCgnI2ZpbGVuYW1lJykudmFsKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgaW5wdXRDb250cm9sID0gJCgnI2ZpbGUnKVswXTtcbiAgICAgICAgKiAgICAgICAgICBkYXRhLmFwcGVuZCgnZmlsZScsIGlucHV0Q29udHJvbC5maWxlc1swXSwgZmlsZW5hbWUpO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgICAgYWEuY3JlYXRlKGZpbGVuYW1lLCBkYXRhLCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSB0byBjcmVhdGUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSS4gUmVxdWlyZWQgaWYgdGhlIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLCBvdGhlcndpc2UgaWdub3JlZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5lbmNvZGluZ2AgRWl0aGVyIGBIRVhgIG9yIGBCQVNFXzY0YC4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZGF0YWAgVGhlIGVuY29kZWQgZGF0YSBmb3IgdGhlIGZpbGUuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmNvbnRlbnRUeXBlYCBUaGUgbWltZSB0eXBlIG9mIHRoZSBmaWxlLiBPcHRpb25hbC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgY3JlYXRlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHVwbG9hZCgncG9zdCcsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgYSBmaWxlIGZyb20gdGhlIEFzc2V0IEFQSSwgZmV0Y2hpbmcgdGhlIGFzc2V0IGNvbnRlbnQuIChUbyBnZXQgYSBsaXN0XG4gICAgICAgICogb2YgdGhlIGFzc2V0cyBpbiBhIHNjb3BlLCB1c2UgYGxpc3QoKWAuKVxuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIHJldHJpZXZlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGdldFNlcnZpY2VPcHRpb25zID0gX3BpY2soc2VydmljZU9wdGlvbnMsIFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJywgJ3VzZXJJZCddKTtcbiAgICAgICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIGdldFNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciB1cmwgPSBidWlsZFVybChmaWxlbmFtZSwgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoe30sIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIGxpc3Qgb2YgdGhlIGFzc2V0cyBpbiBhIHNjb3BlLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIGFhLmxpc3QoeyBmdWxsVXJsOiB0cnVlIH0pLnRoZW4oZnVuY3Rpb24oZmlsZUxpc3Qpe1xuICAgICAgICAqICAgICAgICAgICBjb25zb2xlLmxvZygnYXJyYXkgb2YgZmlsZXMgPSAnLCBmaWxlTGlzdCk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLnNjb3BlYCAoT3B0aW9uYWwpIFRoZSBzY29wZSAoYHVzZXJgLCBgZ3JvdXBgLCBgcHJvamVjdGApLlxuICAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gYG9wdGlvbnMuZnVsbFVybGAgKE9wdGlvbmFsKSBEZXRlcm1pbmVzIGlmIHRoZSBsaXN0IG9mIGFzc2V0cyBpbiBhIHNjb3BlIGluY2x1ZGVzIHRoZSBjb21wbGV0ZSBVUkwgZm9yIGVhY2ggYXNzZXQgKGB0cnVlYCksIG9yIG9ubHkgdGhlIGZpbGUgbmFtZXMgb2YgdGhlIGFzc2V0cyAoYGZhbHNlYCkuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgbGlzdDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIHVybCA9IGJ1aWxkVXJsKCcnLCB1cmxPcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHVybE9wdGlvbnMsIHsgdXJsOiB1cmwgfSk7XG4gICAgICAgICAgICB2YXIgZnVsbFVybCA9IGdldE9wdGlvbnMuZnVsbFVybDtcblxuICAgICAgICAgICAgaWYgKCFmdWxsVXJsKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaHR0cC5nZXQoe30sIGdldE9wdGlvbnMpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKGZpbGVzKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBmdWxsUGF0aEZpbGVzID0gJC5tYXAoZmlsZXMsIGZ1bmN0aW9uIChmaWxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gYnVpbGRVcmwoZmlsZSwgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShmdWxsUGF0aEZpbGVzLCBtZSk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZmFpbChkdGQucmVqZWN0KTtcblxuICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmVwbGFjZXMgYW4gZXhpc3RpbmcgZmlsZSBpbiB0aGUgQXNzZXQgQVBJLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIHJlcGxhY2UgYW4gYXNzZXQgdXNpbmcgZW5jb2RlZCB0ZXh0XG4gICAgICAgICogICAgICAgYWEucmVwbGFjZSgndGVzdC50eHQnLCB7XG4gICAgICAgICogICAgICAgICAgIGVuY29kaW5nOiAnQkFTRV82NCcsXG4gICAgICAgICogICAgICAgICAgIGRhdGE6ICdWR2hwY3lCcGN5QmhJSE5sWTI5dVpDQjBaWE4wSUdacGJHVXUnLFxuICAgICAgICAqICAgICAgICAgICBjb250ZW50VHlwZTogJ3RleHQvcGxhaW4nXG4gICAgICAgICogICAgICAgfSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgLy8gYWx0ZXJuYXRpdmVseSwgcmVwbGFjZSBhbiBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAgICAgICAgKiAgICAgICAvLyB0aGlzIHNhbXBsZSBjb2RlIGdvZXMgd2l0aCBhbiBodG1sIGZvcm0gdGhhdCBsb29rcyBsaWtlIHRoaXM6XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAvLyA8Zm9ybSBpZD1cInJlcGxhY2UtZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwiZmlsZVwiIHR5cGU9XCJmaWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJyZXBsYWNlLWZpbGVuYW1lXCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cIm15RmlsZS50eHRcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlJlcGxhY2UgbXlGaWxlPC9idXR0b24+XG4gICAgICAgICogICAgICAgLy8gPC9mb3JtPlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgJCgnI3JlcGxhY2UtZmlsZScpLm9uKCdzdWJtaXQnLCBmdW5jdGlvbiAoZSkge1xuICAgICAgICAqICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgZmlsZW5hbWUgPSAkKCcjcmVwbGFjZS1maWxlbmFtZScpLnZhbCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBkYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGlucHV0Q29udHJvbCA9ICQoJyNmaWxlJylbMF07XG4gICAgICAgICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgIGFhLnJlcGxhY2UoZmlsZW5hbWUsIGRhdGEsIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSBiZWluZyByZXBsYWNlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgKE9wdGlvbmFsKSBCb2R5IHBhcmFtZXRlcnMgdG8gc2VuZCB0byB0aGUgQXNzZXQgQVBJLiBSZXF1aXJlZCBpZiB0aGUgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAsIG90aGVyd2lzZSBpZ25vcmVkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmVuY29kaW5nYCBFaXRoZXIgYEhFWGAgb3IgYEJBU0VfNjRgLiBSZXF1aXJlZCBpZiBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5kYXRhYCBUaGUgZW5jb2RlZCBkYXRhIGZvciB0aGUgZmlsZS4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuY29udGVudFR5cGVgIFRoZSBtaW1lIHR5cGUgb2YgdGhlIGZpbGUuIE9wdGlvbmFsLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICByZXBsYWNlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHVwbG9hZCgncHV0JywgZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogRGVsZXRlcyBhIGZpbGUgZnJvbSB0aGUgQXNzZXQgQVBJLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIGFhLmRlbGV0ZShzYW1wbGVGaWxlTmFtZSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gZGVsZXRlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBkZWxldGU6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHVwbG9hZCgnZGVsZXRlJywgZmlsZW5hbWUsIHt9LCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICBhc3NldFVybDogZnVuY3Rpb24gKGZpbGVuYW1lLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgdXJsT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICByZXR1cm4gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICpcbiAqICMjIEF1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhlIEF1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlIHByb3ZpZGVzIGEgbWV0aG9kIGZvciBsb2dnaW5nIGluLCB3aGljaCBjcmVhdGVzIGFuZCByZXR1cm5zIGEgdXNlciBhY2Nlc3MgdG9rZW4uXG4gKlxuICogVXNlciBhY2Nlc3MgdG9rZW5zIGFyZSByZXF1aXJlZCBmb3IgZWFjaCBjYWxsIHRvIEVwaWNlbnRlci4gKFNlZSBbUHJvamVjdCBBY2Nlc3NdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykgZm9yIG1vcmUgaW5mb3JtYXRpb24uKVxuICpcbiAqIElmIHlvdSBuZWVkIGFkZGl0aW9uYWwgZnVuY3Rpb25hbGl0eSAtLSBzdWNoIGFzIHRyYWNraW5nIHNlc3Npb24gaW5mb3JtYXRpb24sIGVhc2lseSByZXRyaWV2aW5nIHRoZSB1c2VyIHRva2VuLCBvciBnZXR0aW5nIHRoZSBncm91cHMgdG8gd2hpY2ggYW4gZW5kIHVzZXIgYmVsb25ncyAtLSBjb25zaWRlciB1c2luZyB0aGUgW0F1dGhvcml6YXRpb24gTWFuYWdlcl0oLi4vYXV0aC1tYW5hZ2VyLykgaW5zdGVhZC5cbiAqXG4gKiAgICAgIHZhciBhdXRoID0gbmV3IEYuc2VydmljZS5BdXRoKCk7XG4gKiAgICAgIGF1dGgubG9naW4oeyB1c2VyTmFtZTogJ2pzbWl0aEBhY21lc2ltdWxhdGlvbnMuY29tJyxcbiAqICAgICAgICAgICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCcgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVtYWlsIG9yIHVzZXJuYW1lIHRvIHVzZSBmb3IgbG9nZ2luZyBpbi4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdXNlck5hbWU6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBQYXNzd29yZCBmb3Igc3BlY2lmaWVkIGB1c2VyTmFtZWAuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHBhc3N3b3JkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQgZm9yIHRoaXMgYHVzZXJOYW1lYC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciB0aGUgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIFJlcXVpcmVkIGlmIHRoZSBgdXNlck5hbWVgIGlzIGZvciBhbiBbZW5kIHVzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGFjY291bnQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgnYXV0aGVudGljYXRpb24nKVxuICAgIH0pO1xuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2dzIHVzZXIgaW4sIHJldHVybmluZyB0aGUgdXNlciBhY2Nlc3MgdG9rZW4uXG4gICAgICAgICAqXG4gICAgICAgICAqIElmIG5vIGB1c2VyTmFtZWAgb3IgYHBhc3N3b3JkYCB3ZXJlIHByb3ZpZGVkIGluIHRoZSBpbml0aWFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucywgdGhleSBhcmUgcmVxdWlyZWQgaW4gdGhlIGBvcHRpb25zYCBoZXJlLiBJZiBubyBgYWNjb3VudGAgd2FzIHByb3ZpZGVkIGluIHRoZSBpbml0aWFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBhbmQgdGhlIGB1c2VyTmFtZWAgaXMgZm9yIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgdGhlIGBhY2NvdW50YCBpcyByZXF1aXJlZCBhcyB3ZWxsLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGF1dGgubG9naW4oe1xuICAgICAgICAgKiAgICAgICAgICB1c2VyTmFtZTogJ2pzbWl0aCcsXG4gICAgICAgICAqICAgICAgICAgIHBhc3N3b3JkOiAncGFzc3cwcmQnLFxuICAgICAgICAgKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycgfSlcbiAgICAgICAgICogICAgICAudGhlbihmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgICAgICogICAgICAgICAgY29uc29sZS5sb2coXCJ1c2VyIGFjY2VzcyB0b2tlbiBpczogXCIsIHRva2VuLmFjY2Vzc190b2tlbik7XG4gICAgICAgICAqICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvZ2luOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgeyBzdWNjZXNzOiAkLm5vb3AgfSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaWYgKCFodHRwT3B0aW9ucy51c2VyTmFtZSB8fCAhaHR0cE9wdGlvbnMucGFzc3dvcmQpIHtcbiAgICAgICAgICAgICAgICB2YXIgcmVzcCA9IHsgc3RhdHVzOiA0MDEsIHN0YXR1c01lc3NhZ2U6ICdObyB1c2VybmFtZSBvciBwYXNzd29yZCBzcGVjaWZpZWQuJyB9O1xuICAgICAgICAgICAgICAgIGlmIChvcHRpb25zLmVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuZXJyb3IuY2FsbCh0aGlzLCByZXNwKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlamVjdChyZXNwKS5wcm9taXNlKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBwb3N0UGFyYW1zID0ge1xuICAgICAgICAgICAgICAgIHVzZXJOYW1lOiBodHRwT3B0aW9ucy51c2VyTmFtZSxcbiAgICAgICAgICAgICAgICBwYXNzd29yZDogaHR0cE9wdGlvbnMucGFzc3dvcmQsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgaWYgKGh0dHBPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgICAgICAgICAvL3Bhc3MgaW4gbnVsbCBmb3IgYWNjb3VudCB1bmRlciBvcHRpb25zIGlmIHlvdSBkb24ndCB3YW50IGl0IHRvIGJlIHNlbnRcbiAgICAgICAgICAgICAgICBwb3N0UGFyYW1zLmFjY291bnQgPSBodHRwT3B0aW9ucy5hY2NvdW50O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBvc3RQYXJhbXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvLyAocmVwbGFjZSB3aXRoIC8qICovIGNvbW1lbnQgYmxvY2ssIHRvIG1ha2UgdmlzaWJsZSBpbiBkb2NzLCBvbmNlIHRoaXMgaXMgbW9yZSB0aGFuIGEgbm9vcClcbiAgICAgICAgLy9cbiAgICAgICAgLy8gTG9ncyB1c2VyIG91dCBmcm9tIHNwZWNpZmllZCBhY2NvdW50cy5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gRXBpY2VudGVyIGxvZ291dCBpcyBub3QgaW1wbGVtZW50ZWQgeWV0LCBzbyBmb3Igbm93IHRoaXMgaXMgYSBkdW1teSBwcm9taXNlIHRoYXQgZ2V0cyBhdXRvbWF0aWNhbGx5IHJlc29sdmVkLlxuICAgICAgICAvL1xuICAgICAgICAvLyAqKkV4YW1wbGUqKlxuICAgICAgICAvL1xuICAgICAgICAvLyAgICAgIGF1dGgubG9nb3V0KCk7XG4gICAgICAgIC8vXG4gICAgICAgIC8vICoqUGFyYW1ldGVycyoqXG4gICAgICAgIC8vIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgLy9cbiAgICAgICAgbG9nb3V0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIGR0ZC5yZXNvbHZlKCk7XG4gICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxuLyoqXG4gKiAjIyBDaGFubmVsIFNlcnZpY2VcbiAqXG4gKiBUaGUgRXBpY2VudGVyIHBsYXRmb3JtIHByb3ZpZGVzIGEgcHVzaCBjaGFubmVsLCB3aGljaCBhbGxvd3MgeW91IHRvIHB1Ymxpc2ggYW5kIHN1YnNjcmliZSB0byBtZXNzYWdlcyB3aXRoaW4gYSBbcHJvamVjdF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3Byb2plY3RzKSwgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSwgb3IgW211bHRpcGxheWVyIHdvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLiBUaGVyZSBhcmUgdHdvIG1haW4gdXNlIGNhc2VzIGZvciB0aGUgY2hhbm5lbDogZXZlbnQgbm90aWZpY2F0aW9ucyBhbmQgY2hhdCBtZXNzYWdlcy5cbiAqXG4gKiBUaGUgQ2hhbm5lbCBTZXJ2aWNlIGlzIGEgYnVpbGRpbmcgYmxvY2sgZm9yIHRoaXMgZnVuY3Rpb25hbGl0eS4gSXQgY3JlYXRlcyBhIHB1Ymxpc2gtc3Vic2NyaWJlIG9iamVjdCwgYWxsb3dpbmcgeW91IHRvIHB1Ymxpc2ggbWVzc2FnZXMsIHN1YnNjcmliZSB0byBtZXNzYWdlcywgb3IgdW5zdWJzY3JpYmUgZnJvbSBtZXNzYWdlcyBmb3IgYSBnaXZlbiAndG9waWMnIG9uIGEgYCQuY29tZXRkYCB0cmFuc3BvcnQgaW5zdGFuY2UuXG4gKlxuICogVHlwaWNhbGx5LCB5b3UgdXNlIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pIHRvIGNyZWF0ZSBvciByZXRyaWV2ZSBjaGFubmVscywgdGhlbiB1c2UgdGhlIENoYW5uZWwgU2VydmljZSBgc3Vic2NyaWJlKClgIGFuZCBgcHVibGlzaCgpYCBtZXRob2RzIHRvIGxpc3RlbiB0byBvciB1cGRhdGUgZGF0YS4gKEZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQgb24gRXBpY2VudGVyJ3MgcHVzaCBjaGFubmVsLCBzZWUgdGhlIGludHJvZHVjdG9yeSBub3RlcyBvbiB0aGUgW1B1c2ggQ2hhbm5lbCBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLykgcGFnZS4pXG4gKlxuICogWW91J2xsIG5lZWQgdG8gaW5jbHVkZSB0aGUgYGVwaWNlbnRlci1tdWx0aXBsYXllci1kZXBlbmRlbmNpZXMuanNgIGxpYnJhcnkgaW4gYWRkaXRpb24gdG8gdGhlIGBlcGljZW50ZXIuanNgIGxpYnJhcnkgaW4geW91ciBwcm9qZWN0IHRvIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlLiBTZWUgW0luY2x1ZGluZyBFcGljZW50ZXIuanNdKC4uLy4uLyNpbmNsdWRlKS5cbiAqXG4gKiBUbyB1c2UgdGhlIENoYW5uZWwgU2VydmljZSwgaW5zdGFudGlhdGUgaXQsIHRoZW4gbWFrZSBjYWxscyB0byBhbnkgb2YgdGhlIG1ldGhvZHMgeW91IG5lZWQuXG4gKlxuICogICAgICAgIHZhciBjcyA9IG5ldyBGLnNlcnZpY2UuQ2hhbm5lbCgpO1xuICogICAgICAgIGNzLnB1Ymxpc2goJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vdmFyaWFibGVzJywgeyBwcmljZTogNTAgfSk7XG4gKlxuICogVGhlIHBhcmFtZXRlcnMgZm9yIGluc3RhbnRpYXRpbmcgYSBDaGFubmVsIFNlcnZpY2UgaW5jbHVkZTpcbiAqXG4gKiAqIGBvcHRpb25zYCBUaGUgb3B0aW9ucyBvYmplY3QgdG8gY29uZmlndXJlIHRoZSBDaGFubmVsIFNlcnZpY2UuXG4gKiAqIGBvcHRpb25zLmJhc2VgIFRoZSBiYXNlIHRvcGljLiBUaGlzIGlzIGFkZGVkIGFzIGEgcHJlZml4IHRvIGFsbCBmdXJ0aGVyIHRvcGljcyB5b3UgcHVibGlzaCBvciBzdWJzY3JpYmUgdG8gd2hpbGUgd29ya2luZyB3aXRoIHRoaXMgQ2hhbm5lbCBTZXJ2aWNlLlxuICogKiBgb3B0aW9ucy50b3BpY1Jlc29sdmVyYCBBIGZ1bmN0aW9uIHRoYXQgcHJvY2Vzc2VzIGFsbCAndG9waWNzJyBwYXNzZWQgaW50byB0aGUgYHB1Ymxpc2hgIGFuZCBgc3Vic2NyaWJlYCBtZXRob2RzLiBUaGlzIGlzIHVzZWZ1bCBpZiB5b3Ugd2FudCB0byBpbXBsZW1lbnQgeW91ciBvd24gc2VyaWFsaXplIGZ1bmN0aW9ucyBmb3IgY29udmVydGluZyBjdXN0b20gb2JqZWN0cyB0byB0b3BpYyBuYW1lcy4gUmV0dXJucyBhIFN0cmluZy4gQnkgZGVmYXVsdCwgaXQganVzdCBlY2hvZXMgdGhlIHRvcGljLlxuICogKiBgb3B0aW9ucy50cmFuc3BvcnRgIFRoZSBpbnN0YW5jZSBvZiBgJC5jb21ldGRgIHRvIGhvb2sgb250by4gU2VlIGh0dHA6Ly9kb2NzLmNvbWV0ZC5vcmcvcmVmZXJlbmNlL2phdmFzY3JpcHQuaHRtbCBmb3IgYWRkaXRpb25hbCBiYWNrZ3JvdW5kIG9uIGNvbWV0ZC5cbiAqL1xudmFyIENoYW5uZWwgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGJhc2UgdG9waWMuIFRoaXMgaXMgYWRkZWQgYXMgYSBwcmVmaXggdG8gYWxsIGZ1cnRoZXIgdG9waWNzIHlvdSBwdWJsaXNoIG9yIHN1YnNjcmliZSB0byB3aGlsZSB3b3JraW5nIHdpdGggdGhpcyBDaGFubmVsIFNlcnZpY2UuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBiYXNlOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQSBmdW5jdGlvbiB0aGF0IHByb2Nlc3NlcyBhbGwgJ3RvcGljcycgcGFzc2VkIGludG8gdGhlIGBwdWJsaXNoYCBhbmQgYHN1YnNjcmliZWAgbWV0aG9kcy4gVGhpcyBpcyB1c2VmdWwgaWYgeW91IHdhbnQgdG8gaW1wbGVtZW50IHlvdXIgb3duIHNlcmlhbGl6ZSBmdW5jdGlvbnMgZm9yIGNvbnZlcnRpbmcgY3VzdG9tIG9iamVjdHMgdG8gdG9waWMgbmFtZXMuIEJ5IGRlZmF1bHQsIGl0IGp1c3QgZWNob2VzIHRoZSB0b3BpYy5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICpcbiAgICAgICAgICogKiBgdG9waWNgIFRvcGljIHRvIHBhcnNlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICogKlN0cmluZyo6IFRoaXMgZnVuY3Rpb24gc2hvdWxkIHJldHVybiBhIHN0cmluZyB0b3BpYy5cbiAgICAgICAgICpcbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgdG9waWNSZXNvbHZlcjogZnVuY3Rpb24gKHRvcGljKSB7XG4gICAgICAgICAgICByZXR1cm4gdG9waWM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBpbnN0YW5jZSBvZiBgJC5jb21ldGRgIHRvIGhvb2sgb250by5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDogbnVsbFxuICAgIH07XG4gICAgdGhpcy5jaGFubmVsT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgb3B0aW9ucyk7XG59O1xuXG52YXIgbWFrZU5hbWUgPSBmdW5jdGlvbiAoY2hhbm5lbE5hbWUsIHRvcGljKSB7XG4gICAgLy9SZXBsYWNlIHRyYWlsaW5nL2RvdWJsZSBzbGFzaGVzXG4gICAgdmFyIG5ld05hbWUgPSAoY2hhbm5lbE5hbWUgPyAoY2hhbm5lbE5hbWUgKyAnLycgKyB0b3BpYykgOiB0b3BpYykucmVwbGFjZSgvXFwvXFwvL2csICcvJykucmVwbGFjZSgvXFwvJC8sJycpO1xuICAgIHJldHVybiBuZXdOYW1lO1xufTtcblxuXG5DaGFubmVsLnByb3RvdHlwZSA9ICQuZXh0ZW5kKENoYW5uZWwucHJvdG90eXBlLCB7XG5cbiAgICAvLyBmdXR1cmUgZnVuY3Rpb25hbGl0eTpcbiAgICAvLyAgICAgIC8vIFNldCB0aGUgY29udGV4dCBmb3IgdGhlIGNhbGxiYWNrXG4gICAgLy8gICAgICBjcy5zdWJzY3JpYmUoJ3J1bicsIGZ1bmN0aW9uICgpIHsgdGhpcy5pbm5lckhUTUwgPSAnVHJpZ2dlcmVkJ30sIGRvY3VtZW50LmJvZHkpO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIENvbnRyb2wgdGhlIG9yZGVyIG9mIG9wZXJhdGlvbnMgYnkgc2V0dGluZyB0aGUgYHByaW9yaXR5YFxuICAgICAvLyAgICAgIGNzLnN1YnNjcmliZSgncnVuJywgY2IsIHRoaXMsIHtwcmlvcml0eTogOX0pO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIE9ubHkgZXhlY3V0ZSB0aGUgY2FsbGJhY2ssIGBjYmAsIGlmIHRoZSB2YWx1ZSBvZiB0aGUgYHByaWNlYCB2YXJpYWJsZSBpcyA1MFxuICAgICAvLyAgICAgIGNzLnN1YnNjcmliZSgncnVuL3ZhcmlhYmxlcy9wcmljZScsIGNiLCB0aGlzLCB7cHJpb3JpdHk6IDMwLCB2YWx1ZTogNTB9KTtcbiAgICAgLy9cbiAgICAgLy8gICAgICAvLyBPbmx5IGV4ZWN1dGUgdGhlIGNhbGxiYWNrLCBgY2JgLCBpZiB0aGUgdmFsdWUgb2YgdGhlIGBwcmljZWAgdmFyaWFibGUgaXMgZ3JlYXRlciB0aGFuIDUwXG4gICAgIC8vICAgICAgc3Vic2NyaWJlKCdydW4vdmFyaWFibGVzL3ByaWNlJywgY2IsIHRoaXMsIHtwcmlvcml0eTogMzAsIHZhbHVlOiAnPjUwJ30pO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIE9ubHkgZXhlY3V0ZSB0aGUgY2FsbGJhY2ssIGBjYmAsIGlmIHRoZSB2YWx1ZSBvZiB0aGUgYHByaWNlYCB2YXJpYWJsZSBpcyBldmVuXG4gICAgIC8vICAgICAgc3Vic2NyaWJlKCdydW4vdmFyaWFibGVzL3ByaWNlJywgY2IsIHRoaXMsIHtwcmlvcml0eTogMzAsIHZhbHVlOiBmdW5jdGlvbiAodmFsKSB7cmV0dXJuIHZhbCAlIDIgPT09IDB9fSk7XG5cblxuICAgIC8qKlxuICAgICAqIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGEgdG9waWMuXG4gICAgICpcbiAgICAgKiBUaGUgdG9waWMgc2hvdWxkIGluY2x1ZGUgdGhlIGZ1bGwgcGF0aCBvZiB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMpLCBwcm9qZWN0IGlkLCBhbmQgZ3JvdXAgbmFtZS4gKEluIG1vc3QgY2FzZXMsIGl0IGlzIHNpbXBsZXIgdG8gdXNlIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pIGluc3RlYWQsIGluIHdoaWNoIGNhc2UgdGhpcyBpcyBjb25maWd1cmVkIGZvciB5b3UuKVxuICAgICAqXG4gICAgICogICoqRXhhbXBsZXMqKlxuICAgICAqXG4gICAgICogICAgICB2YXIgY2IgPSBmdW5jdGlvbih2YWwpIHsgY29uc29sZS5sb2codmFsLmRhdGEpOyB9O1xuICAgICAqXG4gICAgICogICAgICAvLyBTdWJzY3JpYmUgdG8gY2hhbmdlcyBvbiBhIHRvcC1sZXZlbCAncnVuJyB0b3BpY1xuICAgICAqICAgICAgY3Muc3Vic2NyaWJlKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuJywgY2IpO1xuICAgICAqXG4gICAgICogICAgICAvLyBTdWJzY3JpYmUgdG8gY2hhbmdlcyBvbiBjaGlsZHJlbiBvZiB0aGUgJ3J1bicgdG9waWMuIE5vdGUgdGhpcyB3aWxsIGFsc28gYmUgdHJpZ2dlcmVkIGZvciBjaGFuZ2VzIHRvIHJ1bi54Lnkuei5cbiAgICAgKiAgICAgIGNzLnN1YnNjcmliZSgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi8qJywgY2IpO1xuICAgICAqXG4gICAgICogICAgICAvLyBTdWJzY3JpYmUgdG8gY2hhbmdlcyBvbiBib3RoIHRoZSB0b3AtbGV2ZWwgJ3J1bicgdG9waWMgYW5kIGl0cyBjaGlsZHJlblxuICAgICAqICAgICAgY3Muc3Vic2NyaWJlKFsnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bicsXG4gICAgICogICAgICAgICAgJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vKiddLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGEgcGFydGljdWxhciB2YXJpYWJsZVxuICAgICAqICAgICAgc3Vic2NyaWJlKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuL3ZhcmlhYmxlcy9wcmljZScsIGNiKTtcbiAgICAgKlxuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqU3RyaW5nKiBSZXR1cm5zIGEgdG9rZW4geW91IGNhbiBsYXRlciB1c2UgdG8gdW5zdWJzY3JpYmUuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xBcnJheX0gICBgdG9waWNgICAgIExpc3Qgb2YgdG9waWNzIHRvIGxpc3RlbiBmb3IgY2hhbmdlcyBvbi5cbiAgICAgKiBAcGFyYW0gIHtGdW5jdGlvbn0gYGNhbGxiYWNrYCBDYWxsYmFjayBmdW5jdGlvbiB0byBleGVjdXRlLiBDYWxsYmFjayBpcyBjYWxsZWQgd2l0aCBzaWduYXR1cmUgYChldnQsIHBheWxvYWQsIG1ldGFkYXRhKWAuXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSAgIGBjb250ZXh0YCAgQ29udGV4dCBpbiB3aGljaCB0aGUgYGNhbGxiYWNrYCBpcyBleGVjdXRlZC5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9ICAgYG9wdGlvbnNgICAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqIEBwYXJhbSAge051bWJlcn0gICBgb3B0aW9ucy5wcmlvcml0eWAgIFVzZWQgdG8gY29udHJvbCBvcmRlciBvZiBvcGVyYXRpb25zLiBEZWZhdWx0cyB0byAwLiBDYW4gYmUgYW55ICt2ZSBvciAtdmUgbnVtYmVyLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xOdW1iZXJ8RnVuY3Rpb259ICAgYG9wdGlvbnMudmFsdWVgIFRoZSBgY2FsbGJhY2tgIGlzIG9ubHkgdHJpZ2dlcmVkIGlmIHRoaXMgY29uZGl0aW9uIG1hdGNoZXMuIFNlZSBleGFtcGxlcyBmb3IgZGV0YWlscy5cbiAgICAgKlxuICAgICAqL1xuICAgIHN1YnNjcmliZTogZnVuY3Rpb24gKHRvcGljLCBjYWxsYmFjaywgY29udGV4dCwgb3B0aW9ucykge1xuXG4gICAgICAgIHZhciB0b3BpY3MgPSBbXS5jb25jYXQodG9waWMpO1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICB2YXIgc3Vic2NyaXB0aW9uSWRzID0gW107XG4gICAgICAgIHZhciBvcHRzID0gbWUuY2hhbm5lbE9wdGlvbnM7XG5cbiAgICAgICAgb3B0cy50cmFuc3BvcnQuYmF0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgJC5lYWNoKHRvcGljcywgZnVuY3Rpb24gKGluZGV4LCB0b3BpYykge1xuICAgICAgICAgICAgICAgIHRvcGljID0gbWFrZU5hbWUob3B0cy5iYXNlLCBvcHRzLnRvcGljUmVzb2x2ZXIodG9waWMpKTtcbiAgICAgICAgICAgICAgICBzdWJzY3JpcHRpb25JZHMucHVzaChvcHRzLnRyYW5zcG9ydC5zdWJzY3JpYmUodG9waWMsIGNhbGxiYWNrKSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiAoc3Vic2NyaXB0aW9uSWRzWzFdID8gc3Vic2NyaXB0aW9uSWRzIDogc3Vic2NyaXB0aW9uSWRzWzBdKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUHVibGlzaCBkYXRhIHRvIGEgdG9waWMuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGVzKipcbiAgICAgKlxuICAgICAqICAgICAgLy8gU2VuZCBkYXRhIHRvIGFsbCBzdWJzY3JpYmVycyBvZiB0aGUgJ3J1bicgdG9waWNcbiAgICAgKiAgICAgIGNzLnB1Ymxpc2goJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4nLCB7IGNvbXBsZXRlZDogZmFsc2UgfSk7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFNlbmQgZGF0YSB0byBhbGwgc3Vic2NyaWJlcnMgb2YgdGhlICdydW4vdmFyaWFibGVzJyB0b3BpY1xuICAgICAqICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi92YXJpYWJsZXMnLCB7IHByaWNlOiA1MCB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGB0b3BpY2AgVG9waWMgdG8gcHVibGlzaCB0by5cbiAgICAgKiBAcGFyYW0gIHsqfSBgZGF0YWAgIERhdGEgdG8gcHVibGlzaCB0byB0b3BpYy5cbiAgICAgKlxuICAgICAqL1xuICAgIHB1Ymxpc2g6IGZ1bmN0aW9uICh0b3BpYywgZGF0YSkge1xuICAgICAgICB2YXIgdG9waWNzID0gW10uY29uY2F0KHRvcGljKTtcbiAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgdmFyIHJldHVybk9ianMgPSBbXTtcbiAgICAgICAgdmFyIG9wdHMgPSBtZS5jaGFubmVsT3B0aW9ucztcblxuXG4gICAgICAgIG9wdHMudHJhbnNwb3J0LmJhdGNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICQuZWFjaCh0b3BpY3MsIGZ1bmN0aW9uIChpbmRleCwgdG9waWMpIHtcbiAgICAgICAgICAgICAgICB0b3BpYyA9IG1ha2VOYW1lKG9wdHMuYmFzZSwgb3B0cy50b3BpY1Jlc29sdmVyKHRvcGljKSk7XG4gICAgICAgICAgICAgICAgaWYgKHRvcGljLmNoYXJBdCh0b3BpYy5sZW5ndGggLSAxKSA9PT0gJyonKSB7XG4gICAgICAgICAgICAgICAgICAgIHRvcGljID0gdG9waWMucmVwbGFjZSgvXFwqKyQvLCAnJyk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignWW91IGNhbiBjYW5ub3QgcHVibGlzaCB0byBjaGFubmVscyB3aXRoIHdpbGRjYXJkcy4gUHVibGlzaGluZyB0byAnLCB0b3BpYywgJ2luc3RlYWQnKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuT2Jqcy5wdXNoKG9wdHMudHJhbnNwb3J0LnB1Ymxpc2godG9waWMsIGRhdGEpKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIChyZXR1cm5PYmpzWzFdID8gcmV0dXJuT2JqcyA6IHJldHVybk9ianNbMF0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBVbnN1YnNjcmliZSBmcm9tIGNoYW5nZXMgdG8gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIGNzLnVuc3Vic2NyaWJlKCdzYW1wbGVUb2tlbicpO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGB0b2tlbmAgVGhlIHRva2VuIGZvciB0b3BpYyBpcyByZXR1cm5lZCB3aGVuIHlvdSBpbml0aWFsbHkgc3Vic2NyaWJlLiBQYXNzIGl0IGhlcmUgdG8gdW5zdWJzY3JpYmUgZnJvbSB0aGF0IHRvcGljLlxuICAgICAqL1xuICAgIHVuc3Vic2NyaWJlOiBmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgICAgdGhpcy5jaGFubmVsT3B0aW9ucy50cmFuc3BvcnQudW5zdWJzY3JpYmUodG9rZW4pO1xuICAgICAgICByZXR1cm4gdG9rZW47XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0YXJ0IGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqXG4gICAgICogU3VwcG9ydGVkIGV2ZW50cyBhcmU6IGBjb25uZWN0YCwgYGRpc2Nvbm5lY3RgLCBgc3Vic2NyaWJlYCwgYHVuc3Vic2NyaWJlYCwgYHB1Ymxpc2hgLCBgZXJyb3JgLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29uLy5cbiAgICAgKi9cbiAgICBvbjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub24uYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RvcCBsaXN0ZW5pbmcgZm9yIGV2ZW50cyBvbiB0aGlzIGluc3RhbmNlLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKi9cbiAgICBvZmY6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLm9mZi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUcmlnZ2VyIGV2ZW50cyBhbmQgZXhlY3V0ZSBoYW5kbGVycy4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKi9cbiAgICB0cmlnZ2VyOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBDaGFubmVsO1xuIiwiLyoqXG4gKiBAY2xhc3MgQ29uZmlndXJhdGlvblNlcnZpY2VcbiAqXG4gKiBBbGwgc2VydmljZXMgdGFrZSBpbiBhIGNvbmZpZ3VyYXRpb24gc2V0dGluZ3Mgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGVtc2VsdmVzLiBBIEpTIGhhc2gge30gaXMgYSB2YWxpZCBjb25maWd1cmF0aW9uIG9iamVjdCwgYnV0IG9wdGlvbmFsbHkgeW91IGNhbiB1c2UgdGhlIGNvbmZpZ3VyYXRpb24gc2VydmljZSB0byB0b2dnbGUgY29uZmlncyBiYXNlZCBvbiB0aGUgZW52aXJvbm1lbnRcbiAqXG4gKiBAZXhhbXBsZVxuICogICAgIHZhciBjcyA9IHJlcXVpcmUoJ2NvbmZpZ3VyYXRpb24tc2VydmljZScpKHtcbiAqICAgICAgICAgIGRldjogeyAvL2Vudmlyb25tZW50XG4gICAgICAgICAgICAgICAgcG9ydDogMzAwMCxcbiAgICAgICAgICAgICAgICBob3N0OiAnbG9jYWxob3N0JyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBwcm9kOiB7XG4gICAgICAgICAgICAgICAgcG9ydDogODA4MCxcbiAgICAgICAgICAgICAgICBob3N0OiAnYXBpLmZvcmlvLmNvbScsXG4gICAgICAgICAgICAgICAgbG9nTGV2ZWw6ICdub25lJ1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGxvZ0xldmVsOiAnREVCVUcnIC8vZ2xvYmFsXG4gKiAgICAgfSk7XG4gKlxuICogICAgICBjcy5nZXQoJ2xvZ0xldmVsJyk7IC8vcmV0dXJucyAnREVCVUcnXG4gKlxuICogICAgICBjcy5zZXRFbnYoJ2RldicpO1xuICogICAgICBjcy5nZXQoJ2xvZ0xldmVsJyk7IC8vcmV0dXJucyAnREVCVUcnXG4gKlxuICogICAgICBjcy5zZXRFbnYoJ3Byb2QnKTtcbiAqICAgICAgY3MuZ2V0KCdsb2dMZXZlbCcpOyAvL3JldHVybnMgJ25vbmUnXG4gKlxuICovXG5cbid1c2Ugc3RyaWN0JztcbnZhciB1cmxTZXJ2aWNlID0gcmVxdWlyZSgnLi91cmwtY29uZmlnLXNlcnZpY2UnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgLy9UT0RPOiBFbnZpcm9ubWVudHNcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIGxvZ0xldmVsOiAnTk9ORSdcbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICBzZXJ2aWNlT3B0aW9ucy5zZXJ2ZXIgPSB1cmxTZXJ2aWNlKHNlcnZpY2VPcHRpb25zLnNlcnZlcik7XG5cbiAgICByZXR1cm4ge1xuXG4gICAgICAgIGRhdGE6IHNlcnZpY2VPcHRpb25zLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgdGhlIGVudmlyb25tZW50IGtleSB0byBnZXQgY29uZmlndXJhdGlvbiBvcHRpb25zIGZyb21cbiAgICAgICAgICogQHBhcmFtIHsgc3RyaW5nfSBlbnZcbiAgICAgICAgICovXG4gICAgICAgIHNldEVudjogZnVuY3Rpb24gKGVudikge1xuXG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBjb25maWd1cmF0aW9uLlxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfSBwcm9wZXJ0eSBvcHRpb25hbFxuICAgICAgICAgKiBAcmV0dXJuIHsqfSAgICAgICAgICBWYWx1ZSBvZiBwcm9wZXJ0eSBpZiBzcGVjaWZpZWQsIHRoZSBlbnRpcmUgY29uZmlnIG9iamVjdCBvdGhlcndpc2VcbiAgICAgICAgICovXG4gICAgICAgIGdldDogZnVuY3Rpb24gKHByb3BlcnR5KSB7XG4gICAgICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnNbcHJvcGVydHldO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgY29uZmlndXJhdGlvbi5cbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xPYmplY3R9IGtleSBpZiBhIGtleSBpcyBwcm92aWRlZCwgc2V0IGEga2V5IHRvIHRoYXQgdmFsdWUuIE90aGVyd2lzZSBtZXJnZSBvYmplY3Qgd2l0aCBjdXJyZW50IGNvbmZpZ1xuICAgICAgICAgKiBAcGFyYW0gIHsqfSB2YWx1ZSAgdmFsdWUgZm9yIHByb3ZpZGVkIGtleVxuICAgICAgICAgKi9cbiAgICAgICAgc2V0OiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnNba2V5XSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfTtcbn07XG5cbiIsIi8qKlxuICogIyMgRGF0YSBBUEkgU2VydmljZVxuICpcbiAqIFRoZSBEYXRhIEFQSSBTZXJ2aWNlIGFsbG93cyB5b3UgdG8gY3JlYXRlLCBhY2Nlc3MsIGFuZCBtYW5pcHVsYXRlIGRhdGEgcmVsYXRlZCB0byBhbnkgb2YgeW91ciBwcm9qZWN0cy4gRGF0YSBhcmUgb3JnYW5pemVkIGluIGNvbGxlY3Rpb25zLiBFYWNoIGNvbGxlY3Rpb24gY29udGFpbnMgYSBkb2N1bWVudDsgZWFjaCBlbGVtZW50IG9mIHRoaXMgdG9wLWxldmVsIGRvY3VtZW50IGlzIGEgSlNPTiBvYmplY3QuIChTZWUgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBvbiB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pLilcbiAqXG4gKiBBbGwgQVBJIGNhbGxzIHRha2UgaW4gYW4gXCJvcHRpb25zXCIgb2JqZWN0IGFzIHRoZSBsYXN0IHBhcmFtZXRlci4gVGhlIG9wdGlvbnMgY2FuIGJlIHVzZWQgdG8gZXh0ZW5kL292ZXJyaWRlIHRoZSBEYXRhIEFQSSBTZXJ2aWNlIGRlZmF1bHRzLiBJbiBwYXJ0aWN1bGFyLCB0aGVyZSBhcmUgdGhyZWUgcmVxdWlyZWQgcGFyYW1ldGVycyB3aGVuIHlvdSBpbnN0YW50aWF0ZSB0aGUgRGF0YSBTZXJ2aWNlOlxuICpcbiAqICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gKiAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4gKiAqIGByb290YDogVGhlIHRoZSBuYW1lIG9mIHRoZSBjb2xsZWN0aW9uLiBJZiB5b3UgaGF2ZSBtdWx0aXBsZSBjb2xsZWN0aW9ucyB3aXRoaW4gZWFjaCBvZiB5b3VyIHByb2plY3RzLCB5b3UgY2FuIGFsc28gcGFzcyB0aGUgY29sbGVjdGlvbiBuYW1lIGFzIGFuIG9wdGlvbiBmb3IgZWFjaCBjYWxsLlxuICpcbiAqICAgICAgIHZhciBkcyA9IG5ldyBGLnNlcnZpY2UuRGF0YSh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgcm9vdDogJ3N1cnZleS1yZXNwb25zZXMnLFxuICogICAgICAgICAgc2VydmVyOiB7IGhvc3Q6ICdhcGkuZm9yaW8uY29tJyB9XG4gKiAgICAgICB9KTtcbiAqICAgICAgIGRzLnNhdmVBcygndXNlcjEnLFxuICogICAgICAgICAgeyAncXVlc3Rpb24xJzogMiwgJ3F1ZXN0aW9uMic6IDEwLFxuICogICAgICAgICAgJ3F1ZXN0aW9uMyc6IGZhbHNlLCAncXVlc3Rpb240JzogJ3NvbWV0aW1lcycgfSApO1xuICogICAgICAgZHMuc2F2ZUFzKCd1c2VyMicsXG4gKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAzLCAncXVlc3Rpb24yJzogOCxcbiAqICAgICAgICAgICdxdWVzdGlvbjMnOiB0cnVlLCAncXVlc3Rpb240JzogJ2Fsd2F5cycgfSApO1xuICogICAgICAgZHMucXVlcnkoJycseyAncXVlc3Rpb24yJzogeyAnJGd0JzogOX0gfSk7XG4gKlxuICogTm90ZSB0aGF0IGluIGFkZGl0aW9uIHRvIHRoZSBgYWNjb3VudGAsIGBwcm9qZWN0YCwgYW5kIGByb290YCwgdGhlIERhdGEgU2VydmljZSBwYXJhbWV0ZXJzIG9wdGlvbmFsbHkgaW5jbHVkZSBhIGBzZXJ2ZXJgIG9iamVjdCwgd2hvc2UgYGhvc3RgIGZpZWxkIGNvbnRhaW5zIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBOYW1lIG9mIGNvbGxlY3Rpb24uIERlZmF1bHRzIHRvIGAvYCwgdGhhdCBpcywgdGhlIHJvb3QgbGV2ZWwgb2YgeW91ciBwcm9qZWN0IGF0IGBmb3Jpby5jb20vYXBwL3lvdXItYWNjb3VudC1pZC95b3VyLXByb2plY3QtaWQvYC4gUmVxdWlyZWQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICByb290OiAnLycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBvcGVyYXRpb25zIHRoYXQgcmVxdWlyZSBhdXRoZW50aWNhdGlvbiwgcGFzcyBpbiB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gKGRlZmF1bHRzIHRvIGVtcHR5IHN0cmluZykuIElmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluIHRvIEVwaWNlbnRlciwgdGhlIHVzZXIgYWNjZXNzIHRva2VuIGlzIGFscmVhZHkgc2V0IGluIGEgY29va2llIGFuZCBhdXRvbWF0aWNhbGx5IGxvYWRlZCBmcm9tIHRoZXJlLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICAgICAqIEBzZWUgW0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXSguLi9hdXRoLWFwaS1zZXJ2aWNlLykgZm9yIGdldHRpbmcgdG9rZW5zLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdG9rZW46IHVuZGVmaW5lZCxcblxuICAgICAgICAvL09wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXJcbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG4gICAgdGhpcy5zZXNzaW9uTWFuYWdlciA9IG5ldyBTZXNzaW9uTWFuYWdlcigpO1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyhkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBnZXRVUkwgPSBmdW5jdGlvbiAoa2V5LCByb290KSB7XG4gICAgICAgIGlmICghcm9vdCkge1xuICAgICAgICAgICAgcm9vdCA9IHNlcnZpY2VPcHRpb25zLnJvb3Q7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVybCA9IHVybENvbmZpZy5nZXRBUElQYXRoKCdkYXRhJykgKyBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKHJvb3QpO1xuICAgICAgICBpZiAoa2V5KSB7XG4gICAgICAgICAgICB1cmwrPSBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKGtleSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IGdldFVSTFxuICAgIH0pO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNlYXJjaCBmb3IgZGF0YSB3aXRoaW4gYSBjb2xsZWN0aW9uLlxuICAgICAgICAgKlxuICAgICAgICAgKiBTZWFyY2hpbmcgdXNpbmcgY29tcGFyaXNvbiBvciBsb2dpY2FsIG9wZXJhdG9ycyAoYXMgb3Bwb3NlZCB0byBleGFjdCBtYXRjaGVzKSByZXF1aXJlcyBNb25nb0RCIHN5bnRheC4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLyNzZWFyY2hpbmcpIGZvciBhZGRpdGlvbmFsIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRhdGEgYXNzb2NpYXRlZCB3aXRoIGRvY3VtZW50ICd1c2VyMSdcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgndXNlcjEnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBleGFjdCBtYXRjaGluZzpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvbiB3aGVyZSAncXVlc3Rpb24yJyBpcyA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IDl9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBjb21wYXJpc29uIG9wZXJhdG9yczpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjInIGlzIGdyZWF0ZXIgdGhhbiA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIGxvZ2ljYWwgb3BlcmF0b3JzOlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRvY3VtZW50cyBpbiBjb2xsZWN0aW9uXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgJ3F1ZXN0aW9uMicgaXMgbGVzcyB0aGFuIDEwLCBhbmQgJ3F1ZXN0aW9uMycgaXMgZmFsc2VcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgnJywgeyAnJGFuZCc6IFsgeyAncXVlc3Rpb24yJzogeyAnJGx0JzoxMH0gfSwgeyAncXVlc3Rpb24zJzogZmFsc2UgfV0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gcmVndWxhciBleHByZXNzc2lvbnM6IHVzZSBhbnkgUGVybC1jb21wYXRpYmxlIHJlZ3VsYXIgZXhwcmVzc2lvbnNcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjUnIGNvbnRhaW5zIHRoZSBzdHJpbmcgJy4qZGF5J1xuICAgICAgICAgKiAgICAgIGRzLnF1ZXJ5KCcnLCB7ICdxdWVzdGlvbjUnOiB7ICckcmVnZXgnOiAnLipkYXknIH0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBga2V5YCBUaGUgbmFtZSBvZiB0aGUgZG9jdW1lbnQgdG8gc2VhcmNoLiBQYXNzIHRoZSBlbXB0eSBzdHJpbmcgKCcnKSB0byBzZWFyY2ggdGhlIGVudGlyZSBjb2xsZWN0aW9uLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHF1ZXJ5YCBUaGUgcXVlcnkgb2JqZWN0LiBGb3IgZXhhY3QgbWF0Y2hpbmcsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCBmaWVsZCB2YWx1ZSB0byBtYXRjaC4gRm9yIG1hdGNoaW5nIGJhc2VkIG9uIGNvbXBhcmlzb24sIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCB0aGUgY29tcGFyaXNvbiBleHByZXNzaW9uLiBGb3IgbWF0Y2hpbmcgYmFzZWQgb24gbG9naWNhbCBvcGVyYXRvcnMsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIGFuIGV4cHJlc3Npb24gdXNpbmcgTW9uZ29EQiBzeW50YXguIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8jc2VhcmNoaW5nKSBmb3IgYWRkaXRpb25hbCBleGFtcGxlcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKlxuICAgICAgICAgKi9cbiAgICAgICAgcXVlcnk6IGZ1bmN0aW9uIChrZXksIHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgcTogcXVlcnkgfSwgb3V0cHV0TW9kaWZpZXIpO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGRhdGEgdG8gYW4gYW5vbnltb3VzIGRvY3VtZW50IHdpdGhpbiB0aGUgY29sbGVjdGlvbi5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmUoJ3F1ZXN0aW9uMScsICd5ZXMnKTtcbiAgICAgICAgICogICAgICBkcy5zYXZlKHtxdWVzdGlvbjE6J3llcycsIHF1ZXN0aW9uMjogMzIgfSk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZSh7IG5hbWU6J0pvaG4nLCBjbGFzc05hbWU6ICdDUzEwMScgfSwgeyByb290OiAnc3R1ZGVudHMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xPYmplY3R9IGBrZXlgIElmIGBrZXlgIGlzIGEgc3RyaW5nLCBpdCBpcyB0aGUgaWQgb2YgdGhlIGVsZW1lbnQgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJZiBga2V5YCBpcyBhbiBvYmplY3QsIHRoZSBvYmplY3QgaXMgdGhlIGRhdGEgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJbiBib3RoIGNhc2VzLCB0aGUgaWQgZm9yIHRoZSBkb2N1bWVudCBpcyBnZW5lcmF0ZWQgYXV0b21hdGljYWxseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGB2YWx1ZWAgKE9wdGlvbmFsKSBUaGUgZGF0YSB0byBzYXZlLiBJZiBga2V5YCBpcyBhIHN0cmluZywgdGhpcyBpcyB0aGUgdmFsdWUgdG8gc2F2ZS4gSWYgYGtleWAgaXMgYW4gb2JqZWN0LCB0aGUgdmFsdWUocykgdG8gc2F2ZSBhcmUgYWxyZWFkeSBwYXJ0IG9mIGBrZXlgIGFuZCB0aGlzIGFyZ3VtZW50IGlzIG5vdCByZXF1aXJlZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZTogZnVuY3Rpb24gKGtleSwgdmFsdWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBhdHRycztcbiAgICAgICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0ga2V5O1xuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSB2YWx1ZTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoJycsIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KGF0dHJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgZGF0YSB0byBhIG5hbWVkIGRvY3VtZW50IG9yIGVsZW1lbnQgd2l0aGluIHRoZSBjb2xsZWN0aW9uLiBUaGUgYHJvb3RgIG9mIHRoZSBjb2xsZWN0aW9uIG11c3QgYmUgc3BlY2lmaWVkIHNlcGFyYXRlbHkgaW4gY29uZmlndXJhdGlvbiBvcHRpb25zLCBlaXRoZXIgYXMgcGFydCBvZiB0aGUgY2FsbCBvciBhcyBwYXJ0IG9mIHRoZSBpbml0aWFsaXphdGlvbiBvZiBkcy5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmVBcygndXNlcjEnLFxuICAgICAgICAgKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAyLCAncXVlc3Rpb24yJzogMTAsXG4gICAgICAgICAqICAgICAgICAgICAncXVlc3Rpb24zJzogZmFsc2UsICdxdWVzdGlvbjQnOiAnc29tZXRpbWVzJyB9ICk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZUFzKCdzdHVkZW50MScsXG4gICAgICAgICAqICAgICAgICAgIHsgZmlyc3ROYW1lOiAnam9obicsIGxhc3ROYW1lOiAnc21pdGgnIH0sXG4gICAgICAgICAqICAgICAgICAgIHsgcm9vdDogJ3N0dWRlbnRzJyB9KTtcbiAgICAgICAgICogICAgICBkcy5zYXZlQXMoJ21nbXQxMDAvZ3JvdXBCJyxcbiAgICAgICAgICogICAgICAgICAgeyBzY2VuYXJpb1llYXI6ICcyMDE1JyB9LFxuICAgICAgICAgKiAgICAgICAgICB7IHJvb3Q6ICdteWNsYXNzZXMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYGtleWAgSWQgb2YgdGhlIGRvY3VtZW50LlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbHVlYCAoT3B0aW9uYWwpIFRoZSBkYXRhIHRvIHNhdmUsIGluIGtleTp2YWx1ZSBwYWlycy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZUFzOiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wdXQodmFsdWUsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGRhdGEgZm9yIGEgc3BlY2lmaWMgZG9jdW1lbnQgb3IgZmllbGQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgZHMubG9hZCgndXNlcjEnKTtcbiAgICAgICAgICogICAgICBkcy5sb2FkKCd1c2VyMS9xdWVzdGlvbjMnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYGtleWAgVGhlIGlkIG9mIHRoZSBkYXRhIHRvIHJldHVybi4gQ2FuIGJlIHRoZSBpZCBvZiBhIGRvY3VtZW50LCBvciBhIHBhdGggdG8gZGF0YSB3aXRoaW4gdGhhdCBkb2N1bWVudC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uIChrZXksIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMudXJsID0gZ2V0VVJMKGtleSwgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQob3V0cHV0TW9kaWZpZXIsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBkYXRhIGZyb20gY29sbGVjdGlvbi4gT25seSBkb2N1bWVudHMgKHRvcC1sZXZlbCBlbGVtZW50cyBpbiBlYWNoIGNvbGxlY3Rpb24pIGNhbiBiZSBkZWxldGVkLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgZHMucmVtb3ZlKCd1c2VyMScpO1xuICAgICAgICAgKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xBcnJheX0gYGtleXNgIFRoZSBpZCBvZiB0aGUgZG9jdW1lbnQgdG8gcmVtb3ZlIGZyb20gdGhpcyBjb2xsZWN0aW9uLCBvciBhbiBhcnJheSBvZiBzdWNoIGlkcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgcmVtb3ZlOiBmdW5jdGlvbiAoa2V5cywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBwYXJhbXM7XG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KGtleXMpKSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBpZDoga2V5cyB9O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSAnJztcbiAgICAgICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoa2V5cywgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUocGFyYW1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFcGljZW50ZXIgZG9lc24ndCBhbGxvdyBudWtpbmcgY29sbGVjdGlvbnNcbiAgICAgICAgLy8gICAgIC8qKlxuICAgICAgICAvLyAgICAgICogUmVtb3ZlcyBjb2xsZWN0aW9uIGJlaW5nIHJlZmVyZW5jZWRcbiAgICAgICAgLy8gICAgICAqIEByZXR1cm4gbnVsbFxuICAgICAgICAvLyAgICAgICovXG4gICAgICAgIC8vICAgICBkZXN0cm95OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvLyAgICAgICAgIHJldHVybiB0aGlzLnJlbW92ZSgnJywgb3B0aW9ucyk7XG4gICAgICAgIC8vICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKlxuICogIyMgR3JvdXAgQVBJIEFkYXB0ZXJcbiAqXG4gKiBUaGUgR3JvdXAgQVBJIEFkYXB0ZXIgcHJvdmlkZXMgbWV0aG9kcyB0byBsb29rIHVwLCBjcmVhdGUsIGNoYW5nZSBvciByZW1vdmUgaW5mb3JtYXRpb24gYWJvdXQgZ3JvdXBzIGluIGEgcHJvamVjdC4gSXQgaXMgYmFzZWQgb24gcXVlcnkgY2FwYWJpbGl0aWVzIG9mIHRoZSB1bmRlcmx5aW5nIFJFU1RmdWwgW0dyb3VwIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL3VzZXJfbWFuYWdlbWVudC9ncm91cC8pLlxuICpcbiAqIFRoaXMgaXMgb25seSBuZWVkZWQgZm9yIEF1dGhlbnRpY2F0ZWQgcHJvamVjdHMsIHRoYXQgaXMsIHRlYW0gcHJvamVjdHMgd2l0aCBbZW5kIHVzZXJzIGFuZCBncm91cHNdKC4uLy4uLy4uL2dyb3Vwc19hbmRfZW5kX3VzZXJzLykuXG4gKlxuICogICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLkdyb3VwKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAqICAgICAgbWEuZ2V0R3JvdXBzRm9yUHJvamVjdCh7IGFjY291bnQ6ICdhY21lJywgcHJvamVjdDogJ3NhbXBsZScgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgc2VydmljZVV0aWxzID0gcmVxdWlyZSgnLi9zZXJ2aWNlLXV0aWxzJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgb2JqZWN0QXNzaWduID0gcmVxdWlyZSgnb2JqZWN0LWFzc2lnbicpO1xuXG52YXIgYXBpRW5kcG9pbnQgPSAnZ3JvdXAvbG9jYWwnO1xuXG52YXIgR3JvdXBTZXJ2aWNlID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciBhY2NvdW50IG5hbWUuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRXBpY2VudGVyIHByb2plY3QgbmFtZS4gRGVmYXVsdHMgdG8gdW5kZWZpbmVkLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcHJvamVjdDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9IHNlcnZpY2VVdGlscy5nZXREZWZhdWx0T3B0aW9ucyhkZWZhdWx0cywgY29uZmlnLCB7IGFwaUVuZHBvaW50OiBhcGlFbmRwb2ludCB9KTtcbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9IHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydDtcbiAgICBkZWxldGUgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0O1xuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucywgc2VydmljZU9wdGlvbnMpO1xuICAgIHZhciBwdWJsaWNBUEkgPSB7XG4gICAgICAgIC8qXG4gICAgICAgICogR2V0cyBpbmZvcm1hdGlvbiBmb3IgYSBncm91cCBvciBtdWx0aXBsZSBncm91cHMuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXNgIHRoZSBncm91cElkIG9mIHRoZSB0YXJnZXQgZ3JvdXBcbiAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHBhcmFtc2Agb2JqZWN0IHdpdGggcXVlcnkgcGFyYW1ldGVyc1xuICAgICAgICAqIEBwYXRhbSB7c3RyaW5nfSBgcGFyYW1zLnFgIHBhcnRpYWwgbWF0Y2ggZm9yIG5hbWUsIG9yZ2FuaXphdGlvbiBvciBldmVudC5cbiAgICAgICAgKiBAcGF0YW0ge3N0cmluZ30gYHBhcmFtcy5hY2NvdW50YCBFcGljZW50ZXIncyBUZWFtIElEXG4gICAgICAgICogQHBhdGFtIHtzdHJpbmd9IGBwYXJhbXMucHJvamVjdGAgRXBpY2VudGVyJ3MgUHJvamVjdCBJRFxuICAgICAgICAqIEBwYXRhbSB7c3RyaW5nfSBgcGFyYW1zLm5hbWVgIEVwaWNlbnRlcidzIEdyb3VwIE5hbWVcbiAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGdldEdyb3VwczogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgLy9ncm91cElEIGlzIHBhcnQgb2YgdGhlIFVSTFxuICAgICAgICAgICAgLy9xLCBhY2NvdW50IGFuZCBwcm9qZWN0IGFyZSBwYXJ0IG9mIHRoZSBxdWVyeSBzdHJpbmdcbiAgICAgICAgICAgIHZhciBmaW5hbE9wdHMgPSBvYmplY3RBc3NpZ24oe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBmaW5hbFBhcmFtcztcbiAgICAgICAgICAgIGlmICh0eXBlb2YgcGFyYW1zID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIGZpbmFsT3B0cy51cmwgPSBzZXJ2aWNlVXRpbHMuZ2V0QXBpVXJsKGFwaUVuZHBvaW50ICsgJy8nICsgcGFyYW1zLCBmaW5hbE9wdHMpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBmaW5hbFBhcmFtcyA9IHBhcmFtcztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaW5hbFBhcmFtcywgZmluYWxPcHRzKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgb2JqZWN0QXNzaWduKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEdyb3VwU2VydmljZTtcbiIsIi8qKlxuICpcbiAqICMjIE1lbWJlciBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBNZW1iZXIgQVBJIEFkYXB0ZXIgcHJvdmlkZXMgbWV0aG9kcyB0byBsb29rIHVwIGluZm9ybWF0aW9uIGFib3V0IGVuZCB1c2VycyBmb3IgeW91ciBwcm9qZWN0IGFuZCBob3cgdGhleSBhcmUgZGl2aWRlZCBhY3Jvc3MgZ3JvdXBzLiBJdCBpcyBiYXNlZCBvbiBxdWVyeSBjYXBhYmlsaXRpZXMgb2YgdGhlIHVuZGVybHlpbmcgUkVTVGZ1bCBbTWVtYmVyIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL3VzZXJfbWFuYWdlbWVudC9tZW1iZXIvKS5cbiAqXG4gKiBUaGlzIGlzIG9ubHkgbmVlZGVkIGZvciBBdXRoZW50aWNhdGVkIHByb2plY3RzLCB0aGF0IGlzLCB0ZWFtIHByb2plY3RzIHdpdGggW2VuZCB1c2VycyBhbmQgZ3JvdXBzXSguLi8uLi8uLi9ncm91cHNfYW5kX2VuZF91c2Vycy8pLiBGb3IgZXhhbXBsZSwgaWYgc29tZSBvZiB5b3VyIGVuZCB1c2VycyBhcmUgZmFjaWxpdGF0b3JzLCBvciBpZiB5b3VyIGVuZCB1c2VycyBzaG91bGQgYmUgdHJlYXRlZCBkaWZmZXJlbnRseSBiYXNlZCBvbiB3aGljaCBncm91cCB0aGV5IGFyZSBpbiwgdXNlIHRoZSBNZW1iZXIgQVBJIHRvIGZpbmQgdGhhdCBpbmZvcm1hdGlvbi5cbiAqXG4gKiAgICAgIHZhciBtYSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAqICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcih7IHVzZXJJZDogJ2I2YjMxM2EzLWFiODQtNDc5Yy1iYWVhLTIwNmY2YmZmMzM3JyB9KTtcbiAqICAgICAgbWEuZ2V0R3JvdXBEZXRhaWxzKHsgZ3JvdXBJZDogJzAwYjUzMzA4LTk4MzMtNDdmMi1iMjFlLTEyNzhjMDdkNTNiOCcgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBhcGlFbmRwb2ludCA9ICdtZW1iZXIvbG9jYWwnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBFcGljZW50ZXIgdXNlciBpZC4gRGVmYXVsdHMgdG8gYSBibGFuayBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1c2VySWQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRXBpY2VudGVyIGdyb3VwIGlkLiBEZWZhdWx0cyB0byBhIGJsYW5rIHN0cmluZy4gTm90ZSB0aGF0IHRoaXMgaXMgdGhlIGdyb3VwICppZCosIG5vdCB0aGUgZ3JvdXAgKm5hbWUqLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZ3JvdXBJZDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMsIHNlcnZpY2VPcHRpb25zKTtcblxuICAgIHZhciBnZXRGaW5hbFBhcmFtcyA9IGZ1bmN0aW9uIChwYXJhbXMpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBwYXJhbXMgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwgc2VydmljZU9wdGlvbnMsIHBhcmFtcyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zO1xuICAgIH07XG5cbiAgICB2YXIgcGF0Y2hVc2VyQWN0aXZlRmllbGQgPSBmdW5jdGlvbiAocGFyYW1zLCBhY3RpdmUsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHtcbiAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcGFyYW1zLmdyb3VwSWQgKyAnLycgKyBwYXJhbXMudXNlcklkXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBodHRwLnBhdGNoKHsgYWN0aXZlOiBhY3RpdmUgfSwgaHR0cE9wdGlvbnMpO1xuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgYWxsIG9mIHRoZSBncm91cCBtZW1iZXJzaGlwcyBmb3Igb25lIGVuZCB1c2VyLiBUaGUgbWVtYmVyc2hpcCBkZXRhaWxzIGFyZSByZXR1cm5lZCBpbiBhbiBhcnJheSwgd2l0aCBvbmUgZWxlbWVudCAoZ3JvdXAgcmVjb3JkKSBmb3IgZWFjaCBncm91cCB0byB3aGljaCB0aGUgZW5kIHVzZXIgYmVsb25ncy5cbiAgICAgICAgKlxuICAgICAgICAqIEluIHRoZSBtZW1iZXJzaGlwIGFycmF5LCBlYWNoIGdyb3VwIHJlY29yZCBpbmNsdWRlcyB0aGUgZ3JvdXAgaWQsIHByb2plY3QgaWQsIGFjY291bnQgKHRlYW0pIGlkLCBhbmQgYW4gYXJyYXkgb2YgbWVtYmVycy4gSG93ZXZlciwgb25seSB0aGUgdXNlciB3aG9zZSB1c2VySWQgaXMgaW5jbHVkZWQgaW4gdGhlIGNhbGwgaXMgbGlzdGVkIGluIHRoZSBtZW1iZXJzIGFycmF5IChyZWdhcmRsZXNzIG9mIHdoZXRoZXIgdGhlcmUgYXJlIG90aGVyIG1lbWJlcnMgaW4gdGhpcyBncm91cCkuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLmdldEdyb3Vwc0ZvclVzZXIoJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKG1lbWJlcnNoaXBzKXtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaTxtZW1iZXJzaGlwcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAqICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKG1lbWJlcnNoaXBzW2ldLmdyb3VwSWQpO1xuICAgICAgICAqICAgICAgICAgICAgICAgfVxuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIG1hLmdldEdyb3Vwc0ZvclVzZXIoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ3xvYmplY3R9IGBwYXJhbXNgIFRoZSB1c2VyIGlkIGZvciB0aGUgZW5kIHVzZXIuIEFsdGVybmF0aXZlbHksIGFuIG9iamVjdCB3aXRoIGZpZWxkIGB1c2VySWRgIGFuZCB2YWx1ZSB0aGUgdXNlciBpZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG5cbiAgICAgICAgZ2V0R3JvdXBzRm9yVXNlcjogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgaXNTdHJpbmcgPSB0eXBlb2YgcGFyYW1zID09PSAnc3RyaW5nJztcbiAgICAgICAgICAgIHZhciBvYmpQYXJhbXMgPSBnZXRGaW5hbFBhcmFtcyhwYXJhbXMpO1xuICAgICAgICAgICAgaWYgKCFpc1N0cmluZyAmJiAhb2JqUGFyYW1zLnVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gdXNlcklkIHNwZWNpZmllZC4nKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGdldFBhcm1zID0gaXNTdHJpbmcgPyB7IHVzZXJJZDogcGFyYW1zIH0gOiBfcGljayhvYmpQYXJhbXMsICd1c2VySWQnKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChnZXRQYXJtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgb25lIGdyb3VwLCBpbmNsdWRpbmcgYW4gYXJyYXkgb2YgYWxsIGl0cyBtZW1iZXJzLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBtYSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAgICAgICAgKiAgICAgICBtYS5nZXRHcm91cERldGFpbHMoJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKGdyb3VwKXtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaTxncm91cC5tZW1iZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coZ3JvdXAubWVtYmVyc1tpXS51c2VyTmFtZSk7XG4gICAgICAgICogICAgICAgICAgICAgICB9XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBEZXRhaWxzKHsgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdH0gYHBhcmFtc2AgVGhlIGdyb3VwIGlkLiBBbHRlcm5hdGl2ZWx5LCBhbiBvYmplY3Qgd2l0aCBmaWVsZCBgZ3JvdXBJZGAgYW5kIHZhbHVlIHRoZSBncm91cCBpZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGdldEdyb3VwRGV0YWlsczogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICB2YXIgaXNTdHJpbmcgPSB0eXBlb2YgcGFyYW1zID09PSAnc3RyaW5nJztcbiAgICAgICAgICAgIHZhciBvYmpQYXJhbXMgPSBnZXRGaW5hbFBhcmFtcyhwYXJhbXMpO1xuICAgICAgICAgICAgaWYgKCFpc1N0cmluZyAmJiAhb2JqUGFyYW1zLmdyb3VwSWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGdyb3VwSWQgc3BlY2lmaWVkLicpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZ3JvdXBJZCA9IGlzU3RyaW5nID8gcGFyYW1zIDogb2JqUGFyYW1zLmdyb3VwSWQ7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBncm91cElkIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldCh7fSwgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFNldCBhIHBhcnRpY3VsYXIgZW5kIHVzZXIgYXMgYGFjdGl2ZWAuIEFjdGl2ZSBlbmQgdXNlcnMgY2FuIGJlIGFzc2lnbmVkIHRvIFt3b3JsZHNdKC4uL3dvcmxkLW1hbmFnZXIvKSBpbiBtdWx0aXBsYXllciBnYW1lcyBkdXJpbmcgYXV0b21hdGljIGFzc2lnbm1lbnQuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLm1ha2VVc2VyQWN0aXZlKHsgdXNlcklkOiAnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwSWQ6ICc4MDI1N2EyNS1hYTEwLTQ5NTktOTY4Yi1mZDA1MzkwMWY3MmYnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgVGhlIGVuZCB1c2VyIGFuZCBncm91cCBpbmZvcm1hdGlvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy51c2VySWRgIFRoZSBpZCBvZiB0aGUgZW5kIHVzZXIgdG8gbWFrZSBhY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZ3JvdXBJZGAgVGhlIGlkIG9mIHRoZSBncm91cCB0byB3aGljaCB0aGlzIGVuZCB1c2VyIGJlbG9uZ3MsIGFuZCBpbiB3aGljaCB0aGUgZW5kIHVzZXIgc2hvdWxkIGJlY29tZSBhY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBtYWtlVXNlckFjdGl2ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHBhdGNoVXNlckFjdGl2ZUZpZWxkKHBhcmFtcywgdHJ1ZSwgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogU2V0IGEgcGFydGljdWxhciBlbmQgdXNlciBhcyBgaW5hY3RpdmVgLiBJbmFjdGl2ZSBlbmQgdXNlcnMgYXJlIG5vdCBhc3NpZ25lZCB0byBbd29ybGRzXSguLi93b3JsZC1tYW5hZ2VyLykgaW4gbXVsdGlwbGF5ZXIgZ2FtZXMgZHVyaW5nIGF1dG9tYXRpYyBhc3NpZ25tZW50LlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBtYSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAgICAgICAgKiAgICAgICBtYS5tYWtlVXNlckluYWN0aXZlKHsgdXNlcklkOiAnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwSWQ6ICc4MDI1N2EyNS1hYTEwLTQ5NTktOTY4Yi1mZDA1MzkwMWY3MmYnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgVGhlIGVuZCB1c2VyIGFuZCBncm91cCBpbmZvcm1hdGlvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy51c2VySWRgIFRoZSBpZCBvZiB0aGUgZW5kIHVzZXIgdG8gbWFrZSBpbmFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5ncm91cElkYCBUaGUgaWQgb2YgdGhlIGdyb3VwIHRvIHdoaWNoIHRoaXMgZW5kIHVzZXIgYmVsb25ncywgYW5kIGluIHdoaWNoIHRoZSBlbmQgdXNlciBzaG91bGQgYmVjb21lIGluYWN0aXZlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgbWFrZVVzZXJJbmFjdGl2ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHBhdGNoVXNlckFjdGl2ZUZpZWxkKHBhcmFtcywgZmFsc2UsIG9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKlxuICogIyMgUnVuIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhlIFJ1biBBUEkgU2VydmljZSBhbGxvd3MgeW91IHRvIHBlcmZvcm0gY29tbW9uIHRhc2tzIGFyb3VuZCBjcmVhdGluZyBhbmQgdXBkYXRpbmcgcnVucywgdmFyaWFibGVzLCBhbmQgZGF0YS5cbiAqXG4gKiBXaGVuIGJ1aWxkaW5nIGludGVyZmFjZXMgdG8gc2hvdyBydW4gb25lIGF0IGEgdGltZSAoYXMgZm9yIHN0YW5kYXJkIGVuZCB1c2VycyksIHR5cGljYWxseSB5b3UgZmlyc3QgaW5zdGFudGlhdGUgYSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyLykgYW5kIHRoZW4gYWNjZXNzIHRoZSBSdW4gU2VydmljZSB0aGF0IGlzIGF1dG9tYXRpY2FsbHkgcGFydCBvZiB0aGUgbWFuYWdlciwgcmF0aGVyIHRoYW4gaW5zdGFudGlhdGluZyB0aGUgUnVuIFNlcnZpY2UgZGlyZWN0bHkuIFRoaXMgaXMgYmVjYXVzZSB0aGUgUnVuIE1hbmFnZXIgZ2l2ZXMgeW91IGNvbnRyb2wgb3ZlciBydW4gY3JlYXRpb24gZGVwZW5kaW5nIG9uIHJ1biBzdGF0ZXMuXG4gKlxuICogSG93ZXZlciwgbWFueSBvZiB0aGUgRXBpY2VudGVyIHNhbXBsZSBwcm9qZWN0cyB1c2UgYSBSdW4gU2VydmljZSwgYmVjYXVzZSBnZW5lcmFsbHkgdGhlIHNhbXBsZSBwcm9qZWN0cyBhcmUgcGxheWVkIGluIG9uZSBlbmQgdXNlciBzZXNzaW9uIGFuZCBkb24ndCBjYXJlIGFib3V0IHJ1biBzdGF0ZXMgb3IgW3J1biBzdHJhdGVnaWVzXSguLi8uLi9zdHJhdGVneS8pLiBUaGUgUnVuIEFQSSBTZXJ2aWNlIGlzIGFsc28gdXNlZnVsIGZvciBidWlsZGluZyBhbiBpbnRlcmZhY2UgZm9yIGEgZmFjaWxpdGF0b3IsIGJlY2F1c2UgaXQgbWFrZXMgaXQgZWFzeSB0byBsaXN0IGRhdGEgYWNyb3NzIG11bHRpcGxlIHJ1bnMgKHVzaW5nIHRoZSBgZmlsdGVyKClgIGFuZCBgcXVlcnkoKWAgbWV0aG9kcykuXG4gKlxuICogVG8gdXNlIHRoZSBSdW4gQVBJIFNlcnZpY2UsIGluc3RhbnRpYXRlIGl0IGJ5IHBhc3NpbmcgaW46XG4gKlxuICogKiBgYWNjb3VudGA6IEVwaWNlbnRlciBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBmb3IgdGVhbSBwcm9qZWN0cywgKipVc2VyIElEKiogZm9yIHBlcnNvbmFsIHByb2plY3RzKS5cbiAqICogYHByb2plY3RgOiBFcGljZW50ZXIgcHJvamVjdCBpZC5cbiAqXG4gKiBGb3IgZXhhbXBsZSxcbiAqXG4gKiAgICAgICB2YXIgcnMgPSBuZXcgRi5zZXJ2aWNlLlJ1bih7XG4gKiAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgfSk7XG4gKiAgICAgIHJzLmNyZWF0ZSgnc3VwcGx5X2NoYWluX2dhbWUucHknKS50aGVuKGZ1bmN0aW9uKHJ1bikge1xuICogICAgICAgICAgICAgcnMuZG8oJ3NvbWVPcGVyYXRpb24nKTtcbiAqICAgICAgfSk7XG4gKlxuICpcbiAqIEFkZGl0aW9uYWxseSwgYWxsIEFQSSBjYWxscyB0YWtlIGluIGFuIFwib3B0aW9uc1wiIG9iamVjdCBhcyB0aGUgbGFzdCBwYXJhbWV0ZXIuIFRoZSBvcHRpb25zIGNhbiBiZSB1c2VkIHRvIGV4dGVuZC9vdmVycmlkZSB0aGUgUnVuIEFQSSBTZXJ2aWNlIGRlZmF1bHRzIGxpc3RlZCBiZWxvdy5cbiAqXG4gKiBOb3RlIHRoYXQgaW4gYWRkaXRpb24gdG8gdGhlIGBhY2NvdW50YCwgYHByb2plY3RgLCBhbmQgYG1vZGVsYCwgdGhlIFJ1biBTZXJ2aWNlIHBhcmFtZXRlcnMgb3B0aW9uYWxseSBpbmNsdWRlIGEgYHNlcnZlcmAgb2JqZWN0LCB3aG9zZSBgaG9zdGAgZmllbGQgY29udGFpbnMgdGhlIFVSSSBvZiB0aGUgRm9yaW8gc2VydmVyLiBUaGlzIGlzIGF1dG9tYXRpY2FsbHkgc2V0LCBidXQgeW91IGNhbiBwYXNzIGl0IGV4cGxpY2l0bHkgaWYgZGVzaXJlZC4gSXQgaXMgbW9zdCBjb21tb25seSB1c2VkIGZvciBjbGFyaXR5IHdoZW4geW91IGFyZSBbaG9zdGluZyBhbiBFcGljZW50ZXIgcHJvamVjdCBvbiB5b3VyIG93biBzZXJ2ZXJdKC4uLy4uLy4uL2hvd190by9zZWxmX2hvc3RpbmcvKS5cbiAqXG4gKiAgICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuICogICAgICAgICAgIHJ1bjoge1xuICogICAgICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5X2NoYWluX2dhbWUucHknLFxuICogICAgICAgICAgICAgICBzZXJ2ZXI6IHsgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH1cbiAqICAgICAgICAgICB9XG4gKiAgICAgICB9KTtcbiAqICAgICAgIHJtLmdldFJ1bigpXG4gKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24ocnVuKSB7XG4gKiAgICAgICAgICAgICAgIC8vIHRoZSBSdW5NYW5hZ2VyLnJ1biBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFJ1biBTZXJ2aWNlLFxuICogICAgICAgICAgICAgICAvLyBzbyBhbnkgUnVuIFNlcnZpY2UgbWV0aG9kIGlzIHZhbGlkIGhlcmVcbiAqICAgICAgICAgICAgICAgdmFyIHJzID0gcm0ucnVuO1xuICogICAgICAgICAgICAgICBycy5kbygnc29tZU9wZXJhdGlvbicpO1xuICogICAgICAgfSlcbiAqXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBydXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcnVuLXV0aWwnKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBWYXJpYWJsZXNTZXJ2aWNlID0gcmVxdWlyZSgnLi92YXJpYWJsZXMtYXBpLXNlcnZpY2UnKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcHJvamVjdCBpZC4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcHJvamVjdDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDcml0ZXJpYSBieSB3aGljaCB0byBmaWx0ZXIgcnVucy4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZmlsdGVyOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVuaWVuY2UgYWxpYXMgZm9yIGZpbHRlci5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGlkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRmxhZyBkZXRlcm1pbmVzIGlmIGBYLUF1dG9SZXN0b3JlOiB0cnVlYCBoZWFkZXIgaXMgc2VudCB0byBFcGljZW50ZXIuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBhdXRvUmVzdG9yZTogdHJ1ZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgY29tcGxldGVzIHN1Y2Nlc3NmdWxseS4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIHN1Y2Nlc3M6ICQubm9vcCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgZmFpbHMuIERlZmF1bHRzIHRvIGAkLm5vb3BgLlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICBlcnJvcjogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdGhpcy5zZXNzaW9uTWFuYWdlciA9IG5ldyBTZXNzaW9uTWFuYWdlcigpO1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyhkZWZhdWx0cywgY29uZmlnKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuaWQpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gc2VydmljZU9wdGlvbnMuaWQ7XG4gICAgfVxuXG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHVybENvbmZpZy5hY2NvdW50UGF0aCA9IHNlcnZpY2VPcHRpb25zLmFjY291bnQ7XG4gICAgfVxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHVybENvbmZpZy5wcm9qZWN0UGF0aCA9IHNlcnZpY2VPcHRpb25zLnByb2plY3Q7XG4gICAgfVxuXG4gICAgdXJsQ29uZmlnLmZpbHRlciA9ICc7JztcbiAgICB1cmxDb25maWcuZ2V0RmlsdGVyVVJMID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgdXJsID0gdXJsQ29uZmlnLmdldEFQSVBhdGgoJ3J1bicpO1xuICAgICAgICB2YXIgZmlsdGVyID0gcXV0aWwudG9NYXRyaXhGb3JtYXQoc2VydmljZU9wdGlvbnMuZmlsdGVyKTtcblxuICAgICAgICBpZiAoZmlsdGVyKSB7XG4gICAgICAgICAgICB1cmwgKz0gZmlsdGVyICsgJy8nO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB1cmw7XG4gICAgfTtcblxuICAgIHVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBmaWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5maWx0ZXI7XG4gICAgICAgIC8vIFRoZSBzZW1pY29sb24gc2VwYXJhdGVkIGZpbHRlciBpcyB1c2VkIHdoZW4gZmlsdGVyIGlzIGFuIG9iamVjdFxuICAgICAgICB2YXIgaXNGaWx0ZXJSdW5JZCA9IGZpbHRlciAmJiAkLnR5cGUoZmlsdGVyKSA9PT0gJ3N0cmluZyc7XG4gICAgICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5hdXRvUmVzdG9yZSAmJiBpc0ZpbHRlclJ1bklkKSB7XG4gICAgICAgICAgICAvLyBCeSBkZWZhdWx0IGF1dG9yZXBsYXkgdGhlIHJ1biBieSBzZW5kaW5nIHRoaXMgaGVhZGVyIHRvIGVwaWNlbnRlclxuICAgICAgICAgICAgLy8gaHR0cHM6Ly9mb3Jpby5jb20vZXBpY2VudGVyL2RvY3MvcHVibGljL3Jlc3RfYXBpcy9hZ2dyZWdhdGVfcnVuX2FwaS8jcmV0cmlldmluZ1xuICAgICAgICAgICAgdmFyIGF1dG9yZXN0b3JlT3B0cyA9IHtcbiAgICAgICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgICAgICdYLUF1dG9SZXN0b3JlJzogdHJ1ZVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwgYXV0b3Jlc3RvcmVPcHRzLCBvcHRpb25zKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBvcHRpb25zO1xuICAgIH07XG5cbiAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEZpbHRlclVSTFxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIGh0dHBPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkoaHR0cE9wdGlvbnMpO1xuICAgIGh0dHAuc3BsaXRHZXQgPSBydXRpbC5zcGxpdEdldEZhY3RvcnkoaHR0cE9wdGlvbnMpO1xuXG4gICAgdmFyIHNldEZpbHRlck9yVGhyb3dFcnJvciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGlmIChvcHRpb25zLmlkKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmlkO1xuICAgICAgICB9XG4gICAgICAgIGlmIChvcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gb3B0aW9ucy5maWx0ZXI7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gZmlsdGVyIHNwZWNpZmllZCB0byBhcHBseSBvcGVyYXRpb25zIGFnYWluc3QnKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcHVibGljQXN5bmNBUEkgPSB7XG4gICAgICAgIHVybENvbmZpZzogdXJsQ29uZmlnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDcmVhdGUgYSBuZXcgcnVuLlxuICAgICAgICAgKlxuICAgICAgICAgKiBOT1RFOiBUeXBpY2FsbHkgdGhpcyBpcyBub3QgdXNlZCEgVXNlIGBSdW5NYW5hZ2VyLmdldFJ1bigpYCB3aXRoIGEgYHN0cmF0ZWd5YCBvZiBgYWx3YXlzLW5ld2AsIG9yIHVzZSBgUnVuTWFuYWdlci5yZXNldCgpYC4gU2VlIFtSdW4gTWFuYWdlcl0oLi4vcnVuLW1hbmFnZXIvKSBmb3IgbW9yZSBkZXRhaWxzLlxuICAgICAgICAgKlxuICAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICBycy5jcmVhdGUoJ2hlbGxvX3dvcmxkLmpsJyk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xPYmplY3R9IGBwYXJhbXNgIElmIGEgc3RyaW5nLCB0aGUgbmFtZSBvZiB0aGUgcHJpbWFyeSBbbW9kZWwgZmlsZV0oLi4vLi4vLi4vd3JpdGluZ195b3VyX21vZGVsLykuIFRoaXMgaXMgdGhlIG9uZSBmaWxlIGluIHRoZSBwcm9qZWN0IHRoYXQgZXhwbGljaXRseSBleHBvc2VzIHZhcmlhYmxlcyBhbmQgbWV0aG9kcywgYW5kIGl0IG11c3QgYmUgc3RvcmVkIGluIHRoZSBNb2RlbCBmb2xkZXIgb2YgeW91ciBFcGljZW50ZXIgcHJvamVjdC4gSWYgYW4gb2JqZWN0LCBtYXkgaW5jbHVkZSBgbW9kZWxgLCBgc2NvcGVgLCBhbmQgYGZpbGVzYC4gKFNlZSB0aGUgW1J1biBNYW5hZ2VyXSguLi9ydW5fbWFuYWdlci8pIGZvciBtb3JlIGluZm9ybWF0aW9uIG9uIGBzY29wZWAgYW5kIGBmaWxlc2AuKVxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqXG4gICAgICAgICAqL1xuICAgICAgICBjcmVhdGU6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBjcmVhdGVPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zLCB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ3J1bicpIH0pO1xuICAgICAgICAgICAgdmFyIHJ1bkFwaVBhcmFtcyA9IFsnbW9kZWwnLCAnc2NvcGUnLCAnZmlsZXMnXTtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgcGFyYW1zID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIC8vIHRoaXMgaXMganVzdCB0aGUgbW9kZWwgbmFtZVxuICAgICAgICAgICAgICAgIHBhcmFtcyA9IHsgbW9kZWw6IHBhcmFtcyB9O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyB3aGl0ZWxpc3QgdGhlIGZpZWxkcyB0aGF0IHdlIGFjdHVhbGx5IGNhbiBzZW5kIHRvIHRoZSBhcGlcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIHJ1bkFwaVBhcmFtcyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBvbGRTdWNjZXNzID0gY3JlYXRlT3B0aW9ucy5zdWNjZXNzO1xuICAgICAgICAgICAgY3JlYXRlT3B0aW9ucy5zdWNjZXNzID0gZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gcmVzcG9uc2UuaWQ7IC8vYWxsIGZ1dHVyZSBjaGFpbmVkIGNhbGxzIHRvIG9wZXJhdGUgb24gdGhpcyBpZFxuICAgICAgICAgICAgICAgIHJldHVybiBvbGRTdWNjZXNzLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgY3JlYXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJldHVybnMgcGFydGljdWxhciBydW5zLCBiYXNlZCBvbiBjb25kaXRpb25zIHNwZWNpZmllZCBpbiB0aGUgYHFzYCBvYmplY3QuXG4gICAgICAgICAqXG4gICAgICAgICAqIFRoZSBlbGVtZW50cyBvZiB0aGUgYHFzYCBvYmplY3QgYXJlIEFORGVkIHRvZ2V0aGVyIHdpdGhpbiBhIHNpbmdsZSBjYWxsIHRvIGAucXVlcnkoKWAuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gcmV0dXJucyBydW5zIHdpdGggc2F2ZWQgPSB0cnVlIGFuZCB2YXJpYWJsZXMucHJpY2UgPiAxLFxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlIHZhcmlhYmxlcy5wcmljZSBoYXMgYmVlbiBwZXJzaXN0ZWQgKHJlY29yZGVkKVxuICAgICAgICAgKiAgICAgIC8vIGluIHRoZSBtb2RlbC5cbiAgICAgICAgICogICAgIHJzLnF1ZXJ5KHtcbiAgICAgICAgICogICAgICAgICAgJ3NhdmVkJzogJ3RydWUnLFxuICAgICAgICAgKiAgICAgICAgICAnLnByaWNlJzogJz4xJ1xuICAgICAgICAgKiAgICAgICB9LFxuICAgICAgICAgKiAgICAgICB7XG4gICAgICAgICAqICAgICAgICAgIHN0YXJ0cmVjb3JkOiAyLFxuICAgICAgICAgKiAgICAgICAgICBlbmRyZWNvcmQ6IDVcbiAgICAgICAgICogICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgcXNgIFF1ZXJ5IG9iamVjdC4gRWFjaCBrZXkgY2FuIGJlIGEgcHJvcGVydHkgb2YgdGhlIHJ1biBvciB0aGUgbmFtZSBvZiB2YXJpYWJsZSB0aGF0IGhhcyBiZWVuIHNhdmVkIGluIHRoZSBydW4gKHByZWZhY2VkIGJ5IGB2YXJpYWJsZXMuYCkuIEVhY2ggdmFsdWUgY2FuIGJlIGEgbGl0ZXJhbCB2YWx1ZSwgb3IgYSBjb21wYXJpc29uIG9wZXJhdG9yIGFuZCB2YWx1ZS4gKFNlZSBbbW9yZSBvbiBmaWx0ZXJpbmddKC4uLy4uLy4uL3Jlc3RfYXBpcy9hZ2dyZWdhdGVfcnVuX2FwaS8jZmlsdGVycykgYWxsb3dlZCBpbiB0aGUgdW5kZXJseWluZyBSdW4gQVBJLikgUXVlcnlpbmcgZm9yIHZhcmlhYmxlcyBpcyBhdmFpbGFibGUgZm9yIHJ1bnMgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgYW5kIGZvciBydW5zIFtpbiB0aGUgZGF0YWJhc2VdKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpIGlmIHRoZSB2YXJpYWJsZXMgYXJlIHBlcnNpc3RlZCAoZS5nLiB0aGF0IGhhdmUgYmVlbiBgcmVjb3JkYGVkIGluIHlvdXIgSnVsaWEgbW9kZWwpLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG91dHB1dE1vZGlmaWVyYCAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBxdWVyeTogZnVuY3Rpb24gKHFzLCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gcXM7IC8vc2hvdWxkbid0IGJlIGFibGUgdG8gb3Zlci1yaWRlXG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMgPSB1cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5zcGxpdEdldChvdXRwdXRNb2RpZmllciwgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZXR1cm5zIHBhcnRpY3VsYXIgcnVucywgYmFzZWQgb24gY29uZGl0aW9ucyBzcGVjaWZpZWQgaW4gdGhlIGBxc2Agb2JqZWN0LlxuICAgICAgICAgKlxuICAgICAgICAgKiBTaW1pbGFyIHRvIGAucXVlcnkoKWAuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgZmlsdGVyYCBGaWx0ZXIgb2JqZWN0LiBFYWNoIGtleSBjYW4gYmUgYSBwcm9wZXJ0eSBvZiB0aGUgcnVuIG9yIHRoZSBuYW1lIG9mIHZhcmlhYmxlIHRoYXQgaGFzIGJlZW4gc2F2ZWQgaW4gdGhlIHJ1biAocHJlZmFjZWQgYnkgYHZhcmlhYmxlcy5gKS4gRWFjaCB2YWx1ZSBjYW4gYmUgYSBsaXRlcmFsIHZhbHVlLCBvciBhIGNvbXBhcmlzb24gb3BlcmF0b3IgYW5kIHZhbHVlLiAoU2VlIFttb3JlIG9uIGZpbHRlcmluZ10oLi4vLi4vLi4vcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNmaWx0ZXJzKSBhbGxvd2VkIGluIHRoZSB1bmRlcmx5aW5nIFJ1biBBUEkuKSBGaWx0ZXJpbmcgZm9yIHZhcmlhYmxlcyBpcyBhdmFpbGFibGUgZm9yIHJ1bnMgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgYW5kIGZvciBydW5zIFtpbiB0aGUgZGF0YWJhc2VdKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpIGlmIHRoZSB2YXJpYWJsZXMgYXJlIHBlcnNpc3RlZCAoZS5nLiB0aGF0IGhhdmUgYmVlbiBgcmVjb3JkYGVkIGluIHlvdXIgSnVsaWEgbW9kZWwpLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG91dHB1dE1vZGlmaWVyYCAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBmaWx0ZXI6IGZ1bmN0aW9uIChmaWx0ZXIsIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHNlcnZpY2VPcHRpb25zLmZpbHRlcikpIHtcbiAgICAgICAgICAgICAgICAkLmV4dGVuZChzZXJ2aWNlT3B0aW9ucy5maWx0ZXIsIGZpbHRlcik7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IGZpbHRlcjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucyA9IHVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlcihodHRwT3B0aW9ucyk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5zcGxpdEdldChvdXRwdXRNb2RpZmllciwgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgZGF0YSBmb3IgYSBzcGVjaWZpYyBydW4uIFRoaXMgaW5jbHVkZXMgc3RhbmRhcmQgcnVuIGRhdGEgc3VjaCBhcyB0aGUgYWNjb3VudCwgbW9kZWwsIHByb2plY3QsIGFuZCBjcmVhdGVkIGFuZCBsYXN0IG1vZGlmaWVkIGRhdGVzLiBUbyByZXF1ZXN0IHNwZWNpZmljIG1vZGVsIHZhcmlhYmxlcywgcGFzcyB0aGVtIGFzIHBhcnQgb2YgdGhlIGBmaWx0ZXJzYCBwYXJhbWV0ZXIuXG4gICAgICAgICAqXG4gICAgICAgICAqIE5vdGUgdGhhdCBpZiB0aGUgcnVuIGlzIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLCBhbnkgbW9kZWwgdmFyaWFibGVzIGFyZSBhdmFpbGFibGU7IGlmIHRoZSBydW4gaXMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLWRiKSwgb25seSBtb2RlbCB2YXJpYWJsZXMgdGhhdCBoYXZlIGJlZW4gcGVyc2lzdGVkICZtZGFzaDsgdGhhdCBpcywgYHJlY29yZGBlZCBpbiB5b3VyIEp1bGlhIG1vZGVsICZtZGFzaDsgYXJlIGF2YWlsYWJsZS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgIHJzLmxvYWQoJ2JiNTg5Njc3LWQ0NzYtNDk3MS1hNjhlLTBjNThkMTkxZTQ1MCcsIHsgaW5jbHVkZTogWycucHJpY2UnLCAnLnNhbGVzJ10gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgcnVuSURgIFRoZSBydW4gaWQuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgZmlsdGVyc2AgKE9wdGlvbmFsKSBPYmplY3QgY29udGFpbmluZyBmaWx0ZXJzIGFuZCBvcGVyYXRpb24gbW9kaWZpZXJzLiBVc2Uga2V5IGBpbmNsdWRlYCB0byBsaXN0IG1vZGVsIHZhcmlhYmxlcyB0aGF0IHlvdSB3YW50IHRvIGluY2x1ZGUgaW4gdGhlIHJlc3BvbnNlLiBPdGhlciBhdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9hZDogZnVuY3Rpb24gKHJ1bklELCBmaWx0ZXJzLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBpZiAocnVuSUQpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBydW5JRDsgLy9zaG91bGRuJ3QgYmUgYWJsZSB0byBvdmVyLXJpZGVcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucyA9IHVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlcihodHRwT3B0aW9ucyk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoZmlsdGVycywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgYXR0cmlidXRlcyAoZGF0YSwgbW9kZWwgdmFyaWFibGVzKSBvZiB0aGUgcnVuLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGVzKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgIC8vIGFkZCAnY29tcGxldGVkJyBmaWVsZCB0byBydW4gcmVjb3JkXG4gICAgICAgICAqICAgICBycy5zYXZlKHsgY29tcGxldGVkOiB0cnVlIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgLy8gdXBkYXRlICdzYXZlZCcgZmllbGQgb2YgcnVuIHJlY29yZCwgYW5kIHVwZGF0ZSB2YWx1ZXMgb2YgbW9kZWwgdmFyaWFibGVzIGZvciB0aGlzIHJ1blxuICAgICAgICAgKiAgICAgcnMuc2F2ZSh7IHNhdmVkOiB0cnVlLCB2YXJpYWJsZXM6IHsgYTogMjMsIGI6IDIzIH0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgYXR0cmlidXRlc2AgVGhlIHJ1biBkYXRhIGFuZCB2YXJpYWJsZXMgdG8gc2F2ZS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBhdHRyaWJ1dGVzLnZhcmlhYmxlc2AgTW9kZWwgdmFyaWFibGVzIG11c3QgYmUgaW5jbHVkZWQgaW4gYSBgdmFyaWFibGVzYCBmaWVsZCB3aXRoaW4gdGhlIGBhdHRyaWJ1dGVzYCBvYmplY3QuIChPdGhlcndpc2UgdGhleSBhcmUgdHJlYXRlZCBhcyBydW4gZGF0YSBhbmQgYWRkZWQgdG8gdGhlIHJ1biByZWNvcmQgZGlyZWN0bHkuKVxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBzYXZlOiBmdW5jdGlvbiAoYXR0cmlidXRlcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHNldEZpbHRlck9yVGhyb3dFcnJvcihodHRwT3B0aW9ucyk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wYXRjaChhdHRyaWJ1dGVzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENhbGwgYSBtZXRob2QgZnJvbSB0aGUgbW9kZWwuXG4gICAgICAgICAqXG4gICAgICAgICAqIERlcGVuZGluZyBvbiB0aGUgbGFuZ3VhZ2UgaW4gd2hpY2ggeW91IGhhdmUgd3JpdHRlbiB5b3VyIG1vZGVsLCB0aGUgbWV0aG9kIG1heSBuZWVkIHRvIGJlIGV4cG9zZWQgKGUuZy4gYGV4cG9ydGAgZm9yIGEgSnVsaWEgbW9kZWwpIGluIHRoZSBtb2RlbCBmaWxlIGluIG9yZGVyIHRvIGJlIGNhbGxlZCB0aHJvdWdoIHRoZSBBUEkuIFNlZSBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKSkuXG4gICAgICAgICAqXG4gICAgICAgICAqIFRoZSBgcGFyYW1zYCBhcmd1bWVudCBpcyBub3JtYWxseSBhbiBhcnJheSBvZiBhcmd1bWVudHMgdG8gdGhlIGBvcGVyYXRpb25gLiBJbiB0aGUgc3BlY2lhbCBjYXNlIHdoZXJlIGBvcGVyYXRpb25gIG9ubHkgdGFrZXMgb25lIGFyZ3VtZW50LCB5b3UgYXJlIG5vdCByZXF1aXJlZCB0byBwdXQgdGhhdCBhcmd1bWVudCBpbnRvIGFuIGFycmF5LlxuICAgICAgICAgKlxuICAgICAgICAgKiBOb3RlIHRoYXQgeW91IGNhbiBjb21iaW5lIHRoZSBgb3BlcmF0aW9uYCBhbmQgYHBhcmFtc2AgYXJndW1lbnRzIGludG8gYSBzaW5nbGUgb2JqZWN0IGlmIHlvdSBwcmVmZXIsIGFzIGluIHRoZSBsYXN0IGV4YW1wbGUuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcInNvbHZlXCIgdGFrZXMgbm8gYXJndW1lbnRzXG4gICAgICAgICAqICAgICBycy5kbygnc29sdmUnKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJlY2hvXCIgdGFrZXMgb25lIGFyZ3VtZW50LCBhIHN0cmluZ1xuICAgICAgICAgKiAgICAgcnMuZG8oJ2VjaG8nLCBbJ2hlbGxvJ10pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImVjaG9cIiB0YWtlcyBvbmUgYXJndW1lbnQsIGEgc3RyaW5nXG4gICAgICAgICAqICAgICBycy5kbygnZWNobycsICdoZWxsbycpO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcInN1bUFycmF5XCIgdGFrZXMgb25lIGFyZ3VtZW50LCBhbiBhcnJheVxuICAgICAgICAgKiAgICAgcnMuZG8oJ3N1bUFycmF5JywgW1s0LDIsMV1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJhZGRcIiB0YWtlcyB0d28gYXJndW1lbnRzLCBib3RoIGludGVnZXJzXG4gICAgICAgICAqICAgICBycy5kbyh7IG5hbWU6J2FkZCcsIHBhcmFtczpbMiw0XSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGBvcGVyYXRpb25gIE5hbWUgb2YgbWV0aG9kLlxuICAgICAgICAgKiBAcGFyYW0ge0FycmF5fSBgcGFyYW1zYCAoT3B0aW9uYWwpIEFueSBwYXJhbWV0ZXJzIHRoZSBvcGVyYXRpb24gdGFrZXMsIHBhc3NlZCBhcyBhbiBhcnJheS4gSW4gdGhlIHNwZWNpYWwgY2FzZSB3aGVyZSBgb3BlcmF0aW9uYCBvbmx5IHRha2VzIG9uZSBhcmd1bWVudCwgeW91IGFyZSBub3QgcmVxdWlyZWQgdG8gcHV0IHRoYXQgYXJndW1lbnQgaW50byBhbiBhcnJheSwgYW5kIGNhbiBqdXN0IHBhc3MgaXQgZGlyZWN0bHkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGRvOiBmdW5jdGlvbiAob3BlcmF0aW9uLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIC8vIGNvbnNvbGUubG9nKCdkbycsIG9wZXJhdGlvbiwgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHNBcmdzO1xuICAgICAgICAgICAgdmFyIHBvc3RPcHRpb25zO1xuICAgICAgICAgICAgaWYgKG9wdGlvbnMpIHtcbiAgICAgICAgICAgICAgICBvcHNBcmdzID0gcGFyYW1zO1xuICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zID0gb3B0aW9ucztcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdChwYXJhbXMpKSB7XG4gICAgICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucyA9IHBhcmFtcztcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBvcHNBcmdzID0gcGFyYW1zO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciByZXN1bHQgPSBydXRpbC5ub3JtYWxpemVPcGVyYXRpb25zKG9wZXJhdGlvbiwgb3BzQXJncyk7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIHBvc3RPcHRpb25zKTtcblxuICAgICAgICAgICAgc2V0RmlsdGVyT3JUaHJvd0Vycm9yKGh0dHBPcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIHBybXMgPSAocmVzdWx0LmFyZ3NbMF0ubGVuZ3RoICYmIChyZXN1bHQuYXJnc1swXSAhPT0gbnVsbCAmJiByZXN1bHQuYXJnc1swXSAhPT0gdW5kZWZpbmVkKSkgPyByZXN1bHQuYXJnc1swXSA6IFtdO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdCh7IGFyZ3VtZW50czogcHJtcyB9LCAkLmV4dGVuZCh0cnVlLCB7fSwgaHR0cE9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRGaWx0ZXJVUkwoKSArICdvcGVyYXRpb25zLycgKyByZXN1bHQub3BzWzBdICsgJy8nXG4gICAgICAgICAgICB9KSk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENhbGwgc2V2ZXJhbCBtZXRob2RzIGZyb20gdGhlIG1vZGVsLCBzZXF1ZW50aWFsbHkuXG4gICAgICAgICAqXG4gICAgICAgICAqIERlcGVuZGluZyBvbiB0aGUgbGFuZ3VhZ2UgaW4gd2hpY2ggeW91IGhhdmUgd3JpdHRlbiB5b3VyIG1vZGVsLCB0aGUgbWV0aG9kcyBtYXkgbmVlZCB0byBiZSBleHBvc2VkIChlLmcuIGBleHBvcnRgIGZvciBhIEp1bGlhIG1vZGVsKSBpbiB0aGUgbW9kZWwgZmlsZSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdGhyb3VnaCB0aGUgQVBJLiBTZWUgW1dyaXRpbmcgeW91ciBNb2RlbF0oLi4vLi4vLi4vd3JpdGluZ195b3VyX21vZGVsLykpLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGVzKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiaW5pdGlhbGl6ZVwiIGFuZCBcInNvbHZlXCIgZG8gbm90IHRha2UgYW55IGFyZ3VtZW50c1xuICAgICAgICAgKiAgICAgcnMuc2VyaWFsKFsnaW5pdGlhbGl6ZScsICdzb2x2ZSddKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiaW5pdFwiIGFuZCBcInJlc2V0XCIgdGFrZSB0d28gYXJndW1lbnRzIGVhY2hcbiAgICAgICAgICogICAgIHJzLnNlcmlhbChbICB7IG5hbWU6ICdpbml0JywgcGFyYW1zOiBbMSwyXSB9LFxuICAgICAgICAgKiAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3Jlc2V0JywgcGFyYW1zOiBbMiwzXSB9XSk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwiaW5pdFwiIHRha2VzIHR3byBhcmd1bWVudHMsXG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwicnVubW9kZWxcIiB0YWtlcyBub25lXG4gICAgICAgICAqICAgICBycy5zZXJpYWwoWyAgeyBuYW1lOiAnaW5pdCcsIHBhcmFtczogWzEsMl0gfSxcbiAgICAgICAgICogICAgICAgICAgICAgICAgICB7IG5hbWU6ICdydW5tb2RlbCcsIHBhcmFtczogW10gfV0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge0FycmF5fSBgb3BlcmF0aW9uc2AgSWYgbm9uZSBvZiB0aGUgbWV0aG9kcyB0YWtlIHBhcmFtZXRlcnMsIHBhc3MgYW4gYXJyYXkgb2YgdGhlIG1ldGhvZCBuYW1lcyAoc3RyaW5ncykuIElmIGFueSBvZiB0aGUgbWV0aG9kcyBkbyB0YWtlIHBhcmFtZXRlcnMsIHBhc3MgYW4gYXJyYXkgb2Ygb2JqZWN0cywgZWFjaCBvZiB3aGljaCBjb250YWlucyBhIG1ldGhvZCBuYW1lIGFuZCBpdHMgb3duIChwb3NzaWJseSBlbXB0eSkgYXJyYXkgb2YgcGFyYW1ldGVycy5cbiAgICAgICAgICogQHBhcmFtIHsqfSBgcGFyYW1zYCBQYXJhbWV0ZXJzIHRvIHBhc3MgdG8gb3BlcmF0aW9ucy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2VyaWFsOiBmdW5jdGlvbiAob3BlcmF0aW9ucywgcGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgb3BQYXJhbXMgPSBydXRpbC5ub3JtYWxpemVPcGVyYXRpb25zKG9wZXJhdGlvbnMsIHBhcmFtcyk7XG4gICAgICAgICAgICB2YXIgb3BzID0gb3BQYXJhbXMub3BzO1xuICAgICAgICAgICAgdmFyIGFyZ3MgPSBvcFBhcmFtcy5hcmdzO1xuICAgICAgICAgICAgdmFyIG1lID0gdGhpcztcblxuICAgICAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIHBvc3RPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRvU2luZ2xlT3AgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgdmFyIG9wID0gb3BzLnNoaWZ0KCk7XG4gICAgICAgICAgICAgICAgdmFyIGFyZyA9IGFyZ3Muc2hpZnQoKTtcblxuICAgICAgICAgICAgICAgIG1lLmRvKG9wLCBhcmcsIHtcbiAgICAgICAgICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG9wcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb1NpbmdsZU9wKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICRkLnJlc29sdmUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucy5zdWNjZXNzLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIGVycm9yOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAkZC5yZWplY3QuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zLmVycm9yLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIGRvU2luZ2xlT3AoKTtcblxuICAgICAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBzZXZlcmFsIG1ldGhvZHMgZnJvbSB0aGUgbW9kZWwsIGV4ZWN1dGluZyB0aGVtIGluIHBhcmFsbGVsLlxuICAgICAgICAgKlxuICAgICAgICAgKiBEZXBlbmRpbmcgb24gdGhlIGxhbmd1YWdlIGluIHdoaWNoIHlvdSBoYXZlIHdyaXR0ZW4geW91ciBtb2RlbCwgdGhlIG1ldGhvZHMgbWF5IG5lZWQgdG8gYmUgZXhwb3NlZCAoZS5nLiBgZXhwb3J0YCBmb3IgYSBKdWxpYSBtb2RlbCkgaW4gdGhlIG1vZGVsIGZpbGUgaW4gb3JkZXIgdG8gYmUgY2FsbGVkIHRocm91Z2ggdGhlIEFQSS4gU2VlIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pKS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwic29sdmVcIiBhbmQgXCJyZXNldFwiIGRvIG5vdCB0YWtlIGFueSBhcmd1bWVudHNcbiAgICAgICAgICogICAgIHJzLnBhcmFsbGVsKFsnc29sdmUnLCAncmVzZXQnXSk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kcyBcImFkZFwiIGFuZCBcInN1YnRyYWN0XCIgdGFrZSB0d28gYXJndW1lbnRzIGVhY2hcbiAgICAgICAgICogICAgIHJzLnBhcmFsbGVsKFsgeyBuYW1lOiAnYWRkJywgcGFyYW1zOiBbMSwyXSB9LFxuICAgICAgICAgKiAgICAgICAgICAgICAgICAgICB7IG5hbWU6ICdzdWJ0cmFjdCcsIHBhcmFtczpbMiwzXSB9XSk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kcyBcImFkZFwiIGFuZCBcInN1YnRyYWN0XCIgdGFrZSB0d28gYXJndW1lbnRzIGVhY2hcbiAgICAgICAgICogICAgIHJzLnBhcmFsbGVsKHsgYWRkOiBbMSwyXSwgc3VidHJhY3Q6IFsyLDRdIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdH0gYG9wZXJhdGlvbnNgIElmIG5vbmUgb2YgdGhlIG1ldGhvZHMgdGFrZSBwYXJhbWV0ZXJzLCBwYXNzIGFuIGFycmF5IG9mIHRoZSBtZXRob2QgbmFtZXMgKGFzIHN0cmluZ3MpLiBJZiBhbnkgb2YgdGhlIG1ldGhvZHMgZG8gdGFrZSBwYXJhbWV0ZXJzLCB5b3UgaGF2ZSB0d28gb3B0aW9ucy4gWW91IGNhbiBwYXNzIGFuIGFycmF5IG9mIG9iamVjdHMsIGVhY2ggb2Ygd2hpY2ggY29udGFpbnMgYSBtZXRob2QgbmFtZSBhbmQgaXRzIG93biAocG9zc2libHkgZW1wdHkpIGFycmF5IG9mIHBhcmFtZXRlcnMuIEFsdGVybmF0aXZlbHksIHlvdSBjYW4gcGFzcyBhIHNpbmdsZSBvYmplY3Qgd2l0aCB0aGUgbWV0aG9kIG5hbWUgYW5kIGEgKHBvc3NpYmx5IGVtcHR5KSBhcnJheSBvZiBwYXJhbWV0ZXJzLlxuICAgICAgICAgKiBAcGFyYW0geyp9IGBwYXJhbXNgIFBhcmFtZXRlcnMgdG8gcGFzcyB0byBvcGVyYXRpb25zLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBwYXJhbGxlbDogZnVuY3Rpb24gKG9wZXJhdGlvbnMsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuXG4gICAgICAgICAgICB2YXIgb3BQYXJhbXMgPSBydXRpbC5ub3JtYWxpemVPcGVyYXRpb25zKG9wZXJhdGlvbnMsIHBhcmFtcyk7XG4gICAgICAgICAgICB2YXIgb3BzID0gb3BQYXJhbXMub3BzO1xuICAgICAgICAgICAgdmFyIGFyZ3MgPSBvcFBhcmFtcy5hcmdzO1xuICAgICAgICAgICAgdmFyIHBvc3RPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIHF1ZXVlICA9IFtdO1xuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGk8IG9wcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIHF1ZXVlLnB1c2goXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZG8ob3BzW2ldLCBhcmdzW2ldKVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAkLndoZW4uYXBwbHkodGhpcywgcXVldWUpXG4gICAgICAgICAgICAgICAgLmRvbmUoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAkZC5yZXNvbHZlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zLnN1Y2Nlc3MuYXBwbHkodGhpcy5hcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmZhaWwoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAkZC5yZWplY3QuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuZXJyb3IuYXBwbHkodGhpcy5hcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNTeW5jQVBJID0ge1xuICAgICAgICBnZXRDdXJyZW50Q29uZmlnOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnM7XG4gICAgICAgIH0sXG4gICAgICAgIC8qKlxuICAgICAgICAgICogUmV0dXJucyBhIFZhcmlhYmxlcyBTZXJ2aWNlIGluc3RhbmNlLiBVc2UgdGhlIHZhcmlhYmxlcyBpbnN0YW5jZSB0byBsb2FkLCBzYXZlLCBhbmQgcXVlcnkgZm9yIHNwZWNpZmljIG1vZGVsIHZhcmlhYmxlcy4gU2VlIHRoZSBbVmFyaWFibGUgQVBJIFNlcnZpY2VdKC4uL3ZhcmlhYmxlcy1hcGktc2VydmljZS8pIGZvciBtb3JlIGluZm9ybWF0aW9uLlxuICAgICAgICAgICpcbiAgICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAgKlxuICAgICAgICAgICogICAgICB2YXIgdnMgPSBycy52YXJpYWJsZXMoKTtcbiAgICAgICAgICAqICAgICAgdnMuc2F2ZSh7IHNhbXBsZV9pbnQ6IDQgfSk7XG4gICAgICAgICAgKlxuICAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgY29uZmlnYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgICovXG4gICAgICAgIHZhcmlhYmxlczogZnVuY3Rpb24gKGNvbmZpZykge1xuICAgICAgICAgICAgdmFyIHZzID0gbmV3IFZhcmlhYmxlc1NlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBjb25maWcsIHtcbiAgICAgICAgICAgICAgICBydW5TZXJ2aWNlOiB0aGlzXG4gICAgICAgICAgICB9KSk7XG4gICAgICAgICAgICByZXR1cm4gdnM7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQXN5bmNBUEkpO1xuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY1N5bmNBUEkpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG52YXIgb2JqZWN0QXNzaWduID0gcmVxdWlyZSgnb2JqZWN0LWFzc2lnbicpO1xuXG52YXIgc2VydmljZVV0aWxzID0ge1xuICAgIC8qXG4gICAgKiBHZXRzIHRoZSBkZWZhdWx0IG9wdGlvbnMgZm9yIGEgYXBpIHNlcnZpY2UuXG4gICAgKiBJdCB3aWxsIG1lcmdlOlxuICAgICogLSBUaGUgU2Vzc2lvbiBvcHRpb25zIChVc2luZyB0aGUgU2Vzc2lvbiBNYW5hZ2VyKVxuICAgICogLSBUaGUgQXV0aG9yaXphdGlvbiBIZWFkZXIgZnJvbSB0aGUgdG9rZW4gb3B0aW9uXG4gICAgKiAtIFRoZSBmdWxsIHVybCBmcm9tIHRoZSBlbmRwb2ludCBvcHRpb25cbiAgICAqIFdpdGggdGhlIHN1cHBsaWVkIG92ZXJyaWRlcyBhbmQgZGVmYXVsdHNcbiAgICAqXG4gICAgKi9cbiAgICBnZXREZWZhdWx0T3B0aW9uczogZnVuY3Rpb24gKGRlZmF1bHRzKSB7XG4gICAgICAgIHZhciByZXN0ID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICAgICAgdmFyIHNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG4gICAgICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9IHNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMuYXBwbHkoc2Vzc2lvbk1hbmFnZXIsIFtkZWZhdWx0c10uY29uY2F0KHJlc3QpKTtcblxuICAgICAgICBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQgPSBvYmplY3RBc3NpZ24oe30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICAgICAgdXJsOiB0aGlzLmdldEFwaVVybChzZXJ2aWNlT3B0aW9ucy5hcGlFbmRwb2ludCwgc2VydmljZU9wdGlvbnMpXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnM7XG4gICAgfSxcblxuICAgIGdldEFwaVVybDogZnVuY3Rpb24gKGFwaUVuZHBvaW50LCBzZXJ2aWNlT3B0aW9ucykge1xuICAgICAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgICAgIHJldHVybiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBzZXJ2aWNlVXRpbHM7IiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4gKiAjIyBTdGF0ZSBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBTdGF0ZSBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHJlcGxheSBvciBjbG9uZSBydW5zLiBJdCBicmluZ3MgZXhpc3RpbmcsIHBlcnNpc3RlZCBydW4gZGF0YSBmcm9tIHRoZSBkYXRhYmFzZSBiYWNrIGludG8gbWVtb3J5LCB1c2luZyB0aGUgc2FtZSBydW4gaWQgKGByZXBsYXlgKSBvciBhIG5ldyBydW4gaWQgKGBjbG9uZWApLiBSdW5zIG11c3QgYmUgaW4gbWVtb3J5IGluIG9yZGVyIGZvciB5b3UgdG8gdXBkYXRlIHZhcmlhYmxlcyBvciBjYWxsIG9wZXJhdGlvbnMgb24gdGhlbS5cbiAqXG4gKiBTcGVjaWZpY2FsbHksIHRoZSBTdGF0ZSBBUEkgQWRhcHRlciB3b3JrcyBieSBcInJlLXJ1bm5pbmdcIiB0aGUgcnVuICh1c2VyIGludGVyYWN0aW9ucykgZnJvbSB0aGUgY3JlYXRpb24gb2YgdGhlIHJ1biB1cCB0byB0aGUgdGltZSBpdCB3YXMgbGFzdCBwZXJzaXN0ZWQgaW4gdGhlIGRhdGFiYXNlLiBUaGlzIHByb2Nlc3MgdXNlcyB0aGUgY3VycmVudCB2ZXJzaW9uIG9mIHRoZSBydW4ncyBtb2RlbC4gVGhlcmVmb3JlLCBpZiB0aGUgbW9kZWwgaGFzIGNoYW5nZWQgc2luY2UgdGhlIG9yaWdpbmFsIHJ1biB3YXMgY3JlYXRlZCwgdGhlIHJldHJpZXZlZCBydW4gd2lsbCB1c2UgdGhlIG5ldyBtb2RlbCDigJQgYW5kIG1heSBlbmQgdXAgaGF2aW5nIGRpZmZlcmVudCB2YWx1ZXMgb3IgYmVoYXZpb3IgYXMgYSByZXN1bHQuIFVzZSB3aXRoIGNhcmUhXG4gKlxuICogVG8gdXNlIHRoZSBTdGF0ZSBBUEkgQWRhcHRlciwgaW5zdGFudGlhdGUgaXQgYW5kIHRoZW4gY2FsbCBpdHMgbWV0aG9kczpcbiAqXG4gKiAgICAgIHZhciBzYSA9IG5ldyBGLnNlcnZpY2UuU3RhdGUoKTtcbiAqICAgICAgc2EucmVwbGF5KHtydW5JZDogJzE4NDJiYjVjLTgzYWQtNGJhOC1hOTU1LWJkMTNjYzJmZGI0Zid9KTtcbiAqXG4gKiBUaGUgY29uc3RydWN0b3IgdGFrZXMgYW4gb3B0aW9uYWwgYG9wdGlvbnNgIHBhcmFtZXRlciBpbiB3aGljaCB5b3UgY2FuIHNwZWNpZnkgdGhlIGBhY2NvdW50YCBhbmQgYHByb2plY3RgIGlmIHRoZXkgYXJlIG5vdCBhbHJlYWR5IGF2YWlsYWJsZSBpbiB0aGUgY3VycmVudCBjb250ZXh0LlxuICpcbiAqL1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcbnZhciBhcGlFbmRwb2ludCA9ICdtb2RlbC9zdGF0ZSc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgfTtcblxuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG4gICAgdmFyIHBhcnNlUnVuSWRPckVycm9yID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHBhcmFtcykgJiYgcGFyYW1zLnJ1bklkKSB7XG4gICAgICAgICAgICByZXR1cm4gcGFyYW1zLnJ1bklkO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcGFzcyBpbiBhIHJ1biBpZCcpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAqIFJlcGxheSBhIHJ1bi4gQWZ0ZXIgdGhpcyBjYWxsLCB0aGUgcnVuLCB3aXRoIGl0cyBvcmlnaW5hbCBydW4gaWQsIGlzIG5vdyBhdmFpbGFibGUgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkuIChJdCBjb250aW51ZXMgdG8gYmUgcGVyc2lzdGVkIGludG8gdGhlIEVwaWNlbnRlciBkYXRhYmFzZSBhdCByZWd1bGFyIGludGVydmFscy4pXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHNhID0gbmV3IEYuc2VydmljZS5TdGF0ZSgpO1xuICAgICAgICAqICAgICAgc2EucmVwbGF5KHtydW5JZDogJzE4NDJiYjVjLTgzYWQtNGJhOC1hOTU1LWJkMTNjYzJmZGI0ZicsIHN0b3BCZWZvcmU6ICdjYWxjdWxhdGVTY29yZSd9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBQYXJhbWV0ZXJzIG9iamVjdC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5ydW5JZGAgVGhlIGlkIG9mIHRoZSBydW4gdG8gYnJpbmcgYmFjayB0byBtZW1vcnkuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuc3RvcEJlZm9yZWAgKE9wdGlvbmFsKSBUaGUgcnVuIGlzIGFkdmFuY2VkIG9ubHkgdXAgdG8gdGhlIGZpcnN0IG9jY3VycmVuY2Ugb2YgdGhpcyBtZXRob2QuXG4gICAgICAgICogQHBhcmFtIHthcnJheX0gYHBhcmFtcy5leGNsdWRlYCAoT3B0aW9uYWwpIEFycmF5IG9mIG1ldGhvZHMgdG8gZXhjbHVkZSB3aGVuIGFkdmFuY2luZyB0aGUgcnVuLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgcmVwbGF5OiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcnVuSWQgPSBwYXJzZVJ1bklkT3JFcnJvcihwYXJhbXMpO1xuXG4gICAgICAgICAgICB2YXIgcmVwbGF5T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHJ1bklkIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgYWN0aW9uOiAncmVwbGF5JyB9LCBfcGljayhwYXJhbXMsIFsnc3RvcEJlZm9yZScsICdleGNsdWRlJ10pKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChwYXJhbXMsIHJlcGxheU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIENsb25lIGEgZ2l2ZW4gcnVuIGFuZCByZXR1cm4gYSBuZXcgcnVuIGluIHRoZSBzYW1lIHN0YXRlIGFzIHRoZSBnaXZlbiBydW4uXG4gICAgICAgICpcbiAgICAgICAgKiBUaGUgbmV3IHJ1biBpZCBpcyBub3cgYXZhaWxhYmxlIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLiBUaGUgbmV3IHJ1biBpbmNsdWRlcyBhIGNvcHkgb2YgYWxsIG9mIHRoZSBkYXRhIGZyb20gdGhlIG9yaWdpbmFsIHJ1biwgRVhDRVBUOlxuICAgICAgICAqXG4gICAgICAgICogKiBUaGUgYHNhdmVkYCBmaWVsZCBpbiB0aGUgbmV3IHJ1biByZWNvcmQgaXMgbm90IGNvcGllZCBmcm9tIHRoZSBvcmlnaW5hbCBydW4gcmVjb3JkLiBJdCBkZWZhdWx0cyB0byBgZmFsc2VgLlxuICAgICAgICAqICogVGhlIGBpbml0aWFsaXplZGAgZmllbGQgaW4gdGhlIG5ldyBydW4gcmVjb3JkIGlzIG5vdCBjb3BpZWQgZnJvbSB0aGUgb3JpZ2luYWwgcnVuIHJlY29yZC4gSXQgZGVmYXVsdHMgdG8gYGZhbHNlYCBidXQgbWF5IGNoYW5nZSB0byBgdHJ1ZWAgYXMgdGhlIG5ldyBydW4gaXMgYWR2YW5jZWQuIEZvciBleGFtcGxlLCBpZiB0aGVyZSBoYXMgYmVlbiBhIGNhbGwgdG8gdGhlIGBzdGVwYCBmdW5jdGlvbiAoZm9yIFZlbnNpbSBtb2RlbHMpLCB0aGUgYGluaXRpYWxpemVkYCBmaWVsZCBpcyBzZXQgdG8gYHRydWVgLlxuICAgICAgICAqICogVGhlIGBjcmVhdGVkYCBmaWVsZCBpbiB0aGUgbmV3IHJ1biByZWNvcmQgaXMgdGhlIGRhdGUgYW5kIHRpbWUgYXQgd2hpY2ggdGhlIGNsb25lIHdhcyBjcmVhdGVkIChub3QgdGhlIHRpbWUgdGhhdCB0aGUgb3JpZ2luYWwgcnVuIHdhcyBjcmVhdGVkLilcbiAgICAgICAgKlxuICAgICAgICAqIFRoZSBvcmlnaW5hbCBydW4gcmVtYWlucyBvbmx5IFtpbiB0aGUgZGF0YWJhc2VdKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1kYikuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHNhID0gbmV3IEYuc2VydmljZS5TdGF0ZSgpO1xuICAgICAgICAqICAgICAgc2EuY2xvbmUoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJywgc3RvcEJlZm9yZTogJ2NhbGN1bGF0ZVNjb3JlJywgZXhjbHVkZTogWydpbnRlcmltQ2FsY3VsYXRpb24nXSB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBQYXJhbWV0ZXJzIG9iamVjdC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5ydW5JZGAgVGhlIGlkIG9mIHRoZSBydW4gdG8gY2xvbmUgZnJvbSBtZW1vcnkuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuc3RvcEJlZm9yZWAgKE9wdGlvbmFsKSBUaGUgbmV3bHkgY2xvbmVkIHJ1biBpcyBhZHZhbmNlZCBvbmx5IHVwIHRvIHRoZSBmaXJzdCBvY2N1cnJlbmNlIG9mIHRoaXMgbWV0aG9kLlxuICAgICAgICAqIEBwYXJhbSB7YXJyYXl9IGBwYXJhbXMuZXhjbHVkZWAgKE9wdGlvbmFsKSBBcnJheSBvZiBtZXRob2RzIHRvIGV4Y2x1ZGUgd2hlbiBhZHZhbmNpbmcgdGhlIG5ld2x5IGNsb25lZCBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBjbG9uZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHJ1bklkID0gcGFyc2VSdW5JZE9yRXJyb3IocGFyYW1zKTtcblxuICAgICAgICAgICAgdmFyIHJlcGxheU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBydW5JZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBwYXJhbXMgPSAkLmV4dGVuZCh0cnVlLCB7IGFjdGlvbjogJ2Nsb25lJyB9LCBfcGljayhwYXJhbXMsIFsnc3RvcEJlZm9yZScsICdleGNsdWRlJ10pKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChwYXJhbXMsIHJlcGxheU9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgZXBpVmVyc2lvbiA9IHJlcXVpcmUoJy4uL2FwaS12ZXJzaW9uLmpzb24nKTtcblxuLy9UT0RPOiB1cmx1dGlscyB0byBnZXQgaG9zdCwgc2luY2Ugbm8gd2luZG93IG9uIG5vZGVcbnZhciBkZWZhdWx0cyA9IHtcbiAgICBob3N0OiB3aW5kb3cubG9jYXRpb24uaG9zdCxcbiAgICBwYXRobmFtZTogd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lXG59O1xuXG52YXIgVXJsQ29uZmlnU2VydmljZSA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICBmdW5jdGlvbiBpc0xvY2FsaG9zdCgpIHtcbiAgICAgICAgdmFyIGhvc3QgPSBvcHRpb25zLmhvc3Q7XG4gICAgICAgIHZhciBwYXRoID0gb3B0aW9ucy5wYXRobmFtZTtcbiAgICAgICAgLy8gU29ydCBvZiBoYXJkY29kZSB0aGUgZmFjdCB0aGF0IGVwaWNlbnRlciBhcHBsaWNhdGlvbiBzcGFjZSBpcyBwcmVmaXhlZCBieSAvYXBwL1xuICAgICAgICByZXR1cm4gKCFob3N0IHx8IHBhdGguaW5kZXhPZignL2FwcC8nKSAhPT0gMCk7XG4gICAgfVxuXG4gICAgdmFyIEFQSV9QUk9UT0NPTCA9ICdodHRwcyc7XG4gICAgdmFyIEhPU1RfQVBJX01BUFBJTkcgPSB7XG4gICAgICAgICdmb3Jpby5jb20nOiAnYXBpLmZvcmlvLmNvbScsXG4gICAgICAgICdmb3Jpb2Rldi5jb20nOiAnYXBpLmVwaWNlbnRlci5mb3Jpb2Rldi5jb20nXG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNFeHBvcnRzID0ge1xuICAgICAgICBwcm90b2NvbDogQVBJX1BST1RPQ09MLFxuXG4gICAgICAgIGFwaTogJycsXG5cbiAgICAgICAgaG9zdDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBob3N0ID0gb3B0aW9ucy5ob3N0O1xuICAgICAgICAgICAgaWYgKGlzTG9jYWxob3N0KCkpIHtcbiAgICAgICAgICAgICAgICBob3N0ID0gJ2ZvcmlvLmNvbSc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gKEhPU1RfQVBJX01BUFBJTkdbaG9zdF0pID8gSE9TVF9BUElfTUFQUElOR1tob3N0XSA6ICdhcGkuJyArIGhvc3Q7XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgYXBwUGF0aDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBwYXRoID0gb3B0aW9ucy5wYXRobmFtZS5zcGxpdCgnXFwvJyk7XG5cbiAgICAgICAgICAgIHJldHVybiBwYXRoICYmIHBhdGhbMV0gfHwgJyc7XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgYWNjb3VudFBhdGg6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgYWNjbnQgPSAnJztcbiAgICAgICAgICAgIHZhciBwYXRoID0gb3B0aW9ucy5wYXRobmFtZS5zcGxpdCgnXFwvJyk7XG4gICAgICAgICAgICBpZiAocGF0aCAmJiBwYXRoWzFdID09PSAnYXBwJykge1xuICAgICAgICAgICAgICAgIGFjY250ID0gcGF0aFsyXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhY2NudDtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBwcm9qZWN0UGF0aDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBwcmogPSAnJztcbiAgICAgICAgICAgIHZhciBwYXRoID0gb3B0aW9ucy5wYXRobmFtZS5zcGxpdCgnXFwvJyk7XG4gICAgICAgICAgICBpZiAocGF0aCAmJiBwYXRoWzFdID09PSAnYXBwJykge1xuICAgICAgICAgICAgICAgIHByaiA9IHBhdGhbM107XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gcHJqO1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIHZlcnNpb25QYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHZlcnNpb24gPSBlcGlWZXJzaW9uLnZlcnNpb24gPyBlcGlWZXJzaW9uLnZlcnNpb24gKyAnLycgOiAnJztcbiAgICAgICAgICAgIHJldHVybiB2ZXJzaW9uO1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIGlzTG9jYWxob3N0OiBpc0xvY2FsaG9zdCxcblxuICAgICAgICBnZXRBUElQYXRoOiBmdW5jdGlvbiAoYXBpKSB7XG4gICAgICAgICAgICB2YXIgUFJPSkVDVF9BUElTID0gWydydW4nLCAnZGF0YScsICdmaWxlJ107XG5cbiAgICAgICAgICAgIHZhciBhcGlQYXRoID0gdGhpcy5wcm90b2NvbCArICc6Ly8nICsgdGhpcy5ob3N0ICsgJy8nICsgdGhpcy52ZXJzaW9uUGF0aCArIGFwaSArICcvJztcblxuICAgICAgICAgICAgaWYgKCQuaW5BcnJheShhcGksIFBST0pFQ1RfQVBJUykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgYXBpUGF0aCArPSB0aGlzLmFjY291bnRQYXRoICsgJy8nICsgdGhpcy5wcm9qZWN0UGF0aCAgKyAnLyc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gYXBpUGF0aDtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvLyBUaGlzIGRhdGEgaXMgc2V0IGJ5IGFuIGV4dGVybmFsIHNjcmlwdCAoc3RhcnQtbG9hZC5qcylcbiAgICB2YXIgZW52Q29uZiA9IHtcbiAgICAgICAgcHJvdG9jb2w6IFVybENvbmZpZ1NlcnZpY2UucHJvdG9jb2wsXG4gICAgICAgIGhvc3Q6IFVybENvbmZpZ1NlcnZpY2UuaG9zdFxuICAgIH07XG5cbiAgICAkLmV4dGVuZChwdWJsaWNFeHBvcnRzLCBlbnZDb25mLCBjb25maWcpO1xuICAgIHJldHVybiBwdWJsaWNFeHBvcnRzO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBVcmxDb25maWdTZXJ2aWNlO1xuIiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4qICMjIFVzZXIgQVBJIEFkYXB0ZXJcbipcbiogVGhlIFVzZXIgQVBJIEFkYXB0ZXIgYWxsb3dzIHlvdSB0byByZXRyaWV2ZSBkZXRhaWxzIGFib3V0IGVuZCB1c2VycyBpbiB5b3VyIHRlYW0gKGFjY291bnQpLiBJdCBpcyBiYXNlZCBvbiB0aGUgcXVlcnlpbmcgY2FwYWJpbGl0aWVzIG9mIHRoZSB1bmRlcmx5aW5nIFJFU1RmdWwgW1VzZXIgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvdXNlcl9tYW5hZ2VtZW50L3VzZXIvKS5cbipcbiogVG8gdXNlIHRoZSBVc2VyIEFQSSBBZGFwdGVyLCBpbnN0YW50aWF0ZSBpdCBhbmQgdGhlbiBjYWxsIGl0cyBtZXRob2RzLlxuKlxuKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuKiAgICAgICAgICAgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJ1xuKiAgICAgICB9KTtcbiogICAgICAgdWEuZ2V0QnlJZCgnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyk7XG4qICAgICAgIHVhLmdldCh7IHVzZXJOYW1lOiAnanNtaXRoJyB9KTtcbiogICAgICAgdWEuZ2V0KHsgaWQ6IFsnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiogICAgICAgICAgICAgICAgICAgJzRlYTc1NjMxLTRjOGQtNDg3Mi05ZDgwLWI0NjAwMTQ2NDc4ZSddIH0pO1xuKlxuKiBUaGUgY29uc3RydWN0b3IgdGFrZXMgYW4gb3B0aW9uYWwgYG9wdGlvbnNgIHBhcmFtZXRlciBpbiB3aGljaCB5b3UgY2FuIHNwZWNpZnkgdGhlIGBhY2NvdW50YCBhbmQgYHRva2VuYCBpZiB0aGV5IGFyZSBub3QgYWxyZWFkeSBhdmFpbGFibGUgaW4gdGhlIGN1cnJlbnQgY29udGV4dC5cbiovXG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY2VzcyB0b2tlbiB0byB1c2Ugd2hlbiBzZWFyY2hpbmcgZm9yIGVuZCB1c2Vycy4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdG9rZW46IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9XG4gICAgfTtcblxuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCd1c2VyJylcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBwYXJ0aWN1bGFyIGVuZCB1c2VycyBpbiB5b3VyIHRlYW0sIGJhc2VkIG9uIHVzZXIgbmFtZSBvciB1c2VyIGlkLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciB1YSA9IG5ldyBGLnNlcnZpY2UuVXNlcih7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJ1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqICAgICAgIHVhLmdldCh7IHVzZXJOYW1lOiAnanNtaXRoJyB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXQoeyBpZDogWyc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICc0ZWE3NTYzMS00YzhkLTQ4NzItOWQ4MC1iNDYwMDE0NjQ3OGUnXSB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBmaWx0ZXJgIE9iamVjdCB3aXRoIGZpZWxkIGB1c2VyTmFtZWAgYW5kIHZhbHVlIG9mIHRoZSB1c2VybmFtZS4gQWx0ZXJuYXRpdmVseSwgb2JqZWN0IHdpdGggZmllbGQgYGlkYCBhbmQgdmFsdWUgb2YgYW4gYXJyYXkgb2YgdXNlciBpZHMuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuXG4gICAgICAgIGdldDogZnVuY3Rpb24gKGZpbHRlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICBmaWx0ZXIgPSBmaWx0ZXIgfHwge307XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9uc1xuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFyIHRvUUZpbHRlciA9IGZ1bmN0aW9uIChmaWx0ZXIpIHtcbiAgICAgICAgICAgICAgICB2YXIgcmVzID0ge307XG5cbiAgICAgICAgICAgICAgICAvLyBBUEkgb25seSBzdXBwb3J0cyBmaWx0ZXJpbmcgYnkgdXNlcm5hbWUgZm9yIG5vd1xuICAgICAgICAgICAgICAgIGlmIChmaWx0ZXIudXNlck5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzLnEgPSBmaWx0ZXIudXNlck5hbWU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciB0b0lkRmlsdGVycyA9IGZ1bmN0aW9uIChpZCkge1xuICAgICAgICAgICAgICAgIGlmICghaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlkID0gJC5pc0FycmF5KGlkKSA/IGlkIDogW2lkXTtcbiAgICAgICAgICAgICAgICByZXR1cm4gJ2lkPScgKyBpZC5qb2luKCcmaWQ9Jyk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0RmlsdGVycyA9IFtcbiAgICAgICAgICAgICAgICAnYWNjb3VudD0nICsgZ2V0T3B0aW9ucy5hY2NvdW50LFxuICAgICAgICAgICAgICAgIHRvSWRGaWx0ZXJzKGZpbHRlci5pZCksXG4gICAgICAgICAgICAgICAgcXV0aWwudG9RdWVyeUZvcm1hdCh0b1FGaWx0ZXIoZmlsdGVyKSlcbiAgICAgICAgICAgIF0uam9pbignJicpO1xuXG4gICAgICAgICAgICAvLyBzcGVjaWFsIGNhc2UgZm9yIHF1ZXJpZXMgd2l0aCBsYXJnZSBudW1iZXIgb2YgaWRzXG4gICAgICAgICAgICAvLyBtYWtlIGl0IGFzIGEgcG9zdCB3aXRoIEdFVCBzZW1hbnRpY3NcbiAgICAgICAgICAgIHZhciB0aHJlc2hvbGQgPSAzMDtcbiAgICAgICAgICAgIGlmIChmaWx0ZXIuaWQgJiYgJC5pc0FycmF5KGZpbHRlci5pZCkgJiYgZmlsdGVyLmlkLmxlbmd0aCA+PSB0aHJlc2hvbGQpIHtcbiAgICAgICAgICAgICAgICBnZXRPcHRpb25zLnVybCA9IHVybENvbmZpZy5nZXRBUElQYXRoKCd1c2VyJykgKyAnP19tZXRob2Q9R0VUJztcbiAgICAgICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHsgaWQ6IGZpbHRlci5pZCB9LCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGdldEZpbHRlcnMsIGdldE9wdGlvbnMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgYSBzaW5nbGUgZW5kIHVzZXIgaW4geW91ciB0ZWFtLCBiYXNlZCBvbiB1c2VyIGlkLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciB1YSA9IG5ldyBGLnNlcnZpY2UuVXNlcih7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJ1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqICAgICAgIHVhLmdldEJ5SWQoJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycpO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJJZGAgVGhlIHVzZXIgaWQgZm9yIHRoZSBlbmQgdXNlciBpbiB5b3VyIHRlYW0uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuXG4gICAgICAgIGdldEJ5SWQ6IGZ1bmN0aW9uICh1c2VySWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBwdWJsaWNBUEkuZ2V0KHsgaWQ6IHVzZXJJZCB9LCBvcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcblxuXG5cblxuIiwiLyoqXG4gKlxuICogIyMgVmFyaWFibGVzIEFQSSBTZXJ2aWNlXG4gKlxuICogVXNlZCBpbiBjb25qdW5jdGlvbiB3aXRoIHRoZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSB0byByZWFkLCB3cml0ZSwgYW5kIHNlYXJjaCBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLlxuICpcbiAqICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuICogICAgICAgICAgIHJ1bjoge1xuICogICAgICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5LWNoYWluLW1vZGVsLmpsJ1xuICogICAgICAgICAgIH1cbiAqICAgICAgfSk7XG4gKiAgICAgcm0uZ2V0UnVuKClcbiAqICAgICAgIC50aGVuKGZ1bmN0aW9uKCkge1xuICogICAgICAgICAgdmFyIHZzID0gcm0ucnVuLnZhcmlhYmxlcygpO1xuICogICAgICAgICAgdnMuc2F2ZSh7c2FtcGxlX2ludDogNH0pO1xuICogICAgICAgIH0pO1xuICpcbiAqL1xuXG5cbiAndXNlIHN0cmljdCc7XG5cbiB2YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG4gdmFyIHJ1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9ydW4tdXRpbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcnVucyBvYmplY3QgdG8gd2hpY2ggdGhlIHZhcmlhYmxlIGZpbHRlcnMgYXBwbHkuIERlZmF1bHRzIHRvIG51bGwuXG4gICAgICAgICAqIEB0eXBlIHtydW5TZXJ2aWNlfVxuICAgICAgICAgKi9cbiAgICAgICAgcnVuU2VydmljZTogbnVsbFxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIGdldFVSTCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zLnJ1blNlcnZpY2UudXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ3ZhcmlhYmxlcy8nO1xuICAgIH07XG5cbiAgICB2YXIgYWRkQXV0b1Jlc3RvcmVIZWFkZXIgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnMucnVuU2VydmljZS51cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIob3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBodHRwT3B0aW9ucyA9IHtcbiAgICAgICAgdXJsOiBnZXRVUkxcbiAgICB9O1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcbiAgICBodHRwLnNwbGl0R2V0ID0gcnV0aWwuc3BsaXRHZXRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCB2YWx1ZXMgZm9yIGEgdmFyaWFibGUuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMubG9hZCgnc2FtcGxlX2ludCcpXG4gICAgICAgICAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHZhbCl7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgY29udGFpbnMgdGhlIHZhbHVlIG9mIHNhbXBsZV9pbnRcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgdmFyaWFibGVgIE5hbWUgb2YgdmFyaWFibGUgdG8gbG9hZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9hZDogZnVuY3Rpb24gKHZhcmlhYmxlLCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KG91dHB1dE1vZGlmaWVyLCAkLmV4dGVuZCh7fSwgaHR0cE9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IGdldFVSTCgpICsgdmFyaWFibGUgKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHZhcmlhYmxlcywgYmFzZWQgb24gY29uZGl0aW9ucyBzcGVjaWZpZWQgaW4gdGhlIGBxdWVyeWAgb2JqZWN0LlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHZzLnF1ZXJ5KFsncHJpY2UnLCAnc2FsZXMnXSlcbiAgICAgICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24odmFsKSB7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgaXMgYW4gb2JqZWN0IHdpdGggdGhlIHZhbHVlcyBvZiB0aGUgcmVxdWVzdGVkIHZhcmlhYmxlczogdmFsLnByaWNlLCB2YWwuc2FsZXNcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMucXVlcnkoeyBpbmNsdWRlOlsncHJpY2UnLCAnc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8QXJyYXl9IGBxdWVyeWAgVGhlIG5hbWVzIG9mIHRoZSB2YXJpYWJsZXMgcmVxdWVzdGVkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG91dHB1dE1vZGlmaWVyYCAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqXG4gICAgICAgICAqL1xuICAgICAgICBxdWVyeTogZnVuY3Rpb24gKHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgLy9RdWVyeSBhbmQgb3V0cHV0TW9kaWZpZXIgYXJlIGJvdGggcXVlcnlzdHJpbmdzIGluIHRoZSB1cmw7IG9ubHkgY2FsbGluZyB0aGVtIG91dCBzZXBhcmF0ZWx5IGhlcmUgdG8gYmUgY29uc2lzdGVudCB3aXRoIHRoZSBvdGhlciBjYWxsc1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KHF1ZXJ5KSkge1xuICAgICAgICAgICAgICAgIHF1ZXJ5ID0geyBpbmNsdWRlOiBxdWVyeSB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgJC5leHRlbmQocXVlcnksIG91dHB1dE1vZGlmaWVyKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KHF1ZXJ5LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgdmFsdWVzIHRvIG1vZGVsIHZhcmlhYmxlcy4gT3ZlcndyaXRlcyBleGlzdGluZyB2YWx1ZXMuIE5vdGUgdGhhdCB5b3UgY2FuIG9ubHkgdXBkYXRlIG1vZGVsIHZhcmlhYmxlcyBpZiB0aGUgcnVuIGlzIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLiAoQW4gYWx0ZXJuYXRlIHdheSB0byB1cGRhdGUgbW9kZWwgdmFyaWFibGVzIGlzIHRvIGNhbGwgYSBtZXRob2QgZnJvbSB0aGUgbW9kZWwgYW5kIG1ha2Ugc3VyZSB0aGF0IHRoZSBtZXRob2QgcGVyc2lzdHMgdGhlIHZhcmlhYmxlcy4gU2VlIGBkb2AsIGBzZXJpYWxgLCBhbmQgYHBhcmFsbGVsYCBpbiB0aGUgW1J1biBBUEkgU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykgZm9yIGNhbGxpbmcgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbC4pXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMuc2F2ZSgncHJpY2UnLCA0KTtcbiAgICAgICAgICogICAgICB2cy5zYXZlKHsgcHJpY2U6IDQsIHF1YW50aXR5OiA1LCBwcm9kdWN0czogWzIsMyw0XSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgdmFyaWFibGVgIEFuIG9iamVjdCBjb21wb3NlZCBvZiB0aGUgbW9kZWwgdmFyaWFibGVzIGFuZCB0aGUgdmFsdWVzIHRvIHNhdmUuIEFsdGVybmF0aXZlbHksIGEgc3RyaW5nIHdpdGggdGhlIG5hbWUgb2YgdGhlIHZhcmlhYmxlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbGAgKE9wdGlvbmFsKSBJZiBwYXNzaW5nIGEgc3RyaW5nIGZvciBgdmFyaWFibGVgLCB1c2UgdGhpcyBhcmd1bWVudCBmb3IgdGhlIHZhbHVlIHRvIHNhdmUuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uICh2YXJpYWJsZSwgdmFsLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHZhcmlhYmxlID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHZhbDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW3ZhcmlhYmxlXSA9IHZhbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoLmNhbGwodGhpcywgYXR0cnMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIE5vdCBBdmFpbGFibGUgdW50aWwgdW5kZXJseWluZyBBUEkgc3VwcG9ydHMgUFVULiBPdGhlcndpc2Ugc2F2ZSB3b3VsZCBiZSBQVVQgYW5kIG1lcmdlIHdvdWxkIGJlIFBBVENIXG4gICAgICAgIC8vICpcbiAgICAgICAgLy8gICogU2F2ZSB2YWx1ZXMgdG8gdGhlIGFwaS4gTWVyZ2VzIGFycmF5cywgYnV0IG90aGVyd2lzZSBzYW1lIGFzIHNhdmVcbiAgICAgICAgLy8gICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSB2YXJpYWJsZSBPYmplY3Qgd2l0aCBhdHRyaWJ1dGVzLCBvciBzdHJpbmcga2V5XG4gICAgICAgIC8vICAqIEBwYXJhbSB7T2JqZWN0fSB2YWwgT3B0aW9uYWwgaWYgcHJldiBwYXJhbWV0ZXIgd2FzIGEgc3RyaW5nLCBzZXQgdmFsdWUgaGVyZVxuICAgICAgICAvLyAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xuICAgICAgICAvLyAgKlxuICAgICAgICAvLyAgKiBAZXhhbXBsZVxuICAgICAgICAvLyAgKiAgICAgdnMubWVyZ2UoeyBwcmljZTogNCwgcXVhbnRpdHk6IDUsIHByb2R1Y3RzOiBbMiwzLDRdIH0pXG4gICAgICAgIC8vICAqICAgICB2cy5tZXJnZSgncHJpY2UnLCA0KTtcblxuICAgICAgICAvLyBtZXJnZTogZnVuY3Rpb24gKHZhcmlhYmxlLCB2YWwsIG9wdGlvbnMpIHtcbiAgICAgICAgLy8gICAgIHZhciBhdHRycztcbiAgICAgICAgLy8gICAgIGlmICh0eXBlb2YgdmFyaWFibGUgPT09ICdvYmplY3QnKSB7XG4gICAgICAgIC8vICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgIC8vICAgICAgIG9wdGlvbnMgPSB2YWw7XG4gICAgICAgIC8vICAgICB9IGVsc2Uge1xuICAgICAgICAvLyAgICAgICAoYXR0cnMgPSB7fSlbdmFyaWFibGVdID0gdmFsO1xuICAgICAgICAvLyAgICAgfVxuICAgICAgICAvLyAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAvLyAgICAgcmV0dXJuIGh0dHAucGF0Y2guY2FsbCh0aGlzLCBhdHRycywgaHR0cE9wdGlvbnMpO1xuICAgICAgICAvLyB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICogIyMgV29ybGQgQVBJIEFkYXB0ZXJcbiAqXG4gKiBBIFtydW5dKC4uLy4uLy4uL2dsb3NzYXJ5LyNydW4pIGlzIGEgY29sbGVjdGlvbiBvZiBlbmQgdXNlciBpbnRlcmFjdGlvbnMgd2l0aCBhIHByb2plY3QgYW5kIGl0cyBtb2RlbCAtLSBpbmNsdWRpbmcgc2V0dGluZyB2YXJpYWJsZXMsIG1ha2luZyBkZWNpc2lvbnMsIGFuZCBjYWxsaW5nIG9wZXJhdGlvbnMuIEZvciBidWlsZGluZyBtdWx0aXBsYXllciBzaW11bGF0aW9ucyB5b3UgdHlwaWNhbGx5IHdhbnQgbXVsdGlwbGUgZW5kIHVzZXJzIHRvIHNoYXJlIHRoZSBzYW1lIHNldCBvZiBpbnRlcmFjdGlvbnMsIGFuZCB3b3JrIHdpdGhpbiBhIGNvbW1vbiBzdGF0ZS4gRXBpY2VudGVyIGFsbG93cyB5b3UgdG8gY3JlYXRlIFwid29ybGRzXCIgdG8gaGFuZGxlIHN1Y2ggY2FzZXMuIE9ubHkgW3RlYW0gcHJvamVjdHNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN0ZWFtKSBjYW4gYmUgbXVsdGlwbGF5ZXIuXG4gKlxuICogVGhlIFdvcmxkIEFQSSBBZGFwdGVyIGFsbG93cyB5b3UgdG8gY3JlYXRlLCBhY2Nlc3MsIGFuZCBtYW5pcHVsYXRlIG11bHRpcGxheWVyIHdvcmxkcyB3aXRoaW4geW91ciBFcGljZW50ZXIgcHJvamVjdC4gWW91IGNhbiB1c2UgdGhpcyB0byBhZGQgYW5kIHJlbW92ZSBlbmQgdXNlcnMgZnJvbSB0aGUgd29ybGQsIGFuZCB0byBjcmVhdGUsIGFjY2VzcywgYW5kIHJlbW92ZSB0aGVpciBydW5zLiBCZWNhdXNlIG9mIHRoaXMsIHR5cGljYWxseSB0aGUgV29ybGQgQWRhcHRlciBpcyB1c2VkIGZvciBmYWNpbGl0YXRvciBwYWdlcyBpbiB5b3VyIHByb2plY3QuIChUaGUgcmVsYXRlZCBbV29ybGQgTWFuYWdlcl0oLi4vd29ybGQtbWFuYWdlci8pIHByb3ZpZGVzIGFuIGVhc3kgd2F5IHRvIGFjY2VzcyBydW5zIGFuZCB3b3JsZHMgZm9yIHBhcnRpY3VsYXIgZW5kIHVzZXJzLCBzbyBpcyB0eXBpY2FsbHkgdXNlZCBpbiBwYWdlcyB0aGF0IGVuZCB1c2VycyB3aWxsIGludGVyYWN0IHdpdGguKVxuICpcbiAqIEFzIHdpdGggYWxsIHRoZSBvdGhlciBbQVBJIEFkYXB0ZXJzXSguLi8uLi8pLCBhbGwgbWV0aG9kcyB0YWtlIGluIGFuIFwib3B0aW9uc1wiIG9iamVjdCBhcyB0aGUgbGFzdCBwYXJhbWV0ZXIuIFRoZSBvcHRpb25zIGNhbiBiZSB1c2VkIHRvIGV4dGVuZC9vdmVycmlkZSB0aGUgV29ybGQgQVBJIFNlcnZpY2UgZGVmYXVsdHMuXG4gKlxuICogVG8gdXNlIHRoZSBXb3JsZCBBZGFwdGVyLCBpbnN0YW50aWF0ZSBpdCBhbmQgdGhlbiBhY2Nlc3MgdGhlIG1ldGhvZHMgcHJvdmlkZWQuIEluc3RhbnRpYXRpbmcgcmVxdWlyZXMgdGhlIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGluIHRoZSBFcGljZW50ZXIgdXNlciBpbnRlcmZhY2UpLCBwcm9qZWN0IGlkICgqKlByb2plY3QgSUQqKiksIGFuZCBncm91cCAoKipHcm91cCBOYW1lKiopLlxuICpcbiAqICAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICogICAgICAgd2EuY3JlYXRlKClcbiAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gKiAgICAgICAgICAgICAgLy8gY2FsbCBtZXRob2RzLCBlLmcuIHdhLmFkZFVzZXJzKClcbiAqICAgICAgICAgIH0pO1xuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xuLy8gdmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcblxudmFyIGFwaUJhc2UgPSAnbXVsdGlwbGF5ZXIvJztcbnZhciBhc3NpZ25tZW50RW5kcG9pbnQgPSBhcGlCYXNlICsgJ2Fzc2lnbic7XG52YXIgYXBpRW5kcG9pbnQgPSBhcGlCYXNlICsgJ3dvcmxkJztcbnZhciBwcm9qZWN0RW5kcG9pbnQgPSBhcGlCYXNlICsgJ3Byb2plY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgIHRva2VuOiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcHJvamVjdDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKS4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGdyb3VwIG5hbWUuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGdyb3VwOiB1bmRlZmluZWQsXG5cbiAgICAgICAvKipcbiAgICAgICAgICogVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBydW5zIGluIHRoaXMgd29ybGQuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIG1vZGVsOiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENyaXRlcmlhIGJ5IHdoaWNoIHRvIGZpbHRlciB3b3JsZC4gQ3VycmVudGx5IG9ubHkgc3VwcG9ydHMgd29ybGQtaWRzIGFzIGZpbHRlcnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBmaWx0ZXI6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZW5pZW5jZSBhbGlhcyBmb3IgZmlsdGVyXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBpZDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgY29tcGxldGVzIHN1Y2Nlc3NmdWxseS4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIHN1Y2Nlc3M6ICQubm9vcCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgZmFpbHMuIERlZmF1bHRzIHRvIGAkLm5vb3BgLlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICBlcnJvcjogJC5ub29wXG4gICAgfTtcblxuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmlkKSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHNlcnZpY2VPcHRpb25zLmlkO1xuICAgIH1cblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIGlmICghc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50ID0gdXJsQ29uZmlnLmFjY291bnRQYXRoO1xuICAgIH1cblxuICAgIGlmICghc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0ID0gdXJsQ29uZmlnLnByb2plY3RQYXRoO1xuICAgIH1cblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuXG4gICAgdmFyIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMuaWQpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IG9wdGlvbnMuaWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmZpbHRlcjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyB3b3JsZCBpZCBzcGVjaWZpZWQgdG8gYXBwbHkgb3BlcmF0aW9ucyBhZ2FpbnN0LiBUaGlzIGNvdWxkIGhhcHBlbiBpZiB0aGUgdXNlciBpcyBub3QgYXNzaWduZWQgdG8gYSB3b3JsZCBhbmQgaXMgdHJ5aW5nIHRvIHdvcmsgd2l0aCBydW5zIGZyb20gdGhhdCB3b3JsZC4nKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGlmICghb3B0aW9ucy5tb2RlbCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBtb2RlbCBzcGVjaWZpZWQgdG8gZ2V0IHRoZSBjdXJyZW50IHJ1bicpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIG5ldyBXb3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIFVzaW5nIHRoaXMgbWV0aG9kIGlzIHJhcmUuIEl0IGlzIG1vcmUgY29tbW9uIHRvIGNyZWF0ZSB3b3JsZHMgYXV0b21hdGljYWxseSB3aGlsZSB5b3UgYGF1dG9Bc3NpZ24oKWAgZW5kIHVzZXJzIHRvIHdvcmxkcy4gKEluIHRoaXMgY2FzZSwgY29uZmlndXJhdGlvbiBkYXRhIGZvciB0aGUgd29ybGQsIHN1Y2ggYXMgdGhlIHJvbGVzLCBhcmUgcmVhZCBmcm9tIHRoZSBwcm9qZWN0LWxldmVsIHdvcmxkIGNvbmZpZ3VyYXRpb24gaW5mb3JtYXRpb24sIGZvciBleGFtcGxlIGJ5IGBnZXRQcm9qZWN0U2V0dGluZ3MoKWAuKVxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKHtcbiAgICAgICAgKiAgICAgICAgICAgcm9sZXM6IFsnVlAgTWFya2V0aW5nJywgJ1ZQIFNhbGVzJywgJ1ZQIEVuZ2luZWVyaW5nJ11cbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBQYXJhbWV0ZXJzIHRvIGNyZWF0ZSB0aGUgd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZ3JvdXBgIChPcHRpb25hbCkgVGhlICoqR3JvdXAgTmFtZSoqIHRvIGNyZWF0ZSB0aGlzIHdvcmxkIHVuZGVyLiBPbmx5IGVuZCB1c2VycyBpbiB0aGlzIGdyb3VwIGFyZSBlbGlnaWJsZSB0byBqb2luIHRoZSB3b3JsZC4gT3B0aW9uYWwgaGVyZTsgcmVxdWlyZWQgd2hlbiBpbnN0YW50aWF0aW5nIHRoZSBzZXJ2aWNlIChgbmV3IEYuc2VydmljZS5Xb3JsZCgpYCkuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMucm9sZXNgIChPcHRpb25hbCkgVGhlIGxpc3Qgb2Ygcm9sZXMgKHN0cmluZ3MpIGZvciB0aGlzIHdvcmxkLiBTb21lIHdvcmxkcyBoYXZlIHNwZWNpZmljIHJvbGVzIHRoYXQgKiptdXN0KiogYmUgZmlsbGVkIGJ5IGVuZCB1c2Vycy4gTGlzdGluZyB0aGUgcm9sZXMgYWxsb3dzIHlvdSB0byBhdXRvYXNzaWduIHVzZXJzIHRvIHdvcmxkcyBhbmQgZW5zdXJlIHRoYXQgYWxsIHJvbGVzIGFyZSBmaWxsZWQgaW4gZWFjaCB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtcy5vcHRpb25hbFJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIG9wdGlvbmFsIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbWF5KiogYmUgZmlsbGVkIGJ5IGVuZCB1c2Vycy4gTGlzdGluZyB0aGUgb3B0aW9uYWwgcm9sZXMgYXMgcGFydCBvZiB0aGUgd29ybGQgb2JqZWN0IGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtpbnRlZ2VyfSBgcGFyYW1zLm1pblVzZXJzYCAoT3B0aW9uYWwpIFRoZSBtaW5pbXVtIG51bWJlciBvZiB1c2VycyBmb3IgdGhlIHdvcmxkLiBJbmNsdWRpbmcgdGhpcyBudW1iZXIgYWxsb3dzIHlvdSB0byBhdXRvYXNzaWduIGVuZCB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IHRoZSBjb3JyZWN0IG51bWJlciBvZiB1c2VycyBhcmUgaW4gZWFjaCB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgY3JlYXRlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgY3JlYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSB9KTtcbiAgICAgICAgICAgIHZhciB3b3JsZEFwaVBhcmFtcyA9IFsnc2NvcGUnLCAnZmlsZXMnLCAncm9sZXMnLCAnb3B0aW9uYWxSb2xlcycsICdtaW5Vc2VycycsICdncm91cCcsICduYW1lJ107XG4gICAgICAgICAgICB2YXIgdmFsaWRQYXJhbXMgPSBfcGljayhzZXJ2aWNlT3B0aW9ucywgWydhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSk7XG4gICAgICAgICAgICAvLyB3aGl0ZWxpc3QgdGhlIGZpZWxkcyB0aGF0IHdlIGFjdHVhbGx5IGNhbiBzZW5kIHRvIHRoZSBhcGlcbiAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgd29ybGRBcGlQYXJhbXMpO1xuXG4gICAgICAgICAgICAvLyBhY2NvdW50IGFuZCBwcm9qZWN0IGdvIGluIHRoZSBib2R5LCBub3QgaW4gdGhlIHVybFxuICAgICAgICAgICAgcGFyYW1zID0gJC5leHRlbmQoe30sIHZhbGlkUGFyYW1zLCBwYXJhbXMpO1xuXG4gICAgICAgICAgICB2YXIgb2xkU3VjY2VzcyA9IGNyZWF0ZU9wdGlvbnMuc3VjY2VzcztcbiAgICAgICAgICAgIGNyZWF0ZU9wdGlvbnMuc3VjY2VzcyA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHJlc3BvbnNlLmlkOyAvL2FsbCBmdXR1cmUgY2hhaW5lZCBjYWxscyB0byBvcGVyYXRlIG9uIHRoaXMgaWRcbiAgICAgICAgICAgICAgICByZXR1cm4gb2xkU3VjY2Vzcy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChwYXJhbXMsIGNyZWF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgYSBXb3JsZCwgZm9yIGV4YW1wbGUgdG8gcmVwbGFjZSB0aGUgcm9sZXMgaW4gdGhlIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogVHlwaWNhbGx5LCB5b3UgY29tcGxldGUgd29ybGQgY29uZmlndXJhdGlvbiBhdCB0aGUgcHJvamVjdCBsZXZlbCwgcmF0aGVyIHRoYW4gYXQgdGhlIHdvcmxkIGxldmVsLiBGb3IgZXhhbXBsZSwgZWFjaCB3b3JsZCBpbiB5b3VyIHByb2plY3QgcHJvYmFibHkgaGFzIHRoZSBzYW1lIHJvbGVzIGZvciBlbmQgdXNlcnMuIEFuZCB5b3VyIHByb2plY3QgaXMgcHJvYmFibHkgZWl0aGVyIGNvbmZpZ3VyZWQgc28gdGhhdCBhbGwgZW5kIHVzZXJzIHNoYXJlIHRoZSBzYW1lIHdvcmxkIChhbmQgcnVuKSwgb3Igc21hbGxlciBzZXRzIG9mIGVuZCB1c2VycyBzaGFyZSB3b3JsZHMg4oCUIGJ1dCBub3QgYm90aC4gSG93ZXZlciwgdGhpcyBtZXRob2QgaXMgYXZhaWxhYmxlIGlmIHlvdSBuZWVkIHRvIHVwZGF0ZSB0aGUgY29uZmlndXJhdGlvbiBvZiBhIHBhcnRpY3VsYXIgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EudXBkYXRlKHsgcm9sZXM6IFsnVlAgTWFya2V0aW5nJywgJ1ZQIFNhbGVzJywgJ1ZQIEVuZ2luZWVyaW5nJ10gfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFBhcmFtZXRlcnMgdG8gdXBkYXRlIHRoZSB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5uYW1lYCBBIHN0cmluZyBpZGVudGlmaWVyIGZvciB0aGUgbGlua2VkIGVuZCB1c2VycywgZm9yIGV4YW1wbGUsIFwibmFtZVwiOiBcIk91ciBUZWFtXCIuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMucm9sZXNgIChPcHRpb25hbCkgVGhlIGxpc3Qgb2Ygcm9sZXMgKHN0cmluZ3MpIGZvciB0aGlzIHdvcmxkLiBTb21lIHdvcmxkcyBoYXZlIHNwZWNpZmljIHJvbGVzIHRoYXQgKiptdXN0KiogYmUgZmlsbGVkIGJ5IGVuZCB1c2Vycy4gTGlzdGluZyB0aGUgcm9sZXMgYWxsb3dzIHlvdSB0byBhdXRvYXNzaWduIHVzZXJzIHRvIHdvcmxkcyBhbmQgZW5zdXJlIHRoYXQgYWxsIHJvbGVzIGFyZSBmaWxsZWQgaW4gZWFjaCB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtcy5vcHRpb25hbFJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIG9wdGlvbmFsIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbWF5KiogYmUgZmlsbGVkIGJ5IGVuZCB1c2Vycy4gTGlzdGluZyB0aGUgb3B0aW9uYWwgcm9sZXMgYXMgcGFydCBvZiB0aGUgd29ybGQgb2JqZWN0IGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtpbnRlZ2VyfSBgcGFyYW1zLm1pblVzZXJzYCAoT3B0aW9uYWwpIFRoZSBtaW5pbXVtIG51bWJlciBvZiB1c2VycyBmb3IgdGhlIHdvcmxkLiBJbmNsdWRpbmcgdGhpcyBudW1iZXIgYWxsb3dzIHlvdSB0byBhdXRvYXNzaWduIGVuZCB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IHRoZSBjb3JyZWN0IG51bWJlciBvZiB1c2VycyBhcmUgaW4gZWFjaCB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgdXBkYXRlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgd2hpdGVsaXN0ID0gWydyb2xlcycsICdvcHRpb25hbFJvbGVzJywgJ21pblVzZXJzJ107XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgdXBkYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMgfHwge30sIHdoaXRlbGlzdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKHBhcmFtcywgdXBkYXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogRGVsZXRlcyBhbiBleGlzdGluZyB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIFRoaXMgZnVuY3Rpb24gb3B0aW9uYWxseSB0YWtlcyBvbmUgYXJndW1lbnQuIElmIHRoZSBhcmd1bWVudCBpcyBhIHN0cmluZywgaXQgaXMgdGhlIGlkIG9mIHRoZSB3b3JsZCB0byBkZWxldGUuIElmIHRoZSBhcmd1bWVudCBpcyBhbiBvYmplY3QsIGl0IGlzIHRoZSBvdmVycmlkZSBmb3IgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuZGVsZXRlKCk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtTdHJpbmd8T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBUaGUgaWQgb2YgdGhlIHdvcmxkIHRvIGRlbGV0ZSwgb3Igb3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgZGVsZXRlOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IChvcHRpb25zICYmICh0eXBlb2Ygb3B0aW9ucyA9PT0gJ3N0cmluZycpKSA/IHsgZmlsdGVyOiBvcHRpb25zIH0gOiB7fTtcbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZGVsZXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZGVsZXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogVXBkYXRlcyB0aGUgY29uZmlndXJhdGlvbiBmb3IgdGhlIGN1cnJlbnQgaW5zdGFuY2Ugb2YgdGhlIFdvcmxkIEFQSSBBZGFwdGVyIChpbmNsdWRpbmcgYWxsIHN1YnNlcXVlbnQgZnVuY3Rpb24gY2FsbHMsIHVudGlsIHRoZSBjb25maWd1cmF0aW9uIGlzIHVwZGF0ZWQgYWdhaW4pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7Li4ufSkudXBkYXRlQ29uZmlnKHsgZmlsdGVyOiAnMTIzJyB9KS5hZGRVc2VyKHsgdXNlcklkOiAnMTIzJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBjb25maWdgIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB0byB1c2UgaW4gdXBkYXRpbmcgZXhpc3RpbmcgY29uZmlndXJhdGlvbi5cbiAgICAgICAgKi9cbiAgICAgICAgdXBkYXRlQ29uZmlnOiBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICAgICAgICAkLmV4dGVuZChzZXJ2aWNlT3B0aW9ucywgY29uZmlnKTtcblxuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogTGlzdHMgYWxsIHdvcmxkcyBmb3IgYSBnaXZlbiBhY2NvdW50LCBwcm9qZWN0LCBhbmQgZ3JvdXAuIEFsbCB0aHJlZSBhcmUgcmVxdWlyZWQsIGFuZCBpZiBub3Qgc3BlY2lmaWVkIGFzIHBhcmFtZXRlcnMsIGFyZSByZWFkIGZyb20gdGhlIHNlcnZpY2UuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgLy8gbGlzdHMgYWxsIHdvcmxkcyBpbiBncm91cCBcInRlYW0xXCJcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmxpc3QoKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgICAgICAgLy8gbGlzdHMgYWxsIHdvcmxkcyBpbiBncm91cCBcIm90aGVyLWdyb3VwLW5hbWVcIlxuICAgICAgICAqICAgICAgICAgICAgICAgd2EubGlzdCh7IGdyb3VwOiAnb3RoZXItZ3JvdXAtbmFtZScgfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGxpc3Q6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFyIGZpbHRlcnMgPSBfcGljayhnZXRPcHRpb25zLCBbJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCddKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGZpbHRlcnMsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgYWxsIHdvcmxkcyB0aGF0IGFuIGVuZCB1c2VyIGJlbG9uZ3MgdG8gZm9yIGEgZ2l2ZW4gYWNjb3VudCAodGVhbSksIHByb2plY3QsIGFuZCBncm91cC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5nZXRXb3JsZHNGb3JVc2VyKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnKVxuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJJZGAgVGhlIGB1c2VySWRgIG9mIHRoZSB1c2VyIHdob3NlIHdvcmxkcyBhcmUgYmVpbmcgcmV0cmlldmVkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0V29ybGRzRm9yVXNlcjogZnVuY3Rpb24gKHVzZXJJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBmaWx0ZXJzID0gJC5leHRlbmQoXG4gICAgICAgICAgICAgICAgX3BpY2soZ2V0T3B0aW9ucywgWydhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSksXG4gICAgICAgICAgICAgICAgeyB1c2VySWQ6IHVzZXJJZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoZmlsdGVycywgZ2V0T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIExvYWQgaW5mb3JtYXRpb24gZm9yIGEgc3BlY2lmaWMgd29ybGQuIEFsbCBmdXJ0aGVyIGNhbGxzIHRvIHRoZSB3b3JsZCBzZXJ2aWNlIHdpbGwgdXNlIHRoZSBpZCBwcm92aWRlZC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGB3b3JsZElkYCBUaGUgaWQgb2YgdGhlIHdvcmxkIHRvIGxvYWQuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBpZiAod29ybGRJZCkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHByb3ZpZGUgYSB3b3JsZGlkIHRvIGxvYWQnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnLycgfSk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoJycsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBBZGRzIGFuIGVuZCB1c2VyIG9yIGxpc3Qgb2YgZW5kIHVzZXJzIHRvIGEgZ2l2ZW4gd29ybGQuIFRoZSBlbmQgdXNlciBtdXN0IGJlIGEgbWVtYmVyIG9mIHRoZSBgZ3JvdXBgIHRoYXQgaXMgYXNzb2NpYXRlZCB3aXRoIHRoaXMgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgLy8gYWRkIG9uZSB1c2VyXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJyk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMyddKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKHsgdXNlcklkOiAnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJywgcm9sZTogJ1ZQIFNhbGVzJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgICAgICAgLy8gYWRkIHNldmVyYWwgdXNlcnNcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKFtcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICB7IHVzZXJJZDogJ2E2ZmUwYzFlLWY0YjgtNGYwMS05ZjVmLTAxY2NmNGMyZWQ0NCcsXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgICByb2xlOiAnVlAgTWFya2V0aW5nJyB9LFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgIHsgdXNlcklkOiAnOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgIHJvbGU6ICdWUCBFbmdpbmVlcmluZycgfVxuICAgICAgICAqICAgICAgICAgICAgICAgXSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBvbmUgdXNlciB0byBhIHNwZWNpZmljIHdvcmxkXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJywgd29ybGQuaWQpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHsgZmlsdGVyOiB3b3JsZC5pZCB9KTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd8b2JqZWN0fGFycmF5fSBgdXNlcnNgIFVzZXIgaWQsIGFycmF5IG9mIHVzZXIgaWRzLCBvYmplY3QsIG9yIGFycmF5IG9mIG9iamVjdHMgb2YgdGhlIHVzZXJzIHRvIGFkZCB0byB0aGlzIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgdXNlcnMucm9sZWAgVGhlIGByb2xlYCB0aGUgdXNlciBzaG91bGQgaGF2ZSBpbiB0aGUgd29ybGQuIEl0IGlzIHVwIHRvIHRoZSBjYWxsZXIgdG8gZW5zdXJlLCBpZiBuZWVkZWQsIHRoYXQgdGhlIGByb2xlYCBwYXNzZWQgaW4gaXMgb25lIG9mIHRoZSBgcm9sZXNgIG9yIGBvcHRpb25hbFJvbGVzYCBvZiB0aGlzIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgd29ybGRJZGAgVGhlIHdvcmxkIHRvIHdoaWNoIHRoZSB1c2VycyBzaG91bGQgYmUgYWRkZWQuIElmIG5vdCBzcGVjaWZpZWQsIHRoZSBmaWx0ZXIgcGFyYW1ldGVyIG9mIHRoZSBgb3B0aW9uc2Agb2JqZWN0IGlzIHVzZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBhZGRVc2VyczogZnVuY3Rpb24gKHVzZXJzLCB3b3JsZElkLCBvcHRpb25zKSB7XG5cbiAgICAgICAgICAgIGlmICghdXNlcnMpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwcm92aWRlIGEgbGlzdCBvZiB1c2VycyB0byBhZGQgdG8gdGhlIHdvcmxkJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIG5vcm1hbGl6ZSB0aGUgbGlzdCBvZiB1c2VycyB0byBhbiBhcnJheSBvZiB1c2VyIG9iamVjdHNcbiAgICAgICAgICAgIHVzZXJzID0gJC5tYXAoW10uY29uY2F0KHVzZXJzKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgICAgICB2YXIgaXNPYmplY3QgPSAkLmlzUGxhaW5PYmplY3QodSk7XG5cbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHUgIT09ICdzdHJpbmcnICYmICFpc09iamVjdCkge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NvbWUgb2YgdGhlIHVzZXJzIGluIHRoZSBsaXN0IGFyZSBub3QgaW4gdGhlIHZhbGlkIGZvcm1hdDogJyArIHUpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBpc09iamVjdCA/IHUgOiB7IHVzZXJJZDogdSB9O1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIC8vIGNoZWNrIGlmIG9wdGlvbnMgd2VyZSBwYXNzZWQgYXMgdGhlIHNlY29uZCBwYXJhbWV0ZXJcbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qod29ybGRJZCkgJiYgIW9wdGlvbnMpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zID0gd29ybGRJZDtcbiAgICAgICAgICAgICAgICB3b3JsZElkID0gbnVsbDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIC8vIHdlIG11c3QgaGF2ZSBvcHRpb25zIGJ5IG5vd1xuICAgICAgICAgICAgaWYgKHR5cGVvZiB3b3JsZElkID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMuZmlsdGVyID0gd29ybGRJZDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciB1cGRhdGVPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2VycycgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdCh1c2VycywgdXBkYXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogVXBkYXRlcyB0aGUgcm9sZSBvZiBhbiBlbmQgdXNlciBpbiBhIGdpdmVuIHdvcmxkLiAoWW91IGNhbiBvbmx5IHVwZGF0ZSBvbmUgZW5kIHVzZXIgYXQgYSB0aW1lLilcbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKS50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgIHdhLmFkZFVzZXJzKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnKTtcbiAgICAgICAgKiAgICAgICAgICAgd2EudXBkYXRlVXNlcih7IHVzZXJJZDogJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHJvbGU6ICdsZWFkZXInIH0pO1xuICAgICAgICAqICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgdXNlcmAgVXNlciBvYmplY3Qgd2l0aCBgdXNlcklkYCBhbmQgdGhlIG5ldyBgcm9sZWAuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZVVzZXI6IGZ1bmN0aW9uICh1c2VyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgaWYgKCF1c2VyIHx8ICF1c2VyLnVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignWW91IG5lZWQgdG8gcGFzcyBhIHVzZXJJZCB0byB1cGRhdGUgZnJvbSB0aGUgd29ybGQnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBwYXRjaE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3VzZXJzLycgKyB1c2VyLnVzZXJJZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wYXRjaChfcGljayh1c2VyLCAncm9sZScpLCBwYXRjaE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJlbW92ZXMgYW4gZW5kIHVzZXIgZnJvbSBhIGdpdmVuIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKFsnYTZmZTBjMWUtZjRiOC00ZjAxLTlmNWYtMDFjY2Y0YzJlZDQ0JywgJzhmMjYwNGNmLTk2Y2QtNDQ5Zi04MmZhLWUzMzE1MzA3MzRlZSddKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnJlbW92ZVVzZXIoJ2E2ZmUwYzFlLWY0YjgtNGYwMS05ZjVmLTAxY2NmNGMyZWQ0NCcpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EucmVtb3ZlVXNlcih7IHVzZXJJZDogJzhmMjYwNGNmLTk2Y2QtNDQ5Zi04MmZhLWUzMzE1MzA3MzRlZScgfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKiogUGFyYW1ldGVycyAqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fHN0cmluZ30gYHVzZXJgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB0byByZW1vdmUgZnJvbSB0aGUgd29ybGQsIG9yIGFuIG9iamVjdCBjb250YWluaW5nIHRoZSBgdXNlcklkYCBmaWVsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIHJlbW92ZVVzZXI6IGZ1bmN0aW9uICh1c2VyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgaWYgKHR5cGVvZiB1c2VyID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIHVzZXIgPSB7IHVzZXJJZDogdXNlciB9O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoIXVzZXIudXNlcklkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdZb3UgbmVlZCB0byBwYXNzIGEgdXNlcklkIHRvIHJlbW92ZSBmcm9tIHRoZSB3b3JsZCcpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3VzZXJzLycgKyB1c2VyLnVzZXJJZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZ2V0T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogR2V0cyB0aGUgcnVuIGlkIG9mIGN1cnJlbnQgcnVuIGZvciB0aGUgZ2l2ZW4gd29ybGQuIElmIHRoZSB3b3JsZCBkb2VzIG5vdCBoYXZlIGEgcnVuLCBjcmVhdGVzIGEgbmV3IG9uZSBhbmQgcmV0dXJucyB0aGUgcnVuIGlkLlxuICAgICAgICAqXG4gICAgICAgICogUmVtZW1iZXIgdGhhdCBhIFtydW5dKC4uLy4uL2dsb3NzYXJ5LyNydW4pIGlzIGEgY29sbGVjdGlvbiBvZiBpbnRlcmFjdGlvbnMgd2l0aCBhIHByb2plY3QgYW5kIGl0cyBtb2RlbC4gSW4gdGhlIGNhc2Ugb2YgbXVsdGlwbGF5ZXIgcHJvamVjdHMsIHRoZSBydW4gaXMgc2hhcmVkIGJ5IGFsbCBlbmQgdXNlcnMgaW4gdGhlIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmdldEN1cnJlbnRSdW5JZCh7IG1vZGVsOiAnbW9kZWwucHknIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zLm1vZGVsYCBUaGUgbW9kZWwgZmlsZSB0byB1c2UgdG8gY3JlYXRlIGEgcnVuIGlmIG5lZWRlZC5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFJ1bklkOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvcnVuJyB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB2YWxpZGF0ZU1vZGVsT3JUaHJvd0Vycm9yKGdldE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChfcGljayhnZXRPcHRpb25zLCAnbW9kZWwnKSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogR2V0cyB0aGUgY3VycmVudCAobW9zdCByZWNlbnQpIHdvcmxkIGZvciB0aGUgZ2l2ZW4gZW5kIHVzZXIgaW4gdGhlIGdpdmVuIGdyb3VwLiBCcmluZ3MgdGhpcyBtb3N0IHJlY2VudCB3b3JsZCBpbnRvIG1lbW9yeSBpZiBuZWVkZWQuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKCc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgLy8gdXNlIGRhdGEgZnJvbSB3b3JsZFxuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJJZGAgVGhlIGB1c2VySWRgIG9mIHRoZSB1c2VyIHdob3NlIGN1cnJlbnQgKG1vc3QgcmVjZW50KSB3b3JsZCBpcyBiZWluZyByZXRyaWV2ZWQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBncm91cE5hbWVgIChPcHRpb25hbCkgVGhlIG5hbWUgb2YgdGhlIGdyb3VwLiBJZiBub3QgcHJvdmlkZWQsIGRlZmF1bHRzIHRvIHRoZSBncm91cCB1c2VkIHRvIGNyZWF0ZSB0aGUgc2VydmljZS5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFdvcmxkRm9yVXNlcjogZnVuY3Rpb24gKHVzZXJJZCwgZ3JvdXBOYW1lKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgICAgIHRoaXMuZ2V0V29ybGRzRm9yVXNlcih1c2VySWQsIHsgZ3JvdXA6IGdyb3VwTmFtZSB9KVxuICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICh3b3JsZHMpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gYXNzdW1lIHRoZSBtb3N0IHJlY2VudCB3b3JsZCBhcyB0aGUgJ2FjdGl2ZScgd29ybGRcbiAgICAgICAgICAgICAgICAgICAgd29ybGRzLnNvcnQoZnVuY3Rpb24gKGEsIGIpIHsgcmV0dXJuIG5ldyBEYXRlKGIubGFzdE1vZGlmaWVkKSAtIG5ldyBEYXRlKGEubGFzdE1vZGlmaWVkKTsgfSk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBjdXJyZW50V29ybGQgPSB3b3JsZHNbMF07XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGN1cnJlbnRXb3JsZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gIGN1cnJlbnRXb3JsZC5pZDtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGN1cnJlbnRXb3JsZCwgbWUpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgdGhlIGN1cnJlbnQgcnVuIGZyb20gdGhlIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogKE5vdGUgdGhhdCB0aGUgd29ybGQgaWQgcmVtYWlucyBwYXJ0IG9mIHRoZSBydW4gcmVjb3JkLCBpbmRpY2F0aW5nIHRoYXQgdGhlIHJ1biB3YXMgZm9ybWVybHkgYW4gYWN0aXZlIHJ1biBmb3IgdGhlIHdvcmxkLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuZGVsZXRlUnVuKCdzYW1wbGUtd29ybGQtaWQnKTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgd29ybGRJZGAgVGhlIGB3b3JsZElkYCBvZiB0aGUgd29ybGQgZnJvbSB3aGljaCB0aGUgY3VycmVudCBydW4gaXMgYmVpbmcgZGVsZXRlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGRlbGV0ZVJ1bjogZnVuY3Rpb24gKHdvcmxkSWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICBpZiAod29ybGRJZCkge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMuZmlsdGVyID0gd29ybGRJZDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBkZWxldGVPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy9ydW4nIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmRlbGV0ZShudWxsLCBkZWxldGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBDcmVhdGVzIGEgbmV3IHJ1biBmb3IgdGhlIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKCc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICB3YS5uZXdSdW5Gb3JXb3JsZCh3b3JsZC5pZCk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB3b3JsZElkYCB3b3JsZElkIGluIHdoaWNoIHdlIGNyZWF0ZSB0aGUgbmV3IHJ1bi5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zLm1vZGVsYCBUaGUgbW9kZWwgZmlsZSB0byB1c2UgdG8gY3JlYXRlIGEgcnVuIGlmIG5lZWRlZC5cbiAgICAgICAgKi9cbiAgICAgICAgbmV3UnVuRm9yV29ybGQ6IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgY3VycmVudFJ1bk9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgZmlsdGVyOiB3b3JsZElkIHx8IHNlcnZpY2VPcHRpb25zLmZpbHRlciB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgICAgICAgICAgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvcihjdXJyZW50UnVuT3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiB0aGlzLmRlbGV0ZVJ1bih3b3JsZElkLCBvcHRpb25zKVxuICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLmdldEN1cnJlbnRSdW5JZChjdXJyZW50UnVuT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQXNzaWducyBlbmQgdXNlcnMgdG8gd29ybGRzLCBjcmVhdGluZyBuZXcgd29ybGRzIGFzIGFwcHJvcHJpYXRlLCBhdXRvbWF0aWNhbGx5LiBBc3NpZ25zIGFsbCBlbmQgdXNlcnMgaW4gdGhlIGdyb3VwLCBhbmQgY3JlYXRlcyBuZXcgd29ybGRzIGFzIG5lZWRlZCBiYXNlZCBvbiB0aGUgcHJvamVjdC1sZXZlbCB3b3JsZCBjb25maWd1cmF0aW9uIChyb2xlcywgb3B0aW9uYWwgcm9sZXMsIGFuZCBtaW5pbXVtIGVuZCB1c2VycyBwZXIgd29ybGQpLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmF1dG9Bc3NpZ24oKTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGF1dG9Bc3NpZ246IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFzc2lnbm1lbnRFbmRwb2ludCkgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFyIHBhcmFtcyA9IHtcbiAgICAgICAgICAgICAgICBhY2NvdW50OiBvcHQuYWNjb3VudCxcbiAgICAgICAgICAgICAgICBwcm9qZWN0OiBvcHQucHJvamVjdCxcbiAgICAgICAgICAgICAgICBncm91cDogb3B0Lmdyb3VwXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBpZiAob3B0Lm1heFVzZXJzKSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zLm1heFVzZXJzID0gb3B0Lm1heFVzZXJzO1xuICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBvcHQpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIHByb2plY3QncyB3b3JsZCBjb25maWd1cmF0aW9uLlxuICAgICAgICAqXG4gICAgICAgICogVHlwaWNhbGx5LCBldmVyeSBpbnRlcmFjdGlvbiB3aXRoIHlvdXIgcHJvamVjdCB1c2VzIHRoZSBzYW1lIGNvbmZpZ3VyYXRpb24gb2YgZWFjaCB3b3JsZC4gRm9yIGV4YW1wbGUsIGVhY2ggd29ybGQgaW4geW91ciBwcm9qZWN0IHByb2JhYmx5IGhhcyB0aGUgc2FtZSByb2xlcyBmb3IgZW5kIHVzZXJzLiBBbmQgeW91ciBwcm9qZWN0IGlzIHByb2JhYmx5IGVpdGhlciBjb25maWd1cmVkIHNvIHRoYXQgYWxsIGVuZCB1c2VycyBzaGFyZSB0aGUgc2FtZSB3b3JsZCAoYW5kIHJ1biksIG9yIHNtYWxsZXIgc2V0cyBvZiBlbmQgdXNlcnMgc2hhcmUgd29ybGRzIOKAlCBidXQgbm90IGJvdGguXG4gICAgICAgICpcbiAgICAgICAgKiAoVGhlIFtNdWx0aXBsYXllciBQcm9qZWN0IFJFU1QgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvbXVsdGlwbGF5ZXJfcHJvamVjdC8pIGFsbG93cyB5b3UgdG8gc2V0IHRoZXNlIHByb2plY3QtbGV2ZWwgd29ybGQgY29uZmlndXJhdGlvbnMuIFRoZSBXb3JsZCBBZGFwdGVyIHNpbXBseSByZXRyaWV2ZXMgdGhlbSwgZm9yIGV4YW1wbGUgc28gdGhleSBjYW4gYmUgdXNlZCBpbiBhdXRvLWFzc2lnbm1lbnQgb2YgZW5kIHVzZXJzIHRvIHdvcmxkcy4pXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuZ2V0UHJvamVjdFNldHRpbmdzKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oc2V0dGluZ3MpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHNldHRpbmdzLnJvbGVzKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHNldHRpbmdzLm9wdGlvbmFsUm9sZXMpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBnZXRQcm9qZWN0U2V0dGluZ3M6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKHByb2plY3RFbmRwb2ludCkgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgb3B0LnVybCArPSBbb3B0LmFjY291bnQsIG9wdC5wcm9qZWN0XS5qb2luKCcvJyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChudWxsLCBvcHQpO1xuICAgICAgICB9XG5cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqIEBjbGFzcyBDb29raWUgU3RvcmFnZSBTZXJ2aWNlXG4gKlxuICogQGV4YW1wbGVcbiAqICAgICAgdmFyIHBlb3BsZSA9IHJlcXVpcmUoJ2Nvb2tpZS1zdG9yZScpKHsgcm9vdDogJ3Blb3BsZScgfSk7XG4gICAgICAgIHBlb3BsZVxuICAgICAgICAgICAgLnNhdmUoe2xhc3ROYW1lOiAnc21pdGgnIH0pXG5cbiAqL1xuXG5cbid1c2Ugc3RyaWN0JztcblxuLy8gVGhpbiBkb2N1bWVudC5jb29raWUgd3JhcHBlciB0byBhbGxvdyB1bml0IHRlc3RpbmdcbnZhciBDb29raWUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5nZXQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBkb2N1bWVudC5jb29raWU7XG4gICAgfTtcblxuICAgIHRoaXMuc2V0ID0gZnVuY3Rpb24gKG5ld0Nvb2tpZSkge1xuICAgICAgICBkb2N1bWVudC5jb29raWUgPSBuZXdDb29raWU7XG4gICAgfTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBob3N0ID0gd2luZG93LmxvY2F0aW9uLmhvc3RuYW1lO1xuICAgIHZhciB2YWxpZEhvc3QgPSBob3N0LnNwbGl0KCcuJykubGVuZ3RoID4gMTtcbiAgICB2YXIgZG9tYWluID0gdmFsaWRIb3N0ID8gJy4nICsgaG9zdCA6IG51bGw7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBOYW1lIG9mIGNvbGxlY3Rpb25cbiAgICAgICAgICogQHR5cGUgeyBzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICByb290OiAnLycsXG5cbiAgICAgICAgZG9tYWluOiBkb21haW4sXG4gICAgICAgIGNvb2tpZTogbmV3IENvb2tpZSgpXG4gICAgfTtcbiAgICB0aGlzLnNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLy8gKiBUQkRcbiAgICAgICAgLy8gICogUXVlcnkgY29sbGVjdGlvbjsgdXNlcyBNb25nb0RCIHN5bnRheFxuICAgICAgICAvLyAgKiBAc2VlICA8VEJEOiBEYXRhIEFQSSBVUkw+XG4gICAgICAgIC8vICAqXG4gICAgICAgIC8vICAqIEBwYXJhbSB7IHN0cmluZ30gcXMgUXVlcnkgRmlsdGVyXG4gICAgICAgIC8vICAqIEBwYXJhbSB7IHN0cmluZ30gbGltaXRlcnMgQHNlZSA8VEJEOiB1cmwgZm9yIGxpbWl0cywgcGFnaW5nIGV0Yz5cbiAgICAgICAgLy8gICpcbiAgICAgICAgLy8gICogQGV4YW1wbGVcbiAgICAgICAgLy8gICogICAgIGNzLnF1ZXJ5KFxuICAgICAgICAvLyAgKiAgICAgIHsgbmFtZTogJ0pvaG4nLCBjbGFzc05hbWU6ICdDU0MxMDEnIH0sXG4gICAgICAgIC8vICAqICAgICAge2xpbWl0OiAxMH1cbiAgICAgICAgLy8gICogICAgIClcblxuICAgICAgICAvLyBxdWVyeTogZnVuY3Rpb24gKHFzLCBsaW1pdGVycykge1xuXG4gICAgICAgIC8vIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgY29va2llIHZhbHVlXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8T2JqZWN0fSBrZXkgICBJZiBnaXZlbiBhIGtleSBzYXZlIHZhbHVlcyB1bmRlciBpdCwgaWYgZ2l2ZW4gYW4gb2JqZWN0IGRpcmVjdGx5LCBzYXZlIHRvIHRvcC1sZXZlbCBhcGlcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSB2YWx1ZSAoT3B0aW9uYWwpXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIE92ZXJyaWRlcyBmb3Igc2VydmljZSBvcHRpb25zXG4gICAgICAgICAqXG4gICAgICAgICAqIEByZXR1cm4geyp9IFRoZSBzYXZlZCB2YWx1ZVxuICAgICAgICAgKlxuICAgICAgICAgKiBAZXhhbXBsZVxuICAgICAgICAgKiAgICAgY3Muc2V0KCdwZXJzb24nLCB7IGZpcnN0TmFtZTogJ2pvaG4nLCBsYXN0TmFtZTogJ3NtaXRoJyB9KTtcbiAgICAgICAgICogICAgIGNzLnNldCh7IG5hbWU6J3NtaXRoJywgYWdlOiczMicgfSk7XG4gICAgICAgICAqL1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbHVlLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgc2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB0aGlzLnNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRvbWFpbiA9IHNldE9wdGlvbnMuZG9tYWluO1xuICAgICAgICAgICAgdmFyIHBhdGggPSBzZXRPcHRpb25zLnJvb3Q7XG4gICAgICAgICAgICB2YXIgY29va2llID0gc2V0T3B0aW9ucy5jb29raWU7XG5cbiAgICAgICAgICAgIGNvb2tpZS5zZXQoZW5jb2RlVVJJQ29tcG9uZW50KGtleSkgKyAnPScgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmNvZGVVUklDb21wb25lbnQodmFsdWUpICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGRvbWFpbiA/ICc7IGRvbWFpbj0nICsgZG9tYWluIDogJycpICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHBhdGggPyAnOyBwYXRoPScgKyBwYXRoIDogJycpXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIExvYWQgY29va2llIHZhbHVlXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8T2JqZWN0fSBrZXkgICBJZiBnaXZlbiBhIGtleSBzYXZlIHZhbHVlcyB1bmRlciBpdCwgaWYgZ2l2ZW4gYW4gb2JqZWN0IGRpcmVjdGx5LCBzYXZlIHRvIHRvcC1sZXZlbCBhcGlcbiAgICAgICAgICogQHJldHVybiB7Kn0gVGhlIHZhbHVlIHN0b3JlZFxuICAgICAgICAgKlxuICAgICAgICAgKiBAZXhhbXBsZVxuICAgICAgICAgKiAgICAgY3MuZ2V0KCdwZXJzb24nKTtcbiAgICAgICAgICovXG4gICAgICAgIGdldDogZnVuY3Rpb24gKGtleSkge1xuICAgICAgICAgICAgdmFyIGNvb2tpZSA9IHRoaXMuc2VydmljZU9wdGlvbnMuY29va2llO1xuICAgICAgICAgICAgdmFyIGNvb2tpZVJlZyA9IG5ldyBSZWdFeHAoJyg/Ol58OylcXFxccyonICsgZW5jb2RlVVJJQ29tcG9uZW50KGtleSkucmVwbGFjZSgvW1xcLVxcLlxcK1xcKl0vZywgJ1xcXFwkJicpICsgJ1xcXFxzKlxcXFw9XFxcXHMqKFteO10qKS4qJCcpO1xuICAgICAgICAgICAgdmFyIHJlcyA9IGNvb2tpZVJlZy5leGVjKGNvb2tpZS5nZXQoKSk7XG4gICAgICAgICAgICB2YXIgdmFsID0gcmVzID8gZGVjb2RlVVJJQ29tcG9uZW50KHJlc1sxXSkgOiBudWxsO1xuICAgICAgICAgICAgcmV0dXJuIHZhbDtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBrZXkgZnJvbSBjb2xsZWN0aW9uXG4gICAgICAgICAqIEBwYXJhbSB7IHN0cmluZ30ga2V5IGtleSB0byByZW1vdmVcbiAgICAgICAgICogQHJldHVybiB7IHN0cmluZ30ga2V5IFRoZSBrZXkgcmVtb3ZlZFxuICAgICAgICAgKlxuICAgICAgICAgKiBAZXhhbXBsZVxuICAgICAgICAgKiAgICAgY3MucmVtb3ZlKCdwZXJzb24nKTtcbiAgICAgICAgICovXG4gICAgICAgIHJlbW92ZTogZnVuY3Rpb24gKGtleSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHJlbU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdGhpcy5zZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBkb21haW4gPSByZW1PcHRpb25zLmRvbWFpbjtcbiAgICAgICAgICAgIHZhciBwYXRoID0gcmVtT3B0aW9ucy5yb290O1xuICAgICAgICAgICAgdmFyIGNvb2tpZSA9IHJlbU9wdGlvbnMuY29va2llO1xuXG4gICAgICAgICAgICBjb29raWUuc2V0KGVuY29kZVVSSUNvbXBvbmVudChrZXkpICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnPTsgZXhwaXJlcz1UaHUsIDAxIEphbiAxOTcwIDAwOjAwOjAwIEdNVCcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChkb21haW4gPyAnOyBkb21haW49JyArIGRvbWFpbiA6ICcnKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKHBhdGggPyAnOyBwYXRoPScgKyBwYXRoIDogJycpXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmV0dXJuIGtleTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBjb2xsZWN0aW9uIGJlaW5nIHJlZmVyZW5jZWRcbiAgICAgICAgICogQHJldHVybiB7IGFycmF5fSBrZXlzIEFsbCB0aGUga2V5cyByZW1vdmVkXG4gICAgICAgICAqL1xuICAgICAgICBkZXN0cm95OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgY29va2llID0gdGhpcy5zZXJ2aWNlT3B0aW9ucy5jb29raWU7XG4gICAgICAgICAgICB2YXIgYUtleXMgPSBjb29raWUuZ2V0KCkucmVwbGFjZSgvKCg/Ol58XFxzKjspW15cXD1dKykoPz07fCQpfF5cXHMqfFxccyooPzpcXD1bXjtdKik/KD86XFwxfCQpL2csICcnKS5zcGxpdCgvXFxzKig/OlxcPVteO10qKT87XFxzKi8pO1xuICAgICAgICAgICAgZm9yICh2YXIgbklkeCA9IDA7IG5JZHggPCBhS2V5cy5sZW5ndGg7IG5JZHgrKykge1xuICAgICAgICAgICAgICAgIHZhciBjb29raWVLZXkgPSBkZWNvZGVVUklDb21wb25lbnQoYUtleXNbbklkeF0pO1xuICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKGNvb2tpZUtleSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gYUtleXM7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4uL21hbmFnZXJzL2tleS1uYW1lcycpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi9zdG9yZS1mYWN0b3J5Jyk7XG52YXIgb3B0aW9uVXRpbHMgPSByZXF1aXJlKCcuLi91dGlsL29wdGlvbi11dGlscycpO1xuXG52YXIgRVBJX1NFU1NJT05fS0VZID0ga2V5TmFtZXMuRVBJX1NFU1NJT05fS0VZO1xudmFyIGRlZmF1bHRzID0ge1xuICAgIC8qKlxuICAgICAqIFdoZXJlIHRvIHN0b3JlIHVzZXIgYWNjZXNzIHRva2VucyBmb3IgdGVtcG9yYXJ5IGFjY2Vzcy4gRGVmYXVsdHMgdG8gc3RvcmluZyBpbiBhIGNvb2tpZSBpbiB0aGUgYnJvd3Nlci5cbiAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAqL1xuICAgIHN0b3JlOiB7IHN5bmNocm9ub3VzOiB0cnVlIH1cbn07XG5cbnZhciBTZXNzaW9uTWFuYWdlciA9IGZ1bmN0aW9uIChtYW5hZ2VyT3B0aW9ucykge1xuICAgIG1hbmFnZXJPcHRpb25zID0gbWFuYWdlck9wdGlvbnMgfHwge307XG4gICAgZnVuY3Rpb24gZ2V0QmFzZU9wdGlvbnMob3ZlcnJpZGVzKSB7XG4gICAgICAgIG92ZXJyaWRlcyA9IG92ZXJyaWRlcyB8fCB7fTtcbiAgICAgICAgdmFyIGxpYk9wdGlvbnMgPSBvcHRpb25VdGlscy5nZXRPcHRpb25zKCk7XG4gICAgICAgIHZhciBmaW5hbE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIGxpYk9wdGlvbnMsIG1hbmFnZXJPcHRpb25zLCBvdmVycmlkZXMpO1xuICAgICAgICByZXR1cm4gZmluYWxPcHRpb25zO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdldFN0b3JlKG92ZXJyaWRlcykge1xuICAgICAgICB2YXIgYmFzZU9wdGlvbnMgPSBnZXRCYXNlT3B0aW9ucyhvdmVycmlkZXMpO1xuICAgICAgICB2YXIgc3RvcmVPcHRzID0gYmFzZU9wdGlvbnMuc3RvcmUgfHwge307XG4gICAgICAgIGlmIChzdG9yZU9wdHMucm9vdCA9PT0gdW5kZWZpbmVkICYmIGJhc2VPcHRpb25zLmFjY291bnQgJiYgYmFzZU9wdGlvbnMucHJvamVjdCAmJiAhYmFzZU9wdGlvbnMuaXNMb2NhbCkge1xuICAgICAgICAgICAgc3RvcmVPcHRzLnJvb3QgPSAnL2FwcC8nICsgYmFzZU9wdGlvbnMuYWNjb3VudCArICcvJyArIGJhc2VPcHRpb25zLnByb2plY3Q7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG5ldyBTdG9yYWdlRmFjdG9yeShzdG9yZU9wdHMpO1xuICAgIH1cblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG4gICAgICAgIHNhdmVTZXNzaW9uOiBmdW5jdGlvbiAodXNlckluZm8sIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBzZXJpYWxpemVkID0gSlNPTi5zdHJpbmdpZnkodXNlckluZm8pO1xuICAgICAgICAgICAgZ2V0U3RvcmUob3B0aW9ucykuc2V0KEVQSV9TRVNTSU9OX0tFWSwgc2VyaWFsaXplZCk7XG4gICAgICAgIH0sXG4gICAgICAgIGdldFNlc3Npb246IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICAvLyB2YXIgc2Vzc2lvbiA9IGdldFN0b3JlKG9wdGlvbnMpLmdldChFUElfU0VTU0lPTl9LRVkpIHx8ICd7fSc7XG4gICAgICAgICAgICAvLyByZXR1cm4gSlNPTi5wYXJzZShzZXNzaW9uKTtcbiAgICAgICAgICAgIHZhciBzdG9yZSA9IGdldFN0b3JlKG9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIGZpbmFsT3B0cyA9IHN0b3JlLnNlcnZpY2VPcHRpb25zO1xuICAgICAgICAgICAgdmFyIHNlcmlhbGl6ZWQgPSBzdG9yZS5nZXQoRVBJX1NFU1NJT05fS0VZKSB8fCAne30nO1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSBKU09OLnBhcnNlKHNlcmlhbGl6ZWQpO1xuICAgICAgICAgICAgLy8gSWYgdGhlIHVybCBjb250YWlucyB0aGUgcHJvamVjdCBhbmQgYWNjb3VudFxuICAgICAgICAgICAgLy8gdmFsaWRhdGUgdGhlIGFjY291bnQgYW5kIHByb2plY3QgaW4gdGhlIHNlc3Npb25cbiAgICAgICAgICAgIC8vIGFuZCBvdmVycmlkZSBwcm9qZWN0LCBncm91cE5hbWUsIGdyb3VwSWQgYW5kIGlzRmFjXG4gICAgICAgICAgICAvLyBPdGhlcndpc2UgKGkuZS4gbG9jYWxob3N0KSB1c2UgdGhlIHNhdmVkIHNlc3Npb24gdmFsdWVzXG4gICAgICAgICAgICB2YXIgYWNjb3VudCA9IGZpbmFsT3B0cy5hY2NvdW50O1xuICAgICAgICAgICAgdmFyIHByb2plY3QgPSBmaW5hbE9wdHMucHJvamVjdDtcbiAgICAgICAgICAgIGlmIChhY2NvdW50ICYmIHNlc3Npb24uYWNjb3VudCAhPT0gYWNjb3VudCkge1xuICAgICAgICAgICAgICAgIC8vIFRoaXMgbWVhbnMgdGhhdCB0aGUgdG9rZW4gd2FzIG5vdCB1c2VkIHRvIGxvZ2luIHRvIHRoZSBzYW1lIGFjY291bnRcbiAgICAgICAgICAgICAgICByZXR1cm4ge307XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoc2Vzc2lvbi5ncm91cHMgJiYgYWNjb3VudCAmJiBwcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgdmFyIGdyb3VwID0gc2Vzc2lvbi5ncm91cHNbcHJvamVjdF0gfHwgeyBncm91cElkOiAnJywgZ3JvdXBOYW1lOiAnJywgaXNGYWM6IGZhbHNlIH07XG4gICAgICAgICAgICAgICAgJC5leHRlbmQoc2Vzc2lvbiwgeyBwcm9qZWN0OiBwcm9qZWN0IH0sIGdyb3VwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBzZXNzaW9uO1xuICAgICAgICB9LFxuICAgICAgICByZW1vdmVTZXNzaW9uOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHN0b3JlID0gZ2V0U3RvcmUob3B0aW9ucyk7XG4gICAgICAgICAgICBPYmplY3Qua2V5cyhrZXlOYW1lcykuZm9yRWFjaChmdW5jdGlvbiAoY29va2llS2V5KSB7XG4gICAgICAgICAgICAgICAgdmFyIGNvb2tpZU5hbWUgPSBrZXlOYW1lc1tjb29raWVLZXldO1xuICAgICAgICAgICAgICAgIHN0b3JlLnJlbW92ZShjb29raWVOYW1lKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0sXG4gICAgICAgIGdldFN0b3JlOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIGdldFN0b3JlKG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGdldE1lcmdlZE9wdGlvbnM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKTtcbiAgICAgICAgICAgIHZhciBvdmVycmlkZXMgPSAkLmV4dGVuZC5hcHBseSgkLCBbdHJ1ZSwge31dLmNvbmNhdChhcmdzKSk7XG4gICAgICAgICAgICB2YXIgYmFzZU9wdGlvbnMgPSBnZXRCYXNlT3B0aW9ucyhvdmVycmlkZXMpO1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLmdldFNlc3Npb24ob3ZlcnJpZGVzKTtcblxuICAgICAgICAgICAgdmFyIHNlc3Npb25EZWZhdWx0cyA9IHtcbiAgICAgICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgIC8vanNoaW50IGNhbWVsY2FzZTogZmFsc2VcbiAgICAgICAgICAgICAgICAvL2pzY3M6ZGlzYWJsZVxuICAgICAgICAgICAgICAgIHRva2VuOiBzZXNzaW9uLmF1dGhfdG9rZW4sXG4gICAgICAgICAgICAgICAgLyoqXG4gICAgICAgICAgICAgICAgICogVGhlIGdyb3VwIG5hbWUuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBjb29raWUgc2Vzc2lvbi5cbiAgICAgICAgICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgIGdyb3VwOiBzZXNzaW9uLmdyb3VwTmFtZSxcbiAgICAgICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAgICAgKiBUaGUgZ3JvdXAgaWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBjb29raWUgc2Vzc2lvbi5cbiAgICAgICAgICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgIGdyb3VwSWQ6IHNlc3Npb24uZ3JvdXBJZCxcbiAgICAgICAgICAgICAgICB1c2VySWQ6IHNlc3Npb24udXNlcklkXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHRydWUsIHNlc3Npb25EZWZhdWx0cywgYmFzZU9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTZXNzaW9uTWFuYWdlcjsiLCIvKipcbiAgICBEZWNpZGVzIHR5cGUgb2Ygc3RvcmUgdG8gcHJvdmlkZVxuKi9cblxuJ3VzZSBzdHJpY3QnO1xuLy8gdmFyIGlzTm9kZSA9IGZhbHNlOyBGSVhNRTogQnJvd3NlcmlmeS9taW5pZnlpZnkgaGFzIGlzc3VlcyB3aXRoIHRoZSBuZXh0IGxpbmtcbi8vIHZhciBzdG9yZSA9IChpc05vZGUpID8gcmVxdWlyZSgnLi9zZXNzaW9uLXN0b3JlJykgOiByZXF1aXJlKCcuL2Nvb2tpZS1zdG9yZScpO1xudmFyIHN0b3JlID0gcmVxdWlyZSgnLi9jb29raWUtc3RvcmUnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBzdG9yZTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIHF1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgdXJsOiAnJyxcblxuICAgICAgICBjb250ZW50VHlwZTogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICBoZWFkZXJzOiB7fSxcbiAgICAgICAgc3RhdHVzQ29kZToge1xuICAgICAgICAgICAgNDA0OiAkLm5vb3BcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT05MWSBmb3Igc3RyaW5ncyBpbiB0aGUgdXJsLiBBbGwgR0VUICYgREVMRVRFIHBhcmFtcyBhcmUgcnVuIHRocm91Z2ggdGhpc1xuICAgICAgICAgKiBAdHlwZSB7W3R5cGVdIH1cbiAgICAgICAgICovXG4gICAgICAgIHBhcmFtZXRlclBhcnNlcjogcXV0aWxzLnRvUXVlcnlGb3JtYXQsXG5cbiAgICAgICAgLy8gVG8gYWxsb3cgZXBpY2VudGVyLnRva2VuIGFuZCBvdGhlciBzZXNzaW9uIGNvb2tpZXMgdG8gYmUgcGFzc2VkXG4gICAgICAgIC8vIHdpdGggdGhlIHJlcXVlc3RzXG4gICAgICAgIHhockZpZWxkczoge1xuICAgICAgICAgICAgd2l0aENyZWRlbnRpYWxzOiB0cnVlXG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG5cbiAgICB2YXIgcmVzdWx0ID0gZnVuY3Rpb24gKGQpIHtcbiAgICAgICAgcmV0dXJuICgkLmlzRnVuY3Rpb24oZCkpID8gZCgpIDogZDtcbiAgICB9O1xuXG4gICAgdmFyIGNvbm5lY3QgPSBmdW5jdGlvbiAobWV0aG9kLCBwYXJhbXMsIGNvbm5lY3RPcHRpb25zKSB7XG4gICAgICAgIHBhcmFtcyA9IHJlc3VsdChwYXJhbXMpO1xuICAgICAgICBwYXJhbXMgPSAoJC5pc1BsYWluT2JqZWN0KHBhcmFtcykgfHwgJC5pc0FycmF5KHBhcmFtcykpID8gSlNPTi5zdHJpbmdpZnkocGFyYW1zKSA6IHBhcmFtcztcblxuICAgICAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB0cmFuc3BvcnRPcHRpb25zLCBjb25uZWN0T3B0aW9ucywge1xuICAgICAgICAgICAgdHlwZTogbWV0aG9kLFxuICAgICAgICAgICAgZGF0YTogcGFyYW1zXG4gICAgICAgIH0pO1xuICAgICAgICB2YXIgQUxMT1dFRF9UT19CRV9GVU5DVElPTlMgPSBbJ2RhdGEnLCAndXJsJ107XG4gICAgICAgICQuZWFjaChvcHRpb25zLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgaWYgKCQuaXNGdW5jdGlvbih2YWx1ZSkgJiYgJC5pbkFycmF5KGtleSwgQUxMT1dFRF9UT19CRV9GVU5DVElPTlMpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIG9wdGlvbnNba2V5XSA9IHZhbHVlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChvcHRpb25zLmxvZ0xldmVsICYmIG9wdGlvbnMubG9nTGV2ZWwgPT09ICdERUJVRycpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKG9wdGlvbnMudXJsKTtcbiAgICAgICAgICAgIHZhciBvbGRTdWNjZXNzRm4gPSBvcHRpb25zLnN1Y2Nlc3MgfHwgJC5ub29wO1xuICAgICAgICAgICAgb3B0aW9ucy5zdWNjZXNzID0gZnVuY3Rpb24gKHJlc3BvbnNlLCBhamF4U3RhdHVzLCBhamF4UmVxKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2cocmVzcG9uc2UpO1xuICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3NGbi5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBiZWZvcmVTZW5kID0gb3B0aW9ucy5iZWZvcmVTZW5kO1xuICAgICAgICBvcHRpb25zLmJlZm9yZVNlbmQgPSBmdW5jdGlvbiAoeGhyLCBzZXR0aW5ncykge1xuICAgICAgICAgICAgeGhyLnJlcXVlc3RVcmwgPSAoY29ubmVjdE9wdGlvbnMgfHwge30pLnVybDtcbiAgICAgICAgICAgIGlmIChiZWZvcmVTZW5kKSB7XG4gICAgICAgICAgICAgICAgYmVmb3JlU2VuZC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiAkLmFqYXgob3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG4gICAgICAgIGdldDpmdW5jdGlvbiAocGFyYW1zLCBhamF4T3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIG9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgdHJhbnNwb3J0T3B0aW9ucywgYWpheE9wdGlvbnMpO1xuICAgICAgICAgICAgcGFyYW1zID0gb3B0aW9ucy5wYXJhbWV0ZXJQYXJzZXIocmVzdWx0KHBhcmFtcykpO1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuY2FsbCh0aGlzLCAnR0VUJywgcGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgfSxcbiAgICAgICAgc3BsaXRHZXQ6IGZ1bmN0aW9uICgpIHtcblxuICAgICAgICB9LFxuICAgICAgICBwb3N0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ3Bvc3QnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIHBhdGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ3BhdGNoJ10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9LFxuICAgICAgICBwdXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncHV0J10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9LFxuICAgICAgICBkZWxldGU6IGZ1bmN0aW9uIChwYXJhbXMsIGFqYXhPcHRpb25zKSB7XG4gICAgICAgICAgICAvL0RFTEVURSBkb2Vzbid0IHN1cHBvcnQgYm9keSBwYXJhbXMsIGJ1dCBqUXVlcnkgdGhpbmtzIGl0IGRvZXMuXG4gICAgICAgICAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCB0cmFuc3BvcnRPcHRpb25zLCBhamF4T3B0aW9ucyk7XG4gICAgICAgICAgICBwYXJhbXMgPSBvcHRpb25zLnBhcmFtZXRlclBhcnNlcihyZXN1bHQocGFyYW1zKSk7XG4gICAgICAgICAgICBpZiAoJC50cmltKHBhcmFtcykpIHtcbiAgICAgICAgICAgICAgICB2YXIgZGVsaW1pdGVyID0gKHJlc3VsdChvcHRpb25zLnVybCkuaW5kZXhPZignPycpID09PSAtMSkgPyAnPycgOiAnJic7XG4gICAgICAgICAgICAgICAgb3B0aW9ucy51cmwgPSByZXN1bHQob3B0aW9ucy51cmwpICsgZGVsaW1pdGVyICsgcGFyYW1zO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuY2FsbCh0aGlzLCAnREVMRVRFJywgbnVsbCwgb3B0aW9ucyk7XG4gICAgICAgIH0sXG4gICAgICAgIGhlYWQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsnaGVhZCddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfSxcbiAgICAgICAgb3B0aW9uczogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydvcHRpb25zJ10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHJldHVybiAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxuLy8gdmFyIGlzTm9kZSA9IGZhbHNlOyBGSVhNRTogQnJvd3NlcmlmeS9taW5pZnlpZnkgaGFzIGlzc3VlcyB3aXRoIHRoZSBuZXh0IGxpbmtcbi8vIHZhciB0cmFuc3BvcnQgPSAoaXNOb2RlKSA/IHJlcXVpcmUoJy4vbm9kZS1odHRwLXRyYW5zcG9ydCcpIDogcmVxdWlyZSgnLi9hamF4LWh0dHAtdHJhbnNwb3J0Jyk7XG52YXIgdHJhbnNwb3J0ID0gcmVxdWlyZSgnLi9hamF4LWh0dHAtdHJhbnNwb3J0Jyk7XG5tb2R1bGUuZXhwb3J0cyA9IHRyYW5zcG9ydDtcbiIsIi8qKlxuLyogSW5oZXJpdCBmcm9tIGEgY2xhc3MgKHVzaW5nIHByb3RvdHlwZSBib3Jyb3dpbmcpXG4qL1xuJ3VzZSBzdHJpY3QnO1xuXG5mdW5jdGlvbiBpbmhlcml0KEMsIFApIHtcbiAgICB2YXIgRiA9IGZ1bmN0aW9uICgpIHt9O1xuICAgIEYucHJvdG90eXBlID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUgPSBuZXcgRigpO1xuICAgIEMuX19zdXBlciA9IFAucHJvdG90eXBlO1xuICAgIEMucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQztcbn1cblxuLyoqXG4qIFNoYWxsb3cgY29weSBvZiBhbiBvYmplY3RcbiovXG52YXIgZXh0ZW5kID0gZnVuY3Rpb24gKGRlc3QgLyosIHZhcl9hcmdzKi8pIHtcbiAgICB2YXIgb2JqID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICB2YXIgY3VycmVudDtcbiAgICBmb3IgKHZhciBqID0gMDsgajxvYmoubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKCEoY3VycmVudCA9IG9ialtqXSkpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZG8gbm90IHdyYXAgaW5uZXIgaW4gZGVzdC5oYXNPd25Qcm9wZXJ0eSBvciBiYWQgdGhpbmdzIHdpbGwgaGFwcGVuXG4gICAgICAgIC8qanNoaW50IC1XMDg5ICovXG4gICAgICAgIGZvciAodmFyIGtleSBpbiBjdXJyZW50KSB7XG4gICAgICAgICAgICBkZXN0W2tleV0gPSBjdXJyZW50W2tleV07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZGVzdDtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGJhc2UsIHByb3BzLCBzdGF0aWNQcm9wcykge1xuICAgIHZhciBwYXJlbnQgPSBiYXNlO1xuICAgIHZhciBjaGlsZDtcblxuICAgIGNoaWxkID0gcHJvcHMgJiYgcHJvcHMuaGFzT3duUHJvcGVydHkoJ2NvbnN0cnVjdG9yJykgPyBwcm9wcy5jb25zdHJ1Y3RvciA6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHBhcmVudC5hcHBseSh0aGlzLCBhcmd1bWVudHMpOyB9O1xuXG4gICAgLy8gYWRkIHN0YXRpYyBwcm9wZXJ0aWVzIHRvIHRoZSBjaGlsZCBjb25zdHJ1Y3RvciBmdW5jdGlvblxuICAgIGV4dGVuZChjaGlsZCwgcGFyZW50LCBzdGF0aWNQcm9wcyk7XG5cbiAgICAvLyBhc3NvY2lhdGUgcHJvdG90eXBlIGNoYWluXG4gICAgaW5oZXJpdChjaGlsZCwgcGFyZW50KTtcblxuICAgIC8vIGFkZCBpbnN0YW5jZSBwcm9wZXJ0aWVzXG4gICAgaWYgKHByb3BzKSB7XG4gICAgICAgIGV4dGVuZChjaGlsZC5wcm90b3R5cGUsIHByb3BzKTtcbiAgICB9XG5cbiAgICAvLyBkb25lXG4gICAgcmV0dXJuIGNoaWxkO1xufTtcbiIsIid1c2Ugc3RyaWN0Jztcbi8qanNoaW50IGxvb3BmdW5jOmZhbHNlICovXG5cbmZ1bmN0aW9uIF93KHZhbCkge1xuICAgIGlmICh2YWwgJiYgdmFsLnRoZW4pIHtcbiAgICAgICAgcmV0dXJuIHZhbDtcbiAgICB9XG4gICAgdmFyIHAgPSAkLkRlZmVycmVkKCk7XG4gICAgcC5yZXNvbHZlKHZhbCk7XG5cbiAgICByZXR1cm4gcC5wcm9taXNlKCk7XG59XG5cbmZ1bmN0aW9uIHNlcSgpIHtcbiAgICB2YXIgbGlzdCA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5hcHBseShhcmd1bWVudHMpO1xuXG4gICAgZnVuY3Rpb24gbmV4dChwKSB7XG4gICAgICAgIHZhciBjdXIgPSBsaXN0LnNwbGljZSgwLDEpWzBdO1xuXG4gICAgICAgIGlmICghY3VyKSB7XG4gICAgICAgICAgICByZXR1cm4gcDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBfdyhjdXIocCkpLnRoZW4obmV4dCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZ1bmN0aW9uIChzZWVkKSB7XG4gICAgICAgIHJldHVybiBuZXh0KHNlZWQpLmZhaWwoc2VxLmZhaWwpO1xuICAgIH07XG59XG5cbmZ1bmN0aW9uIE1ha2VTZXEob2JqKSB7XG4gICAgdmFyIHJlcyA9IHtcbiAgICAgICAgX19jYWxsczogW10sXG5cbiAgICAgICAgb3JpZ2luYWw6IG9iaixcblxuICAgICAgICB0aGVuOiBmdW5jdGlvbiAoZm4pIHtcbiAgICAgICAgICAgIHRoaXMuX19jYWxscy5wdXNoKGZuKTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuXG4gICAgICAgIHN0YXJ0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICAgICAgICAvLyBjbGVhbiB1cFxuICAgICAgICAgICAgdGhpcy50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICBfdGhpcy5fX2NhbGxzLmxlbmd0aCA9IDA7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gc2VxLmFwcGx5KG51bGwsIHRoaXMuX19jYWxscykoKTtcbiAgICAgICAgfSxcblxuICAgICAgICBmYWlsOiBmdW5jdGlvbiAoZm4pIHtcbiAgICAgICAgICAgIHNlcS5mYWlsID0gZm47XG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgZnVuY01ha2VyID0gZnVuY3Rpb24gKHAsIG9iaikge1xuICAgICAgICB2YXIgZm4gPSBvYmpbcF0uYmluZChvYmopO1xuICAgICAgICByZXR1cm4gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuYXBwbHkoYXJndW1lbnRzKTtcbiAgICAgICAgICAgIHRoaXMuX19jYWxscy5wdXNoKEZ1bmN0aW9uLmJpbmQuYXBwbHkoZm4sIFtudWxsXS5jb25jYXQoYXJncykpKTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9O1xuICAgIH07XG5cbiAgICBmb3IgKHZhciBwcm9wIGluIG9iaikge1xuICAgICAgICBpZiAodHlwZW9mIG9ialtwcm9wXSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgcmVzW3Byb3BdID0gZnVuY01ha2VyKHByb3AsIG9iaik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXNbcHJvcF0gPSBvYmpbcHJvcF07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gcmVzO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IE1ha2VTZXE7XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIF9waWNrOiBmdW5jdGlvbiAob2JqLCBwcm9wcykge1xuICAgICAgICB2YXIgcmVzID0ge307XG4gICAgICAgIGZvciAodmFyIHAgaW4gb2JqKSB7XG4gICAgICAgICAgICBpZiAocHJvcHMuaW5kZXhPZihwKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICByZXNbcF0gPSBvYmpbcF07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcmVzO1xuICAgIH1cbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcblxudmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKCkuZ2V0KCdzZXJ2ZXInKTtcbnZhciBjdXN0b21EZWZhdWx0cyA9IHt9O1xudmFyIGxpYkRlZmF1bHRzID0ge1xuICAgIC8qKlxuICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgKi9cbiAgICBhY2NvdW50OiB1cmxDb25maWcuYWNjb3VudFBhdGgsXG4gICAgLyoqXG4gICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAqL1xuICAgIHByb2plY3Q6IHVybENvbmZpZy5wcm9qZWN0UGF0aCxcbiAgICBpc0xvY2FsOiB1cmxDb25maWcuaXNMb2NhbGhvc3QoKSxcbiAgICBzdG9yZToge31cbn07XG5cbnZhciBvcHRpb25VdGlscyA9IHtcbiAgICAvKipcbiAgICAgKiBHZXRzIHRoZSBmaW5hbCBvcHRpb25zIGJ5IG92ZXJyaWRpbmcgdGhlIGdsb2JhbCBvcHRpb25zIHNldCB3aXRoXG4gICAgICogb3B0aW9uVXRpbHMjc2V0RGVmYXVsdHMoKSBhbmQgdGhlIGxpYiBkZWZhdWx0cy5cbiAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIFRoZSBmaW5hbCBvcHRpb25zIG9iamVjdC5cbiAgICAgKi9cbiAgICBnZXRPcHRpb25zOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwge30sIGxpYkRlZmF1bHRzLCBjdXN0b21EZWZhdWx0cywgb3B0aW9ucyk7XG4gICAgfSxcbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBnbG9iYWwgZGVmYXVsdHMgZm9yIHRoZSBvcHRpb25VdGlscyNnZXRPcHRpb25zKCkgbWV0aG9kLlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgZGVmYXVsdHNgIFRoZSBkZWZhdWx0cyBvYmplY3QuXG4gICAgICovXG4gICAgc2V0RGVmYXVsdHM6IGZ1bmN0aW9uIChkZWZhdWx0cykge1xuICAgICAgICBjdXN0b21EZWZhdWx0cyA9IGRlZmF1bHRzO1xuICAgIH1cbn07XG5tb2R1bGUuZXhwb3J0cyA9IG9wdGlvblV0aWxzO1xuIiwiLyoqXG4gKiBVdGlsaXRpZXMgZm9yIHdvcmtpbmcgd2l0aCBxdWVyeSBzdHJpbmdzXG4qL1xuJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IChmdW5jdGlvbiAoKSB7XG5cbiAgICByZXR1cm4ge1xuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVydHMgdG8gbWF0cml4IGZvcm1hdFxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IHFzIE9iamVjdCB0byBjb252ZXJ0IHRvIHF1ZXJ5IHN0cmluZ1xuICAgICAgICAgKiBAcmV0dXJuIHsgc3RyaW5nfSAgICBNYXRyaXgtZm9ybWF0IHF1ZXJ5IHBhcmFtZXRlcnNcbiAgICAgICAgICovXG4gICAgICAgIHRvTWF0cml4Rm9ybWF0OiBmdW5jdGlvbiAocXMpIHtcbiAgICAgICAgICAgIGlmIChxcyA9PT0gbnVsbCB8fCBxcyA9PT0gdW5kZWZpbmVkIHx8IHFzID09PSAnJykge1xuICAgICAgICAgICAgICAgIHJldHVybiAnOyc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodHlwZW9mIHFzID09PSAnc3RyaW5nJyB8fCBxcyBpbnN0YW5jZW9mIFN0cmluZykge1xuICAgICAgICAgICAgICAgIHJldHVybiBxcztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHJldHVybkFycmF5ID0gW107XG4gICAgICAgICAgICB2YXIgT1BFUkFUT1JTID0gWyc8JywgJz4nLCAnISddO1xuICAgICAgICAgICAgJC5lYWNoKHFzLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgIT09ICdzdHJpbmcnIHx8ICQuaW5BcnJheSgkLnRyaW0odmFsdWUpLmNoYXJBdCgwKSwgT1BFUkFUT1JTKSA9PT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSAnPScgKyB2YWx1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuQXJyYXkucHVzaChrZXkgKyB2YWx1ZSk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgdmFyIG10cnggPSAnOycgKyByZXR1cm5BcnJheS5qb2luKCc7Jyk7XG4gICAgICAgICAgICByZXR1cm4gbXRyeDtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVydHMgc3RyaW5ncy9hcnJheXMvb2JqZWN0cyB0byB0eXBlICdhPWImYj1jJ1xuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfEFycmF5fE9iamVjdH0gcXNcbiAgICAgICAgICogQHJldHVybiB7IHN0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRvUXVlcnlGb3JtYXQ6IGZ1bmN0aW9uIChxcykge1xuICAgICAgICAgICAgaWYgKHFzID09PSBudWxsIHx8IHFzID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJyc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodHlwZW9mIHFzID09PSAnc3RyaW5nJyB8fCBxcyBpbnN0YW5jZW9mIFN0cmluZykge1xuICAgICAgICAgICAgICAgIHJldHVybiBxcztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHJldHVybkFycmF5ID0gW107XG4gICAgICAgICAgICAkLmVhY2gocXMsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgaWYgKCQuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSB2YWx1ZS5qb2luKCcsJyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3QodmFsdWUpKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vTW9zdGx5IGZvciBkYXRhIGFwaVxuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IEpTT04uc3RyaW5naWZ5KHZhbHVlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuQXJyYXkucHVzaChrZXkgKyAnPScgKyB2YWx1ZSk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHJldHVybkFycmF5LmpvaW4oJyYnKTtcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlcnRzIHN0cmluZ3Mgb2YgdHlwZSAnYT1iJmI9YycgdG8geyBhOmIsIGI6Y31cbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ30gcXNcbiAgICAgICAgICogQHJldHVybiB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgcXNUb09iamVjdDogZnVuY3Rpb24gKHFzKSB7XG4gICAgICAgICAgICBpZiAocXMgPT09IG51bGwgfHwgcXMgPT09IHVuZGVmaW5lZCB8fCBxcyA9PT0gJycpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4ge307XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBxc0FycmF5ID0gcXMuc3BsaXQoJyYnKTtcbiAgICAgICAgICAgIHZhciByZXR1cm5PYmogPSB7fTtcbiAgICAgICAgICAgICQuZWFjaChxc0FycmF5LCBmdW5jdGlvbiAoaW5kZXgsIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgdmFyIHFLZXkgPSB2YWx1ZS5zcGxpdCgnPScpWzBdO1xuICAgICAgICAgICAgICAgIHZhciBxVmFsID0gdmFsdWUuc3BsaXQoJz0nKVsxXTtcblxuICAgICAgICAgICAgICAgIGlmIChxVmFsLmluZGV4T2YoJywnKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgcVZhbCA9IHFWYWwuc3BsaXQoJywnKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm5PYmpbcUtleV0gPSBxVmFsO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiByZXR1cm5PYmo7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE5vcm1hbGl6ZXMgYW5kIG1lcmdlcyBzdHJpbmdzIG9mIHR5cGUgJ2E9YicsIHsgYjpjfSB0byB7IGE6YiwgYjpjfVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfEFycmF5fE9iamVjdH0gcXMxXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8QXJyYXl8T2JqZWN0fSBxczJcbiAgICAgICAgICogQHJldHVybiB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgbWVyZ2VRUzogZnVuY3Rpb24gKHFzMSwgcXMyKSB7XG4gICAgICAgICAgICB2YXIgb2JqMSA9IHRoaXMucXNUb09iamVjdCh0aGlzLnRvUXVlcnlGb3JtYXQocXMxKSk7XG4gICAgICAgICAgICB2YXIgb2JqMiA9IHRoaXMucXNUb09iamVjdCh0aGlzLnRvUXVlcnlGb3JtYXQocXMyKSk7XG4gICAgICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwge30sIG9iajEsIG9iajIpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGFkZFRyYWlsaW5nU2xhc2g6IGZ1bmN0aW9uICh1cmwpIHtcbiAgICAgICAgICAgIGlmICghdXJsKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuICh1cmwuY2hhckF0KHVybC5sZW5ndGggLSAxKSA9PT0gJy8nKSA/IHVybCA6ICh1cmwgKyAnLycpO1xuICAgICAgICB9XG4gICAgfTtcbn0oKSk7XG5cblxuXG4iLCIvKipcbiAqIFV0aWxpdGllcyBmb3Igd29ya2luZyB3aXRoIHRoZSBydW4gc2VydmljZVxuKi9cbid1c2Ugc3RyaWN0JztcbnZhciBxdXRpbCA9IHJlcXVpcmUoJy4vcXVlcnktdXRpbCcpO1xudmFyIE1BWF9VUkxfTEVOR1RIID0gMjA0ODtcblxubW9kdWxlLmV4cG9ydHMgPSAoZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiByZXR1cm5zIG9wZXJhdGlvbnMgb2YgdGhlIGZvcm0gYFtbb3AxLG9wMl0sIFthcmcxLCBhcmcyXV1gXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdHxBcnJheXxTdHJpbmd9IGBvcGVyYXRpb25zYCBvcGVyYXRpb25zIHRvIHBlcmZvcm1cbiAgICAgICAgICogQHBhcmFtICB7QXJyYXl9IGBhcmdzYCBhcmd1bWVudHMgZm9yIG9wZXJhdGlvblxuICAgICAgICAgKiBAcmV0dXJuIHtTdHJpbmd9ICAgIE1hdHJpeC1mb3JtYXQgcXVlcnkgcGFyYW1ldGVyc1xuICAgICAgICAgKi9cbiAgICAgICAgbm9ybWFsaXplT3BlcmF0aW9uczogZnVuY3Rpb24gKG9wZXJhdGlvbnMsIGFyZ3MpIHtcbiAgICAgICAgICAgIGlmICghYXJncykge1xuICAgICAgICAgICAgICAgIGFyZ3MgPSBbXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciByZXR1cm5MaXN0ID0ge1xuICAgICAgICAgICAgICAgIG9wczogW10sXG4gICAgICAgICAgICAgICAgYXJnczogW11cbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBfY29uY2F0ID0gZnVuY3Rpb24gKGFycikge1xuICAgICAgICAgICAgICAgIHJldHVybiAoYXJyICE9PSBudWxsICYmIGFyciAhPT0gdW5kZWZpbmVkKSA/IFtdLmNvbmNhdChhcnIpIDogW107XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAvL3sgYWRkOiBbMSwyXSwgc3VidHJhY3Q6IFsyLDRdIH1cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplUGxhaW5PYmplY3RzID0gZnVuY3Rpb24gKG9wZXJhdGlvbnMsIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgJC5lYWNoKG9wZXJhdGlvbnMsIGZ1bmN0aW9uIChvcG4sIGFyZykge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0Lm9wcy5wdXNoKG9wbik7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QuYXJncy5wdXNoKF9jb25jYXQoYXJnKSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgLy97IG5hbWU6ICdhZGQnLCBwYXJhbXM6IFsxXSB9XG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZVN0cnVjdHVyZWRPYmplY3RzID0gZnVuY3Rpb24gKG9wZXJhdGlvbiwgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIGlmICghcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0ID0geyBvcHM6IFtdLCBhcmdzOiBbXSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5MaXN0Lm9wcy5wdXNoKG9wZXJhdGlvbi5uYW1lKTtcbiAgICAgICAgICAgICAgICByZXR1cm5MaXN0LmFyZ3MucHVzaChfY29uY2F0KG9wZXJhdGlvbi5wYXJhbXMpKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplT2JqZWN0ID0gZnVuY3Rpb24gKG9wZXJhdGlvbiwgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAoKG9wZXJhdGlvbi5uYW1lKSA/IF9ub3JtYWxpemVTdHJ1Y3R1cmVkT2JqZWN0cyA6IF9ub3JtYWxpemVQbGFpbk9iamVjdHMpKG9wZXJhdGlvbiwgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZUxpdGVyYWxzID0gZnVuY3Rpb24gKG9wZXJhdGlvbiwgYXJncywgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIGlmICghcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0ID0geyBvcHM6IFtdLCBhcmdzOiBbXSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5MaXN0Lm9wcy5wdXNoKG9wZXJhdGlvbik7XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5hcmdzLnB1c2goX2NvbmNhdChhcmdzKSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuXG5cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplQXJyYXlzID0gZnVuY3Rpb24gKG9wZXJhdGlvbnMsIGFyZywgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIGlmICghcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0ID0geyBvcHM6IFtdLCBhcmdzOiBbXSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAkLmVhY2gob3BlcmF0aW9ucywgZnVuY3Rpb24gKGluZGV4LCBvcG4pIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdChvcG4pKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBfbm9ybWFsaXplT2JqZWN0KG9wbiwgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBfbm9ybWFsaXplTGl0ZXJhbHMob3BuLCBhcmdzW2luZGV4XSwgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qob3BlcmF0aW9ucykpIHtcbiAgICAgICAgICAgICAgICBfbm9ybWFsaXplT2JqZWN0KG9wZXJhdGlvbnMsIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfSBlbHNlIGlmICgkLmlzQXJyYXkob3BlcmF0aW9ucykpIHtcbiAgICAgICAgICAgICAgICBfbm9ybWFsaXplQXJyYXlzKG9wZXJhdGlvbnMsIGFyZ3MsIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBfbm9ybWFsaXplTGl0ZXJhbHMob3BlcmF0aW9ucywgYXJncywgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICB9LFxuXG4gICAgICAgIHNwbGl0R2V0RmFjdG9yeTogZnVuY3Rpb24gKGh0dHBPcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgICAgIHZhciBodHRwID0gdGhpcztcbiAgICAgICAgICAgICAgICB2YXIgZ2V0VmFsdWUgPSBmdW5jdGlvbiAobmFtZSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgdmFsdWUgPSBvcHRpb25zW25hbWVdIHx8IGh0dHBPcHRpb25zW25hbWVdO1xuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IHZhbHVlKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdmFyIGdldEZpbmFsVXJsID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICAgICAgICAgICAgICAgICAgICB2YXIgdXJsID0gZ2V0VmFsdWUoJ3VybCcsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgZGF0YSA9IHBhcmFtcztcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhlcmUgaXMgZWFzeSAob3Iga25vd24pIHdheSB0byBnZXQgdGhlIGZpbmFsIFVSTCBqcXVlcnkgaXMgZ29pbmcgdG8gc2VuZCBzb1xuICAgICAgICAgICAgICAgICAgICAvLyB3ZSdyZSByZXBsaWNhdGluZyBpdC4gVGhlIHByb2Nlc3MgbWlnaHQgY2hhbmdlIGF0IHNvbWUgcG9pbnQgYnV0IGl0IHByb2JhYmx5IHdpbGwgbm90LlxuICAgICAgICAgICAgICAgICAgICAvLyAxLiBSZW1vdmUgaGFzaFxuICAgICAgICAgICAgICAgICAgICB1cmwgPSB1cmwucmVwbGFjZSgvIy4qJC8sICcnKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gMS4gQXBwZW5kIHF1ZXJ5IHN0cmluZ1xuICAgICAgICAgICAgICAgICAgICB2YXIgcXVlcnlQYXJhbXMgPSBxdXRpbC50b1F1ZXJ5Rm9ybWF0KGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgcXVlc3Rpb25JZHggPSB1cmwuaW5kZXhPZignPycpO1xuICAgICAgICAgICAgICAgICAgICBpZiAocXVlcnlQYXJhbXMgJiYgcXVlc3Rpb25JZHggPiAtMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVybCArICcmJyArIHF1ZXJ5UGFyYW1zO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHF1ZXJ5UGFyYW1zKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdXJsICsgJz8nICsgcXVlcnlQYXJhbXM7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVybDtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIHZhciB1cmwgPSBnZXRGaW5hbFVybChwYXJhbXMpO1xuICAgICAgICAgICAgICAgIC8vIFdlIG11c3Qgc3BsaXQgdGhlIEdFVCBpbiBtdWx0aXBsZSBzaG9ydCBVUkwnc1xuICAgICAgICAgICAgICAgIC8vIFRoZSBvbmx5IHByb3BlcnR5IGFsbG93ZWQgdG8gYmUgc3BsaXQgaXMgXCJpbmNsdWRlXCJcbiAgICAgICAgICAgICAgICBpZiAocGFyYW1zICYmIHBhcmFtcy5pbmNsdWRlICYmIGVuY29kZVVSSSh1cmwpLmxlbmd0aCA+IE1BWF9VUkxfTEVOR1RIKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBwYXJhbXNDb3B5ID0gJC5leHRlbmQodHJ1ZSwge30sIHBhcmFtcyk7XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBwYXJhbXNDb3B5LmluY2x1ZGU7XG4gICAgICAgICAgICAgICAgICAgIHZhciB1cmxOb0luY2x1ZGVzID0gZ2V0RmluYWxVcmwocGFyYW1zQ29weSk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBkaWZmID0gTUFYX1VSTF9MRU5HVEggLSB1cmxOb0luY2x1ZGVzLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBvcHRpb25zLnN1Y2Nlc3MgfHwgaHR0cE9wdGlvbnMuc3VjY2VzcyB8fCAkLm5vb3A7XG4gICAgICAgICAgICAgICAgICAgIHZhciBvbGRFcnJvciA9IG9wdGlvbnMuZXJyb3IgfHwgaHR0cE9wdGlvbnMuZXJyb3IgfHwgJC5ub29wO1xuICAgICAgICAgICAgICAgICAgICAvLyByZW1vdmUgdGhlIG9yaWdpbmFsIHN1Y2Nlc3MgYW5kIGVycm9yIGNhbGxiYWNrc1xuICAgICAgICAgICAgICAgICAgICBvcHRpb25zLnN1Y2Nlc3MgPSAkLm5vb3A7XG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuZXJyb3IgPSAkLm5vb3A7XG5cbiAgICAgICAgICAgICAgICAgICAgdmFyIGluY2x1ZGUgPSBwYXJhbXMuaW5jbHVkZTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGN1cnJJbmNsdWRlcyA9IFtdO1xuICAgICAgICAgICAgICAgICAgICB2YXIgaW5jbHVkZU9wdHMgPSBbY3VyckluY2x1ZGVzXTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGN1cnJMZW5ndGggPSBlbmNvZGVVUklDb21wb25lbnQoJz9pbmNsdWRlPScpLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZhcmlhYmxlID0gaW5jbHVkZS5wb3AoKTtcbiAgICAgICAgICAgICAgICAgICAgd2hpbGUgKHZhcmlhYmxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgdmFyTGVuZ2h0ID0gZW5jb2RlVVJJQ29tcG9uZW50KHZhcmlhYmxlKS5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVc2UgYSBncmVlZHkgYXBwcm9hY2ggZm9yIG5vdywgY2FuIGJlIG9wdGltaXplZCB0byBiZSBzb2x2ZWQgaW4gYSBtb3JlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBlZmZpY2llbnQgd2F5XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyArIDEgaXMgdGhlIGNvbW1hXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY3Vyckxlbmd0aCArIHZhckxlbmdodCArIDEgPCBkaWZmKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyckluY2x1ZGVzLnB1c2godmFyaWFibGUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJMZW5ndGggKz0gdmFyTGVuZ2h0ICsgMTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyckluY2x1ZGVzID0gW3ZhcmlhYmxlXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlT3B0cy5wdXNoKGN1cnJJbmNsdWRlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3Vyckxlbmd0aCA9ICc/aW5jbHVkZT0nLmxlbmd0aCArIHZhckxlbmdodDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlID0gaW5jbHVkZS5wb3AoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB2YXIgcmVxcyA9ICQubWFwKGluY2x1ZGVPcHRzLCBmdW5jdGlvbiAoaW5jbHVkZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJlcVBhcmFtcyA9ICQuZXh0ZW5kKHt9LCBwYXJhbXMsIHsgaW5jbHVkZTogaW5jbHVkZSB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChyZXFQYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgJC53aGVuLmFwcGx5KCQsIHJlcXMpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRWFjaCBhcmd1bWVudCBhcmUgYXJyYXlzIG9mIHRoZSBhcmd1bWVudHMgb2YgZWFjaCBkb25lIHJlcXVlc3RcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNvIHRoZSBmaXJzdCBhcmd1bWVudCBvZiB0aGUgZmlyc3QgYXJyYXkgb2YgYXJndW1lbnRzIGlzIHRoZSBkYXRhXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNWYWxpZCA9IGFyZ3VtZW50c1swXSAmJiBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWlzVmFsaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTaG91bGQgbmV2ZXIgaGFwcGVuLi4uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkRXJyb3IoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZHRkLnJlamVjdCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZpcnN0UmVzcG9uc2UgPSBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNPYmplY3QgPSAkLmlzUGxhaW5PYmplY3QoZmlyc3RSZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNSdW5BUEkgPSAoaXNPYmplY3QgJiYgJC5pc1BsYWluT2JqZWN0KGZpcnN0UmVzcG9uc2UudmFyaWFibGVzKSkgfHwgIWlzT2JqZWN0O1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzUnVuQVBJKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzT2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFnZ3JlZ2F0ZSB0aGUgdmFyaWFibGVzIHByb3BlcnR5IG9ubHlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGFnZ3JlZ2F0ZVJ1biA9IGFyZ3VtZW50c1swXVswXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJ1biA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmV4dGVuZCh0cnVlLCBhZ2dyZWdhdGVSdW4udmFyaWFibGVzLCBydW4udmFyaWFibGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlUnVuLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZVJ1biwgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFycmF5IG9mIHJ1bnNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQWdyZWdhdGUgdmFyaWFibGVzIGluIGVhY2ggcnVuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVkUnVucyA9IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2goYXJndW1lbnRzLCBmdW5jdGlvbiAoaWR4LCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcnVucyA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISQuaXNBcnJheShydW5zKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChydW5zLCBmdW5jdGlvbiAoaWR4UnVuLCBydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocnVuLmlkICYmICFhZ2dyZWdhdGVkUnVuc1tydW4uaWRdKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bi52YXJpYWJsZXMgPSBydW4udmFyaWFibGVzIHx8IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyZWdhdGVkUnVuc1tydW4uaWRdID0gcnVuO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAocnVuLmlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZWRSdW5zW3J1bi5pZF0udmFyaWFibGVzLCBydW4udmFyaWFibGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHR1cm4gaXQgaW50byBhbiBhcnJheVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyZWdhdGVkUnVucyA9ICQubWFwKGFnZ3JlZ2F0ZWRSdW5zLCBmdW5jdGlvbiAocnVuKSB7IHJldHVybiBydW47IH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRTdWNjZXNzKGFnZ3JlZ2F0ZWRSdW5zLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZWRSdW5zLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpcyB2YXJpYWJsZXMgQVBJXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWdncmVnYXRlIHRoZSByZXNwb25zZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVkVmFyaWFibGVzID0ge307XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgdmFycyA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIHZhcnMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlZFZhcmlhYmxlcywgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgb2xkRXJyb3IuYXBwbHkoaHR0cCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZWplY3QuYXBwbHkoZHRkLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH07XG59KCkpO1xuIl19 +======= },{"./query-util":48}]},{},[6]) //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvYmFzZTY0LWpzL2xpYi9iNjQuanMiLCJub2RlX21vZHVsZXMvYnVmZmVyL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2llZWU3NTQvaW5kZXguanMiLCJub2RlX21vZHVsZXMvaXNhcnJheS9pbmRleC5qcyIsInNyYy9hcGktdmVyc2lvbi5qc29uIiwic3JjL2FwcC5qcyIsInNyYy9lbnYtbG9hZC5qcyIsInNyYy9tYW5hZ2Vycy9hdXRoLW1hbmFnZXIuanMiLCJzcmMvbWFuYWdlcnMvY2hhbm5lbC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIuanMiLCJzcmMvbWFuYWdlcnMva2V5LW5hbWVzLmpzIiwic3JjL21hbmFnZXJzL3J1bi1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2Fsd2F5cy1uZXctc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvY29uZGl0aW9uYWwtY3JlYXRpb24tc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvaWRlbnRpdHktc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvbXVsdGlwbGF5ZXItc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvbmV3LWlmLWluaXRpYWxpemVkLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1taXNzaW5nLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1wZXJzaXN0ZWQtc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvcGVyc2lzdGVudC1zaW5nbGUtcGxheWVyLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL3N0cmF0ZWdpZXMtbWFwLmpzIiwic3JjL21hbmFnZXJzL3NjZW5hcmlvLW1hbmFnZXIuanMiLCJzcmMvbWFuYWdlcnMvc3BlY2lhbC1vcGVyYXRpb25zLmpzIiwic3JjL21hbmFnZXJzL3dvcmxkLW1hbmFnZXIuanMiLCJzcmMvc2VydmljZS9hZG1pbi1maWxlLXNlcnZpY2UuanMiLCJzcmMvc2VydmljZS9hc3NldC1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL2F1dGgtYXBpLXNlcnZpY2UuanMiLCJzcmMvc2VydmljZS9jaGFubmVsLXNlcnZpY2UuanMiLCJzcmMvc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UuanMiLCJzcmMvc2VydmljZS9kYXRhLWFwaS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvaW50cm9zcGVjdGlvbi1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3J1bi1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3N0YXRlLWFwaS1hZGFwdGVyLmpzIiwic3JjL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3ZhcmlhYmxlcy1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyLmpzIiwic3JjL3N0b3JlL2Nvb2tpZS1zdG9yZS5qcyIsInNyYy9zdG9yZS9zZXNzaW9uLW1hbmFnZXIuanMiLCJzcmMvc3RvcmUvc3RvcmUtZmFjdG9yeS5qcyIsInNyYy90cmFuc3BvcnQvYWpheC1odHRwLXRyYW5zcG9ydC5qcyIsInNyYy90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeS5qcyIsInNyYy91dGlsL2luaGVyaXQuanMiLCJzcmMvdXRpbC9tYWtlLXNlcXVlbmNlLmpzIiwic3JjL3V0aWwvb2JqZWN0LXV0aWwuanMiLCJzcmMvdXRpbC9vcHRpb24tdXRpbHMuanMiLCJzcmMvdXRpbC9xdWVyeS11dGlsLmpzIiwic3JjL3V0aWwvcnVuLXV0aWwuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUM3R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQy9xREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNMQTtBQUNBO0FBQ0E7QUFDQTs7O0FDSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUNsRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvV0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwUEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN1hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6S0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9JQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxWEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwT0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDblFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6TEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1ZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM3VCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNWQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0dBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ05BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3REQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIndXNlIHN0cmljdCdcblxuZXhwb3J0cy50b0J5dGVBcnJheSA9IHRvQnl0ZUFycmF5XG5leHBvcnRzLmZyb21CeXRlQXJyYXkgPSBmcm9tQnl0ZUFycmF5XG5cbnZhciBsb29rdXAgPSBbXVxudmFyIHJldkxvb2t1cCA9IFtdXG52YXIgQXJyID0gdHlwZW9mIFVpbnQ4QXJyYXkgIT09ICd1bmRlZmluZWQnID8gVWludDhBcnJheSA6IEFycmF5XG5cbmZ1bmN0aW9uIGluaXQgKCkge1xuICB2YXIgY29kZSA9ICdBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsvJ1xuICBmb3IgKHZhciBpID0gMCwgbGVuID0gY29kZS5sZW5ndGg7IGkgPCBsZW47ICsraSkge1xuICAgIGxvb2t1cFtpXSA9IGNvZGVbaV1cbiAgICByZXZMb29rdXBbY29kZS5jaGFyQ29kZUF0KGkpXSA9IGlcbiAgfVxuXG4gIHJldkxvb2t1cFsnLScuY2hhckNvZGVBdCgwKV0gPSA2MlxuICByZXZMb29rdXBbJ18nLmNoYXJDb2RlQXQoMCldID0gNjNcbn1cblxuaW5pdCgpXG5cbmZ1bmN0aW9uIHRvQnl0ZUFycmF5IChiNjQpIHtcbiAgdmFyIGksIGosIGwsIHRtcCwgcGxhY2VIb2xkZXJzLCBhcnJcbiAgdmFyIGxlbiA9IGI2NC5sZW5ndGhcblxuICBpZiAobGVuICUgNCA+IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgc3RyaW5nLiBMZW5ndGggbXVzdCBiZSBhIG11bHRpcGxlIG9mIDQnKVxuICB9XG5cbiAgLy8gdGhlIG51bWJlciBvZiBlcXVhbCBzaWducyAocGxhY2UgaG9sZGVycylcbiAgLy8gaWYgdGhlcmUgYXJlIHR3byBwbGFjZWhvbGRlcnMsIHRoYW4gdGhlIHR3byBjaGFyYWN0ZXJzIGJlZm9yZSBpdFxuICAvLyByZXByZXNlbnQgb25lIGJ5dGVcbiAgLy8gaWYgdGhlcmUgaXMgb25seSBvbmUsIHRoZW4gdGhlIHRocmVlIGNoYXJhY3RlcnMgYmVmb3JlIGl0IHJlcHJlc2VudCAyIGJ5dGVzXG4gIC8vIHRoaXMgaXMganVzdCBhIGNoZWFwIGhhY2sgdG8gbm90IGRvIGluZGV4T2YgdHdpY2VcbiAgcGxhY2VIb2xkZXJzID0gYjY0W2xlbiAtIDJdID09PSAnPScgPyAyIDogYjY0W2xlbiAtIDFdID09PSAnPScgPyAxIDogMFxuXG4gIC8vIGJhc2U2NCBpcyA0LzMgKyB1cCB0byB0d28gY2hhcmFjdGVycyBvZiB0aGUgb3JpZ2luYWwgZGF0YVxuICBhcnIgPSBuZXcgQXJyKGxlbiAqIDMgLyA0IC0gcGxhY2VIb2xkZXJzKVxuXG4gIC8vIGlmIHRoZXJlIGFyZSBwbGFjZWhvbGRlcnMsIG9ubHkgZ2V0IHVwIHRvIHRoZSBsYXN0IGNvbXBsZXRlIDQgY2hhcnNcbiAgbCA9IHBsYWNlSG9sZGVycyA+IDAgPyBsZW4gLSA0IDogbGVuXG5cbiAgdmFyIEwgPSAwXG5cbiAgZm9yIChpID0gMCwgaiA9IDA7IGkgPCBsOyBpICs9IDQsIGogKz0gMykge1xuICAgIHRtcCA9IChyZXZMb29rdXBbYjY0LmNoYXJDb2RlQXQoaSldIDw8IDE4KSB8IChyZXZMb29rdXBbYjY0LmNoYXJDb2RlQXQoaSArIDEpXSA8PCAxMikgfCAocmV2TG9va3VwW2I2NC5jaGFyQ29kZUF0KGkgKyAyKV0gPDwgNikgfCByZXZMb29rdXBbYjY0LmNoYXJDb2RlQXQoaSArIDMpXVxuICAgIGFycltMKytdID0gKHRtcCA+PiAxNikgJiAweEZGXG4gICAgYXJyW0wrK10gPSAodG1wID4+IDgpICYgMHhGRlxuICAgIGFycltMKytdID0gdG1wICYgMHhGRlxuICB9XG5cbiAgaWYgKHBsYWNlSG9sZGVycyA9PT0gMikge1xuICAgIHRtcCA9IChyZXZMb29rdXBbYjY0LmNoYXJDb2RlQXQoaSldIDw8IDIpIHwgKHJldkxvb2t1cFtiNjQuY2hhckNvZGVBdChpICsgMSldID4+IDQpXG4gICAgYXJyW0wrK10gPSB0bXAgJiAweEZGXG4gIH0gZWxzZSBpZiAocGxhY2VIb2xkZXJzID09PSAxKSB7XG4gICAgdG1wID0gKHJldkxvb2t1cFtiNjQuY2hhckNvZGVBdChpKV0gPDwgMTApIHwgKHJldkxvb2t1cFtiNjQuY2hhckNvZGVBdChpICsgMSldIDw8IDQpIHwgKHJldkxvb2t1cFtiNjQuY2hhckNvZGVBdChpICsgMildID4+IDIpXG4gICAgYXJyW0wrK10gPSAodG1wID4+IDgpICYgMHhGRlxuICAgIGFycltMKytdID0gdG1wICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIGFyclxufVxuXG5mdW5jdGlvbiB0cmlwbGV0VG9CYXNlNjQgKG51bSkge1xuICByZXR1cm4gbG9va3VwW251bSA+PiAxOCAmIDB4M0ZdICsgbG9va3VwW251bSA+PiAxMiAmIDB4M0ZdICsgbG9va3VwW251bSA+PiA2ICYgMHgzRl0gKyBsb29rdXBbbnVtICYgMHgzRl1cbn1cblxuZnVuY3Rpb24gZW5jb2RlQ2h1bmsgKHVpbnQ4LCBzdGFydCwgZW5kKSB7XG4gIHZhciB0bXBcbiAgdmFyIG91dHB1dCA9IFtdXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgaSArPSAzKSB7XG4gICAgdG1wID0gKHVpbnQ4W2ldIDw8IDE2KSArICh1aW50OFtpICsgMV0gPDwgOCkgKyAodWludDhbaSArIDJdKVxuICAgIG91dHB1dC5wdXNoKHRyaXBsZXRUb0Jhc2U2NCh0bXApKVxuICB9XG4gIHJldHVybiBvdXRwdXQuam9pbignJylcbn1cblxuZnVuY3Rpb24gZnJvbUJ5dGVBcnJheSAodWludDgpIHtcbiAgdmFyIHRtcFxuICB2YXIgbGVuID0gdWludDgubGVuZ3RoXG4gIHZhciBleHRyYUJ5dGVzID0gbGVuICUgMyAvLyBpZiB3ZSBoYXZlIDEgYnl0ZSBsZWZ0LCBwYWQgMiBieXRlc1xuICB2YXIgb3V0cHV0ID0gJydcbiAgdmFyIHBhcnRzID0gW11cbiAgdmFyIG1heENodW5rTGVuZ3RoID0gMTYzODMgLy8gbXVzdCBiZSBtdWx0aXBsZSBvZiAzXG5cbiAgLy8gZ28gdGhyb3VnaCB0aGUgYXJyYXkgZXZlcnkgdGhyZWUgYnl0ZXMsIHdlJ2xsIGRlYWwgd2l0aCB0cmFpbGluZyBzdHVmZiBsYXRlclxuICBmb3IgKHZhciBpID0gMCwgbGVuMiA9IGxlbiAtIGV4dHJhQnl0ZXM7IGkgPCBsZW4yOyBpICs9IG1heENodW5rTGVuZ3RoKSB7XG4gICAgcGFydHMucHVzaChlbmNvZGVDaHVuayh1aW50OCwgaSwgKGkgKyBtYXhDaHVua0xlbmd0aCkgPiBsZW4yID8gbGVuMiA6IChpICsgbWF4Q2h1bmtMZW5ndGgpKSlcbiAgfVxuXG4gIC8vIHBhZCB0aGUgZW5kIHdpdGggemVyb3MsIGJ1dCBtYWtlIHN1cmUgdG8gbm90IGZvcmdldCB0aGUgZXh0cmEgYnl0ZXNcbiAgaWYgKGV4dHJhQnl0ZXMgPT09IDEpIHtcbiAgICB0bXAgPSB1aW50OFtsZW4gLSAxXVxuICAgIG91dHB1dCArPSBsb29rdXBbdG1wID4+IDJdXG4gICAgb3V0cHV0ICs9IGxvb2t1cFsodG1wIDw8IDQpICYgMHgzRl1cbiAgICBvdXRwdXQgKz0gJz09J1xuICB9IGVsc2UgaWYgKGV4dHJhQnl0ZXMgPT09IDIpIHtcbiAgICB0bXAgPSAodWludDhbbGVuIC0gMl0gPDwgOCkgKyAodWludDhbbGVuIC0gMV0pXG4gICAgb3V0cHV0ICs9IGxvb2t1cFt0bXAgPj4gMTBdXG4gICAgb3V0cHV0ICs9IGxvb2t1cFsodG1wID4+IDQpICYgMHgzRl1cbiAgICBvdXRwdXQgKz0gbG9va3VwWyh0bXAgPDwgMikgJiAweDNGXVxuICAgIG91dHB1dCArPSAnPSdcbiAgfVxuXG4gIHBhcnRzLnB1c2gob3V0cHV0KVxuXG4gIHJldHVybiBwYXJ0cy5qb2luKCcnKVxufVxuIiwiLyohXG4gKiBUaGUgYnVmZmVyIG1vZHVsZSBmcm9tIG5vZGUuanMsIGZvciB0aGUgYnJvd3Nlci5cbiAqXG4gKiBAYXV0aG9yICAgRmVyb3NzIEFib3VraGFkaWplaCA8ZmVyb3NzQGZlcm9zcy5vcmc+IDxodHRwOi8vZmVyb3NzLm9yZz5cbiAqIEBsaWNlbnNlICBNSVRcbiAqL1xuLyogZXNsaW50LWRpc2FibGUgbm8tcHJvdG8gKi9cblxuJ3VzZSBzdHJpY3QnXG5cbnZhciBiYXNlNjQgPSByZXF1aXJlKCdiYXNlNjQtanMnKVxudmFyIGllZWU3NTQgPSByZXF1aXJlKCdpZWVlNzU0JylcbnZhciBpc0FycmF5ID0gcmVxdWlyZSgnaXNhcnJheScpXG5cbmV4cG9ydHMuQnVmZmVyID0gQnVmZmVyXG5leHBvcnRzLlNsb3dCdWZmZXIgPSBTbG93QnVmZmVyXG5leHBvcnRzLklOU1BFQ1RfTUFYX0JZVEVTID0gNTBcblxuLyoqXG4gKiBJZiBgQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRgOlxuICogICA9PT0gdHJ1ZSAgICBVc2UgVWludDhBcnJheSBpbXBsZW1lbnRhdGlvbiAoZmFzdGVzdClcbiAqICAgPT09IGZhbHNlICAgVXNlIE9iamVjdCBpbXBsZW1lbnRhdGlvbiAobW9zdCBjb21wYXRpYmxlLCBldmVuIElFNilcbiAqXG4gKiBCcm93c2VycyB0aGF0IHN1cHBvcnQgdHlwZWQgYXJyYXlzIGFyZSBJRSAxMCssIEZpcmVmb3ggNCssIENocm9tZSA3KywgU2FmYXJpIDUuMSssXG4gKiBPcGVyYSAxMS42KywgaU9TIDQuMisuXG4gKlxuICogRHVlIHRvIHZhcmlvdXMgYnJvd3NlciBidWdzLCBzb21ldGltZXMgdGhlIE9iamVjdCBpbXBsZW1lbnRhdGlvbiB3aWxsIGJlIHVzZWQgZXZlblxuICogd2hlbiB0aGUgYnJvd3NlciBzdXBwb3J0cyB0eXBlZCBhcnJheXMuXG4gKlxuICogTm90ZTpcbiAqXG4gKiAgIC0gRmlyZWZveCA0LTI5IGxhY2tzIHN1cHBvcnQgZm9yIGFkZGluZyBuZXcgcHJvcGVydGllcyB0byBgVWludDhBcnJheWAgaW5zdGFuY2VzLFxuICogICAgIFNlZTogaHR0cHM6Ly9idWd6aWxsYS5tb3ppbGxhLm9yZy9zaG93X2J1Zy5jZ2k/aWQ9Njk1NDM4LlxuICpcbiAqICAgLSBDaHJvbWUgOS0xMCBpcyBtaXNzaW5nIHRoZSBgVHlwZWRBcnJheS5wcm90b3R5cGUuc3ViYXJyYXlgIGZ1bmN0aW9uLlxuICpcbiAqICAgLSBJRTEwIGhhcyBhIGJyb2tlbiBgVHlwZWRBcnJheS5wcm90b3R5cGUuc3ViYXJyYXlgIGZ1bmN0aW9uIHdoaWNoIHJldHVybnMgYXJyYXlzIG9mXG4gKiAgICAgaW5jb3JyZWN0IGxlbmd0aCBpbiBzb21lIHNpdHVhdGlvbnMuXG5cbiAqIFdlIGRldGVjdCB0aGVzZSBidWdneSBicm93c2VycyBhbmQgc2V0IGBCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVGAgdG8gYGZhbHNlYCBzbyB0aGV5XG4gKiBnZXQgdGhlIE9iamVjdCBpbXBsZW1lbnRhdGlvbiwgd2hpY2ggaXMgc2xvd2VyIGJ1dCBiZWhhdmVzIGNvcnJlY3RseS5cbiAqL1xuQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQgPSBnbG9iYWwuVFlQRURfQVJSQVlfU1VQUE9SVCAhPT0gdW5kZWZpbmVkXG4gID8gZ2xvYmFsLlRZUEVEX0FSUkFZX1NVUFBPUlRcbiAgOiB0eXBlZEFycmF5U3VwcG9ydCgpXG5cbi8qXG4gKiBFeHBvcnQga01heExlbmd0aCBhZnRlciB0eXBlZCBhcnJheSBzdXBwb3J0IGlzIGRldGVybWluZWQuXG4gKi9cbmV4cG9ydHMua01heExlbmd0aCA9IGtNYXhMZW5ndGgoKVxuXG5mdW5jdGlvbiB0eXBlZEFycmF5U3VwcG9ydCAoKSB7XG4gIHRyeSB7XG4gICAgdmFyIGFyciA9IG5ldyBVaW50OEFycmF5KDEpXG4gICAgYXJyLl9fcHJvdG9fXyA9IHtfX3Byb3RvX186IFVpbnQ4QXJyYXkucHJvdG90eXBlLCBmb286IGZ1bmN0aW9uICgpIHsgcmV0dXJuIDQyIH19XG4gICAgcmV0dXJuIGFyci5mb28oKSA9PT0gNDIgJiYgLy8gdHlwZWQgYXJyYXkgaW5zdGFuY2VzIGNhbiBiZSBhdWdtZW50ZWRcbiAgICAgICAgdHlwZW9mIGFyci5zdWJhcnJheSA9PT0gJ2Z1bmN0aW9uJyAmJiAvLyBjaHJvbWUgOS0xMCBsYWNrIGBzdWJhcnJheWBcbiAgICAgICAgYXJyLnN1YmFycmF5KDEsIDEpLmJ5dGVMZW5ndGggPT09IDAgLy8gaWUxMCBoYXMgYnJva2VuIGBzdWJhcnJheWBcbiAgfSBjYXRjaCAoZSkge1xuICAgIHJldHVybiBmYWxzZVxuICB9XG59XG5cbmZ1bmN0aW9uIGtNYXhMZW5ndGggKCkge1xuICByZXR1cm4gQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRcbiAgICA/IDB4N2ZmZmZmZmZcbiAgICA6IDB4M2ZmZmZmZmZcbn1cblxuZnVuY3Rpb24gY3JlYXRlQnVmZmVyICh0aGF0LCBsZW5ndGgpIHtcbiAgaWYgKGtNYXhMZW5ndGgoKSA8IGxlbmd0aCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdJbnZhbGlkIHR5cGVkIGFycmF5IGxlbmd0aCcpXG4gIH1cbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gUmV0dXJuIGFuIGF1Z21lbnRlZCBgVWludDhBcnJheWAgaW5zdGFuY2UsIGZvciBiZXN0IHBlcmZvcm1hbmNlXG4gICAgdGhhdCA9IG5ldyBVaW50OEFycmF5KGxlbmd0aClcbiAgICB0aGF0Ll9fcHJvdG9fXyA9IEJ1ZmZlci5wcm90b3R5cGVcbiAgfSBlbHNlIHtcbiAgICAvLyBGYWxsYmFjazogUmV0dXJuIGFuIG9iamVjdCBpbnN0YW5jZSBvZiB0aGUgQnVmZmVyIGNsYXNzXG4gICAgaWYgKHRoYXQgPT09IG51bGwpIHtcbiAgICAgIHRoYXQgPSBuZXcgQnVmZmVyKGxlbmd0aClcbiAgICB9XG4gICAgdGhhdC5sZW5ndGggPSBsZW5ndGhcbiAgfVxuXG4gIHJldHVybiB0aGF0XG59XG5cbi8qKlxuICogVGhlIEJ1ZmZlciBjb25zdHJ1Y3RvciByZXR1cm5zIGluc3RhbmNlcyBvZiBgVWludDhBcnJheWAgdGhhdCBoYXZlIHRoZWlyXG4gKiBwcm90b3R5cGUgY2hhbmdlZCB0byBgQnVmZmVyLnByb3RvdHlwZWAuIEZ1cnRoZXJtb3JlLCBgQnVmZmVyYCBpcyBhIHN1YmNsYXNzIG9mXG4gKiBgVWludDhBcnJheWAsIHNvIHRoZSByZXR1cm5lZCBpbnN0YW5jZXMgd2lsbCBoYXZlIGFsbCB0aGUgbm9kZSBgQnVmZmVyYCBtZXRob2RzXG4gKiBhbmQgdGhlIGBVaW50OEFycmF5YCBtZXRob2RzLiBTcXVhcmUgYnJhY2tldCBub3RhdGlvbiB3b3JrcyBhcyBleHBlY3RlZCAtLSBpdFxuICogcmV0dXJucyBhIHNpbmdsZSBvY3RldC5cbiAqXG4gKiBUaGUgYFVpbnQ4QXJyYXlgIHByb3RvdHlwZSByZW1haW5zIHVubW9kaWZpZWQuXG4gKi9cblxuZnVuY3Rpb24gQnVmZmVyIChhcmcsIGVuY29kaW5nT3JPZmZzZXQsIGxlbmd0aCkge1xuICBpZiAoIUJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUICYmICEodGhpcyBpbnN0YW5jZW9mIEJ1ZmZlcikpIHtcbiAgICByZXR1cm4gbmV3IEJ1ZmZlcihhcmcsIGVuY29kaW5nT3JPZmZzZXQsIGxlbmd0aClcbiAgfVxuXG4gIC8vIENvbW1vbiBjYXNlLlxuICBpZiAodHlwZW9mIGFyZyA9PT0gJ251bWJlcicpIHtcbiAgICBpZiAodHlwZW9mIGVuY29kaW5nT3JPZmZzZXQgPT09ICdzdHJpbmcnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICdJZiBlbmNvZGluZyBpcyBzcGVjaWZpZWQgdGhlbiB0aGUgZmlyc3QgYXJndW1lbnQgbXVzdCBiZSBhIHN0cmluZydcbiAgICAgIClcbiAgICB9XG4gICAgcmV0dXJuIGFsbG9jVW5zYWZlKHRoaXMsIGFyZylcbiAgfVxuICByZXR1cm4gZnJvbSh0aGlzLCBhcmcsIGVuY29kaW5nT3JPZmZzZXQsIGxlbmd0aClcbn1cblxuQnVmZmVyLnBvb2xTaXplID0gODE5MiAvLyBub3QgdXNlZCBieSB0aGlzIGltcGxlbWVudGF0aW9uXG5cbi8vIFRPRE86IExlZ2FjeSwgbm90IG5lZWRlZCBhbnltb3JlLiBSZW1vdmUgaW4gbmV4dCBtYWpvciB2ZXJzaW9uLlxuQnVmZmVyLl9hdWdtZW50ID0gZnVuY3Rpb24gKGFycikge1xuICBhcnIuX19wcm90b19fID0gQnVmZmVyLnByb3RvdHlwZVxuICByZXR1cm4gYXJyXG59XG5cbmZ1bmN0aW9uIGZyb20gKHRoYXQsIHZhbHVlLCBlbmNvZGluZ09yT2Zmc2V0LCBsZW5ndGgpIHtcbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdcInZhbHVlXCIgYXJndW1lbnQgbXVzdCBub3QgYmUgYSBudW1iZXInKVxuICB9XG5cbiAgaWYgKHR5cGVvZiBBcnJheUJ1ZmZlciAhPT0gJ3VuZGVmaW5lZCcgJiYgdmFsdWUgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikge1xuICAgIHJldHVybiBmcm9tQXJyYXlCdWZmZXIodGhhdCwgdmFsdWUsIGVuY29kaW5nT3JPZmZzZXQsIGxlbmd0aClcbiAgfVxuXG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIGZyb21TdHJpbmcodGhhdCwgdmFsdWUsIGVuY29kaW5nT3JPZmZzZXQpXG4gIH1cblxuICByZXR1cm4gZnJvbU9iamVjdCh0aGF0LCB2YWx1ZSlcbn1cblxuLyoqXG4gKiBGdW5jdGlvbmFsbHkgZXF1aXZhbGVudCB0byBCdWZmZXIoYXJnLCBlbmNvZGluZykgYnV0IHRocm93cyBhIFR5cGVFcnJvclxuICogaWYgdmFsdWUgaXMgYSBudW1iZXIuXG4gKiBCdWZmZXIuZnJvbShzdHJbLCBlbmNvZGluZ10pXG4gKiBCdWZmZXIuZnJvbShhcnJheSlcbiAqIEJ1ZmZlci5mcm9tKGJ1ZmZlcilcbiAqIEJ1ZmZlci5mcm9tKGFycmF5QnVmZmVyWywgYnl0ZU9mZnNldFssIGxlbmd0aF1dKVxuICoqL1xuQnVmZmVyLmZyb20gPSBmdW5jdGlvbiAodmFsdWUsIGVuY29kaW5nT3JPZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gZnJvbShudWxsLCB2YWx1ZSwgZW5jb2RpbmdPck9mZnNldCwgbGVuZ3RoKVxufVxuXG5pZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgQnVmZmVyLnByb3RvdHlwZS5fX3Byb3RvX18gPSBVaW50OEFycmF5LnByb3RvdHlwZVxuICBCdWZmZXIuX19wcm90b19fID0gVWludDhBcnJheVxuICBpZiAodHlwZW9mIFN5bWJvbCAhPT0gJ3VuZGVmaW5lZCcgJiYgU3ltYm9sLnNwZWNpZXMgJiZcbiAgICAgIEJ1ZmZlcltTeW1ib2wuc3BlY2llc10gPT09IEJ1ZmZlcikge1xuICAgIC8vIEZpeCBzdWJhcnJheSgpIGluIEVTMjAxNi4gU2VlOiBodHRwczovL2dpdGh1Yi5jb20vZmVyb3NzL2J1ZmZlci9wdWxsLzk3XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KEJ1ZmZlciwgU3ltYm9sLnNwZWNpZXMsIHtcbiAgICAgIHZhbHVlOiBudWxsLFxuICAgICAgY29uZmlndXJhYmxlOiB0cnVlXG4gICAgfSlcbiAgfVxufVxuXG5mdW5jdGlvbiBhc3NlcnRTaXplIChzaXplKSB7XG4gIGlmICh0eXBlb2Ygc2l6ZSAhPT0gJ251bWJlcicpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdcInNpemVcIiBhcmd1bWVudCBtdXN0IGJlIGEgbnVtYmVyJylcbiAgfVxufVxuXG5mdW5jdGlvbiBhbGxvYyAodGhhdCwgc2l6ZSwgZmlsbCwgZW5jb2RpbmcpIHtcbiAgYXNzZXJ0U2l6ZShzaXplKVxuICBpZiAoc2l6ZSA8PSAwKSB7XG4gICAgcmV0dXJuIGNyZWF0ZUJ1ZmZlcih0aGF0LCBzaXplKVxuICB9XG4gIGlmIChmaWxsICE9PSB1bmRlZmluZWQpIHtcbiAgICAvLyBPbmx5IHBheSBhdHRlbnRpb24gdG8gZW5jb2RpbmcgaWYgaXQncyBhIHN0cmluZy4gVGhpc1xuICAgIC8vIHByZXZlbnRzIGFjY2lkZW50YWxseSBzZW5kaW5nIGluIGEgbnVtYmVyIHRoYXQgd291bGRcbiAgICAvLyBiZSBpbnRlcnByZXR0ZWQgYXMgYSBzdGFydCBvZmZzZXQuXG4gICAgcmV0dXJuIHR5cGVvZiBlbmNvZGluZyA9PT0gJ3N0cmluZydcbiAgICAgID8gY3JlYXRlQnVmZmVyKHRoYXQsIHNpemUpLmZpbGwoZmlsbCwgZW5jb2RpbmcpXG4gICAgICA6IGNyZWF0ZUJ1ZmZlcih0aGF0LCBzaXplKS5maWxsKGZpbGwpXG4gIH1cbiAgcmV0dXJuIGNyZWF0ZUJ1ZmZlcih0aGF0LCBzaXplKVxufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBuZXcgZmlsbGVkIEJ1ZmZlciBpbnN0YW5jZS5cbiAqIGFsbG9jKHNpemVbLCBmaWxsWywgZW5jb2RpbmddXSlcbiAqKi9cbkJ1ZmZlci5hbGxvYyA9IGZ1bmN0aW9uIChzaXplLCBmaWxsLCBlbmNvZGluZykge1xuICByZXR1cm4gYWxsb2MobnVsbCwgc2l6ZSwgZmlsbCwgZW5jb2RpbmcpXG59XG5cbmZ1bmN0aW9uIGFsbG9jVW5zYWZlICh0aGF0LCBzaXplKSB7XG4gIGFzc2VydFNpemUoc2l6ZSlcbiAgdGhhdCA9IGNyZWF0ZUJ1ZmZlcih0aGF0LCBzaXplIDwgMCA/IDAgOiBjaGVja2VkKHNpemUpIHwgMClcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2l6ZTsgKytpKSB7XG4gICAgICB0aGF0W2ldID0gMFxuICAgIH1cbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG4vKipcbiAqIEVxdWl2YWxlbnQgdG8gQnVmZmVyKG51bSksIGJ5IGRlZmF1bHQgY3JlYXRlcyBhIG5vbi16ZXJvLWZpbGxlZCBCdWZmZXIgaW5zdGFuY2UuXG4gKiAqL1xuQnVmZmVyLmFsbG9jVW5zYWZlID0gZnVuY3Rpb24gKHNpemUpIHtcbiAgcmV0dXJuIGFsbG9jVW5zYWZlKG51bGwsIHNpemUpXG59XG4vKipcbiAqIEVxdWl2YWxlbnQgdG8gU2xvd0J1ZmZlcihudW0pLCBieSBkZWZhdWx0IGNyZWF0ZXMgYSBub24temVyby1maWxsZWQgQnVmZmVyIGluc3RhbmNlLlxuICovXG5CdWZmZXIuYWxsb2NVbnNhZmVTbG93ID0gZnVuY3Rpb24gKHNpemUpIHtcbiAgcmV0dXJuIGFsbG9jVW5zYWZlKG51bGwsIHNpemUpXG59XG5cbmZ1bmN0aW9uIGZyb21TdHJpbmcgKHRoYXQsIHN0cmluZywgZW5jb2RpbmcpIHtcbiAgaWYgKHR5cGVvZiBlbmNvZGluZyAhPT0gJ3N0cmluZycgfHwgZW5jb2RpbmcgPT09ICcnKSB7XG4gICAgZW5jb2RpbmcgPSAndXRmOCdcbiAgfVxuXG4gIGlmICghQnVmZmVyLmlzRW5jb2RpbmcoZW5jb2RpbmcpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignXCJlbmNvZGluZ1wiIG11c3QgYmUgYSB2YWxpZCBzdHJpbmcgZW5jb2RpbmcnKVxuICB9XG5cbiAgdmFyIGxlbmd0aCA9IGJ5dGVMZW5ndGgoc3RyaW5nLCBlbmNvZGluZykgfCAwXG4gIHRoYXQgPSBjcmVhdGVCdWZmZXIodGhhdCwgbGVuZ3RoKVxuXG4gIHRoYXQud3JpdGUoc3RyaW5nLCBlbmNvZGluZylcbiAgcmV0dXJuIHRoYXRcbn1cblxuZnVuY3Rpb24gZnJvbUFycmF5TGlrZSAodGhhdCwgYXJyYXkpIHtcbiAgdmFyIGxlbmd0aCA9IGNoZWNrZWQoYXJyYXkubGVuZ3RoKSB8IDBcbiAgdGhhdCA9IGNyZWF0ZUJ1ZmZlcih0aGF0LCBsZW5ndGgpXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGF0W2ldID0gYXJyYXlbaV0gJiAyNTVcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tQXJyYXlCdWZmZXIgKHRoYXQsIGFycmF5LCBieXRlT2Zmc2V0LCBsZW5ndGgpIHtcbiAgYXJyYXkuYnl0ZUxlbmd0aCAvLyB0aGlzIHRocm93cyBpZiBgYXJyYXlgIGlzIG5vdCBhIHZhbGlkIEFycmF5QnVmZmVyXG5cbiAgaWYgKGJ5dGVPZmZzZXQgPCAwIHx8IGFycmF5LmJ5dGVMZW5ndGggPCBieXRlT2Zmc2V0KSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ1xcJ29mZnNldFxcJyBpcyBvdXQgb2YgYm91bmRzJylcbiAgfVxuXG4gIGlmIChhcnJheS5ieXRlTGVuZ3RoIDwgYnl0ZU9mZnNldCArIChsZW5ndGggfHwgMCkpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignXFwnbGVuZ3RoXFwnIGlzIG91dCBvZiBib3VuZHMnKVxuICB9XG5cbiAgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgYXJyYXkgPSBuZXcgVWludDhBcnJheShhcnJheSwgYnl0ZU9mZnNldClcbiAgfSBlbHNlIHtcbiAgICBhcnJheSA9IG5ldyBVaW50OEFycmF5KGFycmF5LCBieXRlT2Zmc2V0LCBsZW5ndGgpXG4gIH1cblxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICAvLyBSZXR1cm4gYW4gYXVnbWVudGVkIGBVaW50OEFycmF5YCBpbnN0YW5jZSwgZm9yIGJlc3QgcGVyZm9ybWFuY2VcbiAgICB0aGF0ID0gYXJyYXlcbiAgICB0aGF0Ll9fcHJvdG9fXyA9IEJ1ZmZlci5wcm90b3R5cGVcbiAgfSBlbHNlIHtcbiAgICAvLyBGYWxsYmFjazogUmV0dXJuIGFuIG9iamVjdCBpbnN0YW5jZSBvZiB0aGUgQnVmZmVyIGNsYXNzXG4gICAgdGhhdCA9IGZyb21BcnJheUxpa2UodGhhdCwgYXJyYXkpXG4gIH1cbiAgcmV0dXJuIHRoYXRcbn1cblxuZnVuY3Rpb24gZnJvbU9iamVjdCAodGhhdCwgb2JqKSB7XG4gIGlmIChCdWZmZXIuaXNCdWZmZXIob2JqKSkge1xuICAgIHZhciBsZW4gPSBjaGVja2VkKG9iai5sZW5ndGgpIHwgMFxuICAgIHRoYXQgPSBjcmVhdGVCdWZmZXIodGhhdCwgbGVuKVxuXG4gICAgaWYgKHRoYXQubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gdGhhdFxuICAgIH1cblxuICAgIG9iai5jb3B5KHRoYXQsIDAsIDAsIGxlbilcbiAgICByZXR1cm4gdGhhdFxuICB9XG5cbiAgaWYgKG9iaikge1xuICAgIGlmICgodHlwZW9mIEFycmF5QnVmZmVyICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICBvYmouYnVmZmVyIGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHx8ICdsZW5ndGgnIGluIG9iaikge1xuICAgICAgaWYgKHR5cGVvZiBvYmoubGVuZ3RoICE9PSAnbnVtYmVyJyB8fCBpc25hbihvYmoubGVuZ3RoKSkge1xuICAgICAgICByZXR1cm4gY3JlYXRlQnVmZmVyKHRoYXQsIDApXG4gICAgICB9XG4gICAgICByZXR1cm4gZnJvbUFycmF5TGlrZSh0aGF0LCBvYmopXG4gICAgfVxuXG4gICAgaWYgKG9iai50eXBlID09PSAnQnVmZmVyJyAmJiBpc0FycmF5KG9iai5kYXRhKSkge1xuICAgICAgcmV0dXJuIGZyb21BcnJheUxpa2UodGhhdCwgb2JqLmRhdGEpXG4gICAgfVxuICB9XG5cbiAgdGhyb3cgbmV3IFR5cGVFcnJvcignRmlyc3QgYXJndW1lbnQgbXVzdCBiZSBhIHN0cmluZywgQnVmZmVyLCBBcnJheUJ1ZmZlciwgQXJyYXksIG9yIGFycmF5LWxpa2Ugb2JqZWN0LicpXG59XG5cbmZ1bmN0aW9uIGNoZWNrZWQgKGxlbmd0aCkge1xuICAvLyBOb3RlOiBjYW5ub3QgdXNlIGBsZW5ndGggPCBrTWF4TGVuZ3RoYCBoZXJlIGJlY2F1c2UgdGhhdCBmYWlscyB3aGVuXG4gIC8vIGxlbmd0aCBpcyBOYU4gKHdoaWNoIGlzIG90aGVyd2lzZSBjb2VyY2VkIHRvIHplcm8uKVxuICBpZiAobGVuZ3RoID49IGtNYXhMZW5ndGgoKSkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdBdHRlbXB0IHRvIGFsbG9jYXRlIEJ1ZmZlciBsYXJnZXIgdGhhbiBtYXhpbXVtICcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICdzaXplOiAweCcgKyBrTWF4TGVuZ3RoKCkudG9TdHJpbmcoMTYpICsgJyBieXRlcycpXG4gIH1cbiAgcmV0dXJuIGxlbmd0aCB8IDBcbn1cblxuZnVuY3Rpb24gU2xvd0J1ZmZlciAobGVuZ3RoKSB7XG4gIGlmICgrbGVuZ3RoICE9IGxlbmd0aCkgeyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIGVxZXFlcVxuICAgIGxlbmd0aCA9IDBcbiAgfVxuICByZXR1cm4gQnVmZmVyLmFsbG9jKCtsZW5ndGgpXG59XG5cbkJ1ZmZlci5pc0J1ZmZlciA9IGZ1bmN0aW9uIGlzQnVmZmVyIChiKSB7XG4gIHJldHVybiAhIShiICE9IG51bGwgJiYgYi5faXNCdWZmZXIpXG59XG5cbkJ1ZmZlci5jb21wYXJlID0gZnVuY3Rpb24gY29tcGFyZSAoYSwgYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihhKSB8fCAhQnVmZmVyLmlzQnVmZmVyKGIpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnRzIG11c3QgYmUgQnVmZmVycycpXG4gIH1cblxuICBpZiAoYSA9PT0gYikgcmV0dXJuIDBcblxuICB2YXIgeCA9IGEubGVuZ3RoXG4gIHZhciB5ID0gYi5sZW5ndGhcblxuICBmb3IgKHZhciBpID0gMCwgbGVuID0gTWF0aC5taW4oeCwgeSk7IGkgPCBsZW47ICsraSkge1xuICAgIGlmIChhW2ldICE9PSBiW2ldKSB7XG4gICAgICB4ID0gYVtpXVxuICAgICAgeSA9IGJbaV1cbiAgICAgIGJyZWFrXG4gICAgfVxuICB9XG5cbiAgaWYgKHggPCB5KSByZXR1cm4gLTFcbiAgaWYgKHkgPCB4KSByZXR1cm4gMVxuICByZXR1cm4gMFxufVxuXG5CdWZmZXIuaXNFbmNvZGluZyA9IGZ1bmN0aW9uIGlzRW5jb2RpbmcgKGVuY29kaW5nKSB7XG4gIHN3aXRjaCAoU3RyaW5nKGVuY29kaW5nKS50b0xvd2VyQ2FzZSgpKSB7XG4gICAgY2FzZSAnaGV4JzpcbiAgICBjYXNlICd1dGY4JzpcbiAgICBjYXNlICd1dGYtOCc6XG4gICAgY2FzZSAnYXNjaWknOlxuICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgY2FzZSAnYmFzZTY0JzpcbiAgICBjYXNlICdyYXcnOlxuICAgIGNhc2UgJ3VjczInOlxuICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICBjYXNlICd1dGYxNmxlJzpcbiAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICByZXR1cm4gdHJ1ZVxuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gZmFsc2VcbiAgfVxufVxuXG5CdWZmZXIuY29uY2F0ID0gZnVuY3Rpb24gY29uY2F0IChsaXN0LCBsZW5ndGgpIHtcbiAgaWYgKCFpc0FycmF5KGxpc3QpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignXCJsaXN0XCIgYXJndW1lbnQgbXVzdCBiZSBhbiBBcnJheSBvZiBCdWZmZXJzJylcbiAgfVxuXG4gIGlmIChsaXN0Lmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBCdWZmZXIuYWxsb2MoMClcbiAgfVxuXG4gIHZhciBpXG4gIGlmIChsZW5ndGggPT09IHVuZGVmaW5lZCkge1xuICAgIGxlbmd0aCA9IDBcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGlzdC5sZW5ndGg7ICsraSkge1xuICAgICAgbGVuZ3RoICs9IGxpc3RbaV0ubGVuZ3RoXG4gICAgfVxuICB9XG5cbiAgdmFyIGJ1ZmZlciA9IEJ1ZmZlci5hbGxvY1Vuc2FmZShsZW5ndGgpXG4gIHZhciBwb3MgPSAwXG4gIGZvciAoaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgKytpKSB7XG4gICAgdmFyIGJ1ZiA9IGxpc3RbaV1cbiAgICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihidWYpKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdcImxpc3RcIiBhcmd1bWVudCBtdXN0IGJlIGFuIEFycmF5IG9mIEJ1ZmZlcnMnKVxuICAgIH1cbiAgICBidWYuY29weShidWZmZXIsIHBvcylcbiAgICBwb3MgKz0gYnVmLmxlbmd0aFxuICB9XG4gIHJldHVybiBidWZmZXJcbn1cblxuZnVuY3Rpb24gYnl0ZUxlbmd0aCAoc3RyaW5nLCBlbmNvZGluZykge1xuICBpZiAoQnVmZmVyLmlzQnVmZmVyKHN0cmluZykpIHtcbiAgICByZXR1cm4gc3RyaW5nLmxlbmd0aFxuICB9XG4gIGlmICh0eXBlb2YgQXJyYXlCdWZmZXIgIT09ICd1bmRlZmluZWQnICYmIHR5cGVvZiBBcnJheUJ1ZmZlci5pc1ZpZXcgPT09ICdmdW5jdGlvbicgJiZcbiAgICAgIChBcnJheUJ1ZmZlci5pc1ZpZXcoc3RyaW5nKSB8fCBzdHJpbmcgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikpIHtcbiAgICByZXR1cm4gc3RyaW5nLmJ5dGVMZW5ndGhcbiAgfVxuICBpZiAodHlwZW9mIHN0cmluZyAhPT0gJ3N0cmluZycpIHtcbiAgICBzdHJpbmcgPSAnJyArIHN0cmluZ1xuICB9XG5cbiAgdmFyIGxlbiA9IHN0cmluZy5sZW5ndGhcbiAgaWYgKGxlbiA9PT0gMCkgcmV0dXJuIDBcblxuICAvLyBVc2UgYSBmb3IgbG9vcCB0byBhdm9pZCByZWN1cnNpb25cbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcbiAgZm9yICg7Oykge1xuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICBjYXNlICdyYXcnOlxuICAgICAgY2FzZSAncmF3cyc6XG4gICAgICAgIHJldHVybiBsZW5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgY2FzZSB1bmRlZmluZWQ6XG4gICAgICAgIHJldHVybiB1dGY4VG9CeXRlcyhzdHJpbmcpLmxlbmd0aFxuICAgICAgY2FzZSAndWNzMic6XG4gICAgICBjYXNlICd1Y3MtMic6XG4gICAgICBjYXNlICd1dGYxNmxlJzpcbiAgICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgICAgcmV0dXJuIGxlbiAqIDJcbiAgICAgIGNhc2UgJ2hleCc6XG4gICAgICAgIHJldHVybiBsZW4gPj4+IDFcbiAgICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgICAgIHJldHVybiBiYXNlNjRUb0J5dGVzKHN0cmluZykubGVuZ3RoXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBpZiAobG93ZXJlZENhc2UpIHJldHVybiB1dGY4VG9CeXRlcyhzdHJpbmcpLmxlbmd0aCAvLyBhc3N1bWUgdXRmOFxuICAgICAgICBlbmNvZGluZyA9ICgnJyArIGVuY29kaW5nKS50b0xvd2VyQ2FzZSgpXG4gICAgICAgIGxvd2VyZWRDYXNlID0gdHJ1ZVxuICAgIH1cbiAgfVxufVxuQnVmZmVyLmJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoXG5cbmZ1bmN0aW9uIHNsb3dUb1N0cmluZyAoZW5jb2RpbmcsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcblxuICAvLyBObyBuZWVkIHRvIHZlcmlmeSB0aGF0IFwidGhpcy5sZW5ndGggPD0gTUFYX1VJTlQzMlwiIHNpbmNlIGl0J3MgYSByZWFkLW9ubHlcbiAgLy8gcHJvcGVydHkgb2YgYSB0eXBlZCBhcnJheS5cblxuICAvLyBUaGlzIGJlaGF2ZXMgbmVpdGhlciBsaWtlIFN0cmluZyBub3IgVWludDhBcnJheSBpbiB0aGF0IHdlIHNldCBzdGFydC9lbmRcbiAgLy8gdG8gdGhlaXIgdXBwZXIvbG93ZXIgYm91bmRzIGlmIHRoZSB2YWx1ZSBwYXNzZWQgaXMgb3V0IG9mIHJhbmdlLlxuICAvLyB1bmRlZmluZWQgaXMgaGFuZGxlZCBzcGVjaWFsbHkgYXMgcGVyIEVDTUEtMjYyIDZ0aCBFZGl0aW9uLFxuICAvLyBTZWN0aW9uIDEzLjMuMy43IFJ1bnRpbWUgU2VtYW50aWNzOiBLZXllZEJpbmRpbmdJbml0aWFsaXphdGlvbi5cbiAgaWYgKHN0YXJ0ID09PSB1bmRlZmluZWQgfHwgc3RhcnQgPCAwKSB7XG4gICAgc3RhcnQgPSAwXG4gIH1cbiAgLy8gUmV0dXJuIGVhcmx5IGlmIHN0YXJ0ID4gdGhpcy5sZW5ndGguIERvbmUgaGVyZSB0byBwcmV2ZW50IHBvdGVudGlhbCB1aW50MzJcbiAgLy8gY29lcmNpb24gZmFpbCBiZWxvdy5cbiAgaWYgKHN0YXJ0ID4gdGhpcy5sZW5ndGgpIHtcbiAgICByZXR1cm4gJydcbiAgfVxuXG4gIGlmIChlbmQgPT09IHVuZGVmaW5lZCB8fCBlbmQgPiB0aGlzLmxlbmd0aCkge1xuICAgIGVuZCA9IHRoaXMubGVuZ3RoXG4gIH1cblxuICBpZiAoZW5kIDw9IDApIHtcbiAgICByZXR1cm4gJydcbiAgfVxuXG4gIC8vIEZvcmNlIGNvZXJzaW9uIHRvIHVpbnQzMi4gVGhpcyB3aWxsIGFsc28gY29lcmNlIGZhbHNleS9OYU4gdmFsdWVzIHRvIDAuXG4gIGVuZCA+Pj49IDBcbiAgc3RhcnQgPj4+PSAwXG5cbiAgaWYgKGVuZCA8PSBzdGFydCkge1xuICAgIHJldHVybiAnJ1xuICB9XG5cbiAgaWYgKCFlbmNvZGluZykgZW5jb2RpbmcgPSAndXRmOCdcblxuICB3aGlsZSAodHJ1ZSkge1xuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgIGNhc2UgJ2hleCc6XG4gICAgICAgIHJldHVybiBoZXhTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICd1dGY4JzpcbiAgICAgIGNhc2UgJ3V0Zi04JzpcbiAgICAgICAgcmV0dXJuIHV0ZjhTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICdhc2NpaSc6XG4gICAgICAgIHJldHVybiBhc2NpaVNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICAgIHJldHVybiBiaW5hcnlTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICdiYXNlNjQnOlxuICAgICAgICByZXR1cm4gYmFzZTY0U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAndWNzMic6XG4gICAgICBjYXNlICd1Y3MtMic6XG4gICAgICBjYXNlICd1dGYxNmxlJzpcbiAgICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgICAgcmV0dXJuIHV0ZjE2bGVTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBpZiAobG93ZXJlZENhc2UpIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Vua25vd24gZW5jb2Rpbmc6ICcgKyBlbmNvZGluZylcbiAgICAgICAgZW5jb2RpbmcgPSAoZW5jb2RpbmcgKyAnJykudG9Mb3dlckNhc2UoKVxuICAgICAgICBsb3dlcmVkQ2FzZSA9IHRydWVcbiAgICB9XG4gIH1cbn1cblxuLy8gVGhlIHByb3BlcnR5IGlzIHVzZWQgYnkgYEJ1ZmZlci5pc0J1ZmZlcmAgYW5kIGBpcy1idWZmZXJgIChpbiBTYWZhcmkgNS03KSB0byBkZXRlY3Rcbi8vIEJ1ZmZlciBpbnN0YW5jZXMuXG5CdWZmZXIucHJvdG90eXBlLl9pc0J1ZmZlciA9IHRydWVcblxuZnVuY3Rpb24gc3dhcCAoYiwgbiwgbSkge1xuICB2YXIgaSA9IGJbbl1cbiAgYltuXSA9IGJbbV1cbiAgYlttXSA9IGlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5zd2FwMTYgPSBmdW5jdGlvbiBzd2FwMTYgKCkge1xuICB2YXIgbGVuID0gdGhpcy5sZW5ndGhcbiAgaWYgKGxlbiAlIDIgIT09IDApIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignQnVmZmVyIHNpemUgbXVzdCBiZSBhIG11bHRpcGxlIG9mIDE2LWJpdHMnKVxuICB9XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuOyBpICs9IDIpIHtcbiAgICBzd2FwKHRoaXMsIGksIGkgKyAxKVxuICB9XG4gIHJldHVybiB0aGlzXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuc3dhcDMyID0gZnVuY3Rpb24gc3dhcDMyICgpIHtcbiAgdmFyIGxlbiA9IHRoaXMubGVuZ3RoXG4gIGlmIChsZW4gJSA0ICE9PSAwKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ0J1ZmZlciBzaXplIG11c3QgYmUgYSBtdWx0aXBsZSBvZiAzMi1iaXRzJylcbiAgfVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbjsgaSArPSA0KSB7XG4gICAgc3dhcCh0aGlzLCBpLCBpICsgMylcbiAgICBzd2FwKHRoaXMsIGkgKyAxLCBpICsgMilcbiAgfVxuICByZXR1cm4gdGhpc1xufVxuXG5CdWZmZXIucHJvdG90eXBlLnRvU3RyaW5nID0gZnVuY3Rpb24gdG9TdHJpbmcgKCkge1xuICB2YXIgbGVuZ3RoID0gdGhpcy5sZW5ndGggfCAwXG4gIGlmIChsZW5ndGggPT09IDApIHJldHVybiAnJ1xuICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHV0ZjhTbGljZSh0aGlzLCAwLCBsZW5ndGgpXG4gIHJldHVybiBzbG93VG9TdHJpbmcuYXBwbHkodGhpcywgYXJndW1lbnRzKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLmVxdWFscyA9IGZ1bmN0aW9uIGVxdWFscyAoYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihiKSkgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnQgbXVzdCBiZSBhIEJ1ZmZlcicpXG4gIGlmICh0aGlzID09PSBiKSByZXR1cm4gdHJ1ZVxuICByZXR1cm4gQnVmZmVyLmNvbXBhcmUodGhpcywgYikgPT09IDBcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5pbnNwZWN0ID0gZnVuY3Rpb24gaW5zcGVjdCAoKSB7XG4gIHZhciBzdHIgPSAnJ1xuICB2YXIgbWF4ID0gZXhwb3J0cy5JTlNQRUNUX01BWF9CWVRFU1xuICBpZiAodGhpcy5sZW5ndGggPiAwKSB7XG4gICAgc3RyID0gdGhpcy50b1N0cmluZygnaGV4JywgMCwgbWF4KS5tYXRjaCgvLnsyfS9nKS5qb2luKCcgJylcbiAgICBpZiAodGhpcy5sZW5ndGggPiBtYXgpIHN0ciArPSAnIC4uLiAnXG4gIH1cbiAgcmV0dXJuICc8QnVmZmVyICcgKyBzdHIgKyAnPidcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5jb21wYXJlID0gZnVuY3Rpb24gY29tcGFyZSAodGFyZ2V0LCBzdGFydCwgZW5kLCB0aGlzU3RhcnQsIHRoaXNFbmQpIHtcbiAgaWYgKCFCdWZmZXIuaXNCdWZmZXIodGFyZ2V0KSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0FyZ3VtZW50IG11c3QgYmUgYSBCdWZmZXInKVxuICB9XG5cbiAgaWYgKHN0YXJ0ID09PSB1bmRlZmluZWQpIHtcbiAgICBzdGFydCA9IDBcbiAgfVxuICBpZiAoZW5kID09PSB1bmRlZmluZWQpIHtcbiAgICBlbmQgPSB0YXJnZXQgPyB0YXJnZXQubGVuZ3RoIDogMFxuICB9XG4gIGlmICh0aGlzU3RhcnQgPT09IHVuZGVmaW5lZCkge1xuICAgIHRoaXNTdGFydCA9IDBcbiAgfVxuICBpZiAodGhpc0VuZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgdGhpc0VuZCA9IHRoaXMubGVuZ3RoXG4gIH1cblxuICBpZiAoc3RhcnQgPCAwIHx8IGVuZCA+IHRhcmdldC5sZW5ndGggfHwgdGhpc1N0YXJ0IDwgMCB8fCB0aGlzRW5kID4gdGhpcy5sZW5ndGgpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignb3V0IG9mIHJhbmdlIGluZGV4JylcbiAgfVxuXG4gIGlmICh0aGlzU3RhcnQgPj0gdGhpc0VuZCAmJiBzdGFydCA+PSBlbmQpIHtcbiAgICByZXR1cm4gMFxuICB9XG4gIGlmICh0aGlzU3RhcnQgPj0gdGhpc0VuZCkge1xuICAgIHJldHVybiAtMVxuICB9XG4gIGlmIChzdGFydCA+PSBlbmQpIHtcbiAgICByZXR1cm4gMVxuICB9XG5cbiAgc3RhcnQgPj4+PSAwXG4gIGVuZCA+Pj49IDBcbiAgdGhpc1N0YXJ0ID4+Pj0gMFxuICB0aGlzRW5kID4+Pj0gMFxuXG4gIGlmICh0aGlzID09PSB0YXJnZXQpIHJldHVybiAwXG5cbiAgdmFyIHggPSB0aGlzRW5kIC0gdGhpc1N0YXJ0XG4gIHZhciB5ID0gZW5kIC0gc3RhcnRcbiAgdmFyIGxlbiA9IE1hdGgubWluKHgsIHkpXG5cbiAgdmFyIHRoaXNDb3B5ID0gdGhpcy5zbGljZSh0aGlzU3RhcnQsIHRoaXNFbmQpXG4gIHZhciB0YXJnZXRDb3B5ID0gdGFyZ2V0LnNsaWNlKHN0YXJ0LCBlbmQpXG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW47ICsraSkge1xuICAgIGlmICh0aGlzQ29weVtpXSAhPT0gdGFyZ2V0Q29weVtpXSkge1xuICAgICAgeCA9IHRoaXNDb3B5W2ldXG4gICAgICB5ID0gdGFyZ2V0Q29weVtpXVxuICAgICAgYnJlYWtcbiAgICB9XG4gIH1cblxuICBpZiAoeCA8IHkpIHJldHVybiAtMVxuICBpZiAoeSA8IHgpIHJldHVybiAxXG4gIHJldHVybiAwXG59XG5cbmZ1bmN0aW9uIGFycmF5SW5kZXhPZiAoYXJyLCB2YWwsIGJ5dGVPZmZzZXQsIGVuY29kaW5nKSB7XG4gIHZhciBpbmRleFNpemUgPSAxXG4gIHZhciBhcnJMZW5ndGggPSBhcnIubGVuZ3RoXG4gIHZhciB2YWxMZW5ndGggPSB2YWwubGVuZ3RoXG5cbiAgaWYgKGVuY29kaW5nICE9PSB1bmRlZmluZWQpIHtcbiAgICBlbmNvZGluZyA9IFN0cmluZyhlbmNvZGluZykudG9Mb3dlckNhc2UoKVxuICAgIGlmIChlbmNvZGluZyA9PT0gJ3VjczInIHx8IGVuY29kaW5nID09PSAndWNzLTInIHx8XG4gICAgICAgIGVuY29kaW5nID09PSAndXRmMTZsZScgfHwgZW5jb2RpbmcgPT09ICd1dGYtMTZsZScpIHtcbiAgICAgIGlmIChhcnIubGVuZ3RoIDwgMiB8fCB2YWwubGVuZ3RoIDwgMikge1xuICAgICAgICByZXR1cm4gLTFcbiAgICAgIH1cbiAgICAgIGluZGV4U2l6ZSA9IDJcbiAgICAgIGFyckxlbmd0aCAvPSAyXG4gICAgICB2YWxMZW5ndGggLz0gMlxuICAgICAgYnl0ZU9mZnNldCAvPSAyXG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gcmVhZCAoYnVmLCBpKSB7XG4gICAgaWYgKGluZGV4U2l6ZSA9PT0gMSkge1xuICAgICAgcmV0dXJuIGJ1ZltpXVxuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gYnVmLnJlYWRVSW50MTZCRShpICogaW5kZXhTaXplKVxuICAgIH1cbiAgfVxuXG4gIHZhciBmb3VuZEluZGV4ID0gLTFcbiAgZm9yICh2YXIgaSA9IGJ5dGVPZmZzZXQ7IGkgPCBhcnJMZW5ndGg7ICsraSkge1xuICAgIGlmIChyZWFkKGFyciwgaSkgPT09IHJlYWQodmFsLCBmb3VuZEluZGV4ID09PSAtMSA/IDAgOiBpIC0gZm91bmRJbmRleCkpIHtcbiAgICAgIGlmIChmb3VuZEluZGV4ID09PSAtMSkgZm91bmRJbmRleCA9IGlcbiAgICAgIGlmIChpIC0gZm91bmRJbmRleCArIDEgPT09IHZhbExlbmd0aCkgcmV0dXJuIGZvdW5kSW5kZXggKiBpbmRleFNpemVcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKGZvdW5kSW5kZXggIT09IC0xKSBpIC09IGkgLSBmb3VuZEluZGV4XG4gICAgICBmb3VuZEluZGV4ID0gLTFcbiAgICB9XG4gIH1cblxuICByZXR1cm4gLTFcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5pbmRleE9mID0gZnVuY3Rpb24gaW5kZXhPZiAodmFsLCBieXRlT2Zmc2V0LCBlbmNvZGluZykge1xuICBpZiAodHlwZW9mIGJ5dGVPZmZzZXQgPT09ICdzdHJpbmcnKSB7XG4gICAgZW5jb2RpbmcgPSBieXRlT2Zmc2V0XG4gICAgYnl0ZU9mZnNldCA9IDBcbiAgfSBlbHNlIGlmIChieXRlT2Zmc2V0ID4gMHg3ZmZmZmZmZikge1xuICAgIGJ5dGVPZmZzZXQgPSAweDdmZmZmZmZmXG4gIH0gZWxzZSBpZiAoYnl0ZU9mZnNldCA8IC0weDgwMDAwMDAwKSB7XG4gICAgYnl0ZU9mZnNldCA9IC0weDgwMDAwMDAwXG4gIH1cbiAgYnl0ZU9mZnNldCA+Pj0gMFxuXG4gIGlmICh0aGlzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIC0xXG4gIGlmIChieXRlT2Zmc2V0ID49IHRoaXMubGVuZ3RoKSByZXR1cm4gLTFcblxuICAvLyBOZWdhdGl2ZSBvZmZzZXRzIHN0YXJ0IGZyb20gdGhlIGVuZCBvZiB0aGUgYnVmZmVyXG4gIGlmIChieXRlT2Zmc2V0IDwgMCkgYnl0ZU9mZnNldCA9IE1hdGgubWF4KHRoaXMubGVuZ3RoICsgYnl0ZU9mZnNldCwgMClcblxuICBpZiAodHlwZW9mIHZhbCA9PT0gJ3N0cmluZycpIHtcbiAgICB2YWwgPSBCdWZmZXIuZnJvbSh2YWwsIGVuY29kaW5nKVxuICB9XG5cbiAgaWYgKEJ1ZmZlci5pc0J1ZmZlcih2YWwpKSB7XG4gICAgLy8gc3BlY2lhbCBjYXNlOiBsb29raW5nIGZvciBlbXB0eSBzdHJpbmcvYnVmZmVyIGFsd2F5cyBmYWlsc1xuICAgIGlmICh2YWwubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gLTFcbiAgICB9XG4gICAgcmV0dXJuIGFycmF5SW5kZXhPZih0aGlzLCB2YWwsIGJ5dGVPZmZzZXQsIGVuY29kaW5nKVxuICB9XG4gIGlmICh0eXBlb2YgdmFsID09PSAnbnVtYmVyJykge1xuICAgIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCAmJiBVaW50OEFycmF5LnByb3RvdHlwZS5pbmRleE9mID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICByZXR1cm4gVWludDhBcnJheS5wcm90b3R5cGUuaW5kZXhPZi5jYWxsKHRoaXMsIHZhbCwgYnl0ZU9mZnNldClcbiAgICB9XG4gICAgcmV0dXJuIGFycmF5SW5kZXhPZih0aGlzLCBbIHZhbCBdLCBieXRlT2Zmc2V0LCBlbmNvZGluZylcbiAgfVxuXG4gIHRocm93IG5ldyBUeXBlRXJyb3IoJ3ZhbCBtdXN0IGJlIHN0cmluZywgbnVtYmVyIG9yIEJ1ZmZlcicpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuaW5jbHVkZXMgPSBmdW5jdGlvbiBpbmNsdWRlcyAodmFsLCBieXRlT2Zmc2V0LCBlbmNvZGluZykge1xuICByZXR1cm4gdGhpcy5pbmRleE9mKHZhbCwgYnl0ZU9mZnNldCwgZW5jb2RpbmcpICE9PSAtMVxufVxuXG5mdW5jdGlvbiBoZXhXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIG9mZnNldCA9IE51bWJlcihvZmZzZXQpIHx8IDBcbiAgdmFyIHJlbWFpbmluZyA9IGJ1Zi5sZW5ndGggLSBvZmZzZXRcbiAgaWYgKCFsZW5ndGgpIHtcbiAgICBsZW5ndGggPSByZW1haW5pbmdcbiAgfSBlbHNlIHtcbiAgICBsZW5ndGggPSBOdW1iZXIobGVuZ3RoKVxuICAgIGlmIChsZW5ndGggPiByZW1haW5pbmcpIHtcbiAgICAgIGxlbmd0aCA9IHJlbWFpbmluZ1xuICAgIH1cbiAgfVxuXG4gIC8vIG11c3QgYmUgYW4gZXZlbiBudW1iZXIgb2YgZGlnaXRzXG4gIHZhciBzdHJMZW4gPSBzdHJpbmcubGVuZ3RoXG4gIGlmIChzdHJMZW4gJSAyICE9PSAwKSB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgaGV4IHN0cmluZycpXG5cbiAgaWYgKGxlbmd0aCA+IHN0ckxlbiAvIDIpIHtcbiAgICBsZW5ndGggPSBzdHJMZW4gLyAyXG4gIH1cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7ICsraSkge1xuICAgIHZhciBwYXJzZWQgPSBwYXJzZUludChzdHJpbmcuc3Vic3RyKGkgKiAyLCAyKSwgMTYpXG4gICAgaWYgKGlzTmFOKHBhcnNlZCkpIHJldHVybiBpXG4gICAgYnVmW29mZnNldCArIGldID0gcGFyc2VkXG4gIH1cbiAgcmV0dXJuIGlcbn1cblxuZnVuY3Rpb24gdXRmOFdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIodXRmOFRvQnl0ZXMoc3RyaW5nLCBidWYubGVuZ3RoIC0gb2Zmc2V0KSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gYXNjaWlXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKGFzY2lpVG9CeXRlcyhzdHJpbmcpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiBiaW5hcnlXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBhc2NpaVdyaXRlKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gYmFzZTY0V3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcihiYXNlNjRUb0J5dGVzKHN0cmluZyksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIHVjczJXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKHV0ZjE2bGVUb0J5dGVzKHN0cmluZywgYnVmLmxlbmd0aCAtIG9mZnNldCksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGUgPSBmdW5jdGlvbiB3cml0ZSAoc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCwgZW5jb2RpbmcpIHtcbiAgLy8gQnVmZmVyI3dyaXRlKHN0cmluZylcbiAgaWYgKG9mZnNldCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgZW5jb2RpbmcgPSAndXRmOCdcbiAgICBsZW5ndGggPSB0aGlzLmxlbmd0aFxuICAgIG9mZnNldCA9IDBcbiAgLy8gQnVmZmVyI3dyaXRlKHN0cmluZywgZW5jb2RpbmcpXG4gIH0gZWxzZSBpZiAobGVuZ3RoID09PSB1bmRlZmluZWQgJiYgdHlwZW9mIG9mZnNldCA9PT0gJ3N0cmluZycpIHtcbiAgICBlbmNvZGluZyA9IG9mZnNldFxuICAgIGxlbmd0aCA9IHRoaXMubGVuZ3RoXG4gICAgb2Zmc2V0ID0gMFxuICAvLyBCdWZmZXIjd3JpdGUoc3RyaW5nLCBvZmZzZXRbLCBsZW5ndGhdWywgZW5jb2RpbmddKVxuICB9IGVsc2UgaWYgKGlzRmluaXRlKG9mZnNldCkpIHtcbiAgICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gICAgaWYgKGlzRmluaXRlKGxlbmd0aCkpIHtcbiAgICAgIGxlbmd0aCA9IGxlbmd0aCB8IDBcbiAgICAgIGlmIChlbmNvZGluZyA9PT0gdW5kZWZpbmVkKSBlbmNvZGluZyA9ICd1dGY4J1xuICAgIH0gZWxzZSB7XG4gICAgICBlbmNvZGluZyA9IGxlbmd0aFxuICAgICAgbGVuZ3RoID0gdW5kZWZpbmVkXG4gICAgfVxuICAvLyBsZWdhY3kgd3JpdGUoc3RyaW5nLCBlbmNvZGluZywgb2Zmc2V0LCBsZW5ndGgpIC0gcmVtb3ZlIGluIHYwLjEzXG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgJ0J1ZmZlci53cml0ZShzdHJpbmcsIGVuY29kaW5nLCBvZmZzZXRbLCBsZW5ndGhdKSBpcyBubyBsb25nZXIgc3VwcG9ydGVkJ1xuICAgIClcbiAgfVxuXG4gIHZhciByZW1haW5pbmcgPSB0aGlzLmxlbmd0aCAtIG9mZnNldFxuICBpZiAobGVuZ3RoID09PSB1bmRlZmluZWQgfHwgbGVuZ3RoID4gcmVtYWluaW5nKSBsZW5ndGggPSByZW1haW5pbmdcblxuICBpZiAoKHN0cmluZy5sZW5ndGggPiAwICYmIChsZW5ndGggPCAwIHx8IG9mZnNldCA8IDApKSB8fCBvZmZzZXQgPiB0aGlzLmxlbmd0aCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdBdHRlbXB0IHRvIHdyaXRlIG91dHNpZGUgYnVmZmVyIGJvdW5kcycpXG4gIH1cblxuICBpZiAoIWVuY29kaW5nKSBlbmNvZGluZyA9ICd1dGY4J1xuXG4gIHZhciBsb3dlcmVkQ2FzZSA9IGZhbHNlXG4gIGZvciAoOzspIHtcbiAgICBzd2l0Y2ggKGVuY29kaW5nKSB7XG4gICAgICBjYXNlICdoZXgnOlxuICAgICAgICByZXR1cm4gaGV4V3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAndXRmOCc6XG4gICAgICBjYXNlICd1dGYtOCc6XG4gICAgICAgIHJldHVybiB1dGY4V3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAnYXNjaWknOlxuICAgICAgICByZXR1cm4gYXNjaWlXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICdiaW5hcnknOlxuICAgICAgICByZXR1cm4gYmluYXJ5V3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgLy8gV2FybmluZzogbWF4TGVuZ3RoIG5vdCB0YWtlbiBpbnRvIGFjY291bnQgaW4gYmFzZTY0V3JpdGVcbiAgICAgICAgcmV0dXJuIGJhc2U2NFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ3VjczInOlxuICAgICAgY2FzZSAndWNzLTInOlxuICAgICAgY2FzZSAndXRmMTZsZSc6XG4gICAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICAgIHJldHVybiB1Y3MyV3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGxvd2VyZWRDYXNlKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdVbmtub3duIGVuY29kaW5nOiAnICsgZW5jb2RpbmcpXG4gICAgICAgIGVuY29kaW5nID0gKCcnICsgZW5jb2RpbmcpLnRvTG93ZXJDYXNlKClcbiAgICAgICAgbG93ZXJlZENhc2UgPSB0cnVlXG4gICAgfVxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUudG9KU09OID0gZnVuY3Rpb24gdG9KU09OICgpIHtcbiAgcmV0dXJuIHtcbiAgICB0eXBlOiAnQnVmZmVyJyxcbiAgICBkYXRhOiBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbCh0aGlzLl9hcnIgfHwgdGhpcywgMClcbiAgfVxufVxuXG5mdW5jdGlvbiBiYXNlNjRTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIGlmIChzdGFydCA9PT0gMCAmJiBlbmQgPT09IGJ1Zi5sZW5ndGgpIHtcbiAgICByZXR1cm4gYmFzZTY0LmZyb21CeXRlQXJyYXkoYnVmKVxuICB9IGVsc2Uge1xuICAgIHJldHVybiBiYXNlNjQuZnJvbUJ5dGVBcnJheShidWYuc2xpY2Uoc3RhcnQsIGVuZCkpXG4gIH1cbn1cblxuZnVuY3Rpb24gdXRmOFNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgZW5kID0gTWF0aC5taW4oYnVmLmxlbmd0aCwgZW5kKVxuICB2YXIgcmVzID0gW11cblxuICB2YXIgaSA9IHN0YXJ0XG4gIHdoaWxlIChpIDwgZW5kKSB7XG4gICAgdmFyIGZpcnN0Qnl0ZSA9IGJ1ZltpXVxuICAgIHZhciBjb2RlUG9pbnQgPSBudWxsXG4gICAgdmFyIGJ5dGVzUGVyU2VxdWVuY2UgPSAoZmlyc3RCeXRlID4gMHhFRikgPyA0XG4gICAgICA6IChmaXJzdEJ5dGUgPiAweERGKSA/IDNcbiAgICAgIDogKGZpcnN0Qnl0ZSA+IDB4QkYpID8gMlxuICAgICAgOiAxXG5cbiAgICBpZiAoaSArIGJ5dGVzUGVyU2VxdWVuY2UgPD0gZW5kKSB7XG4gICAgICB2YXIgc2Vjb25kQnl0ZSwgdGhpcmRCeXRlLCBmb3VydGhCeXRlLCB0ZW1wQ29kZVBvaW50XG5cbiAgICAgIHN3aXRjaCAoYnl0ZXNQZXJTZXF1ZW5jZSkge1xuICAgICAgICBjYXNlIDE6XG4gICAgICAgICAgaWYgKGZpcnN0Qnl0ZSA8IDB4ODApIHtcbiAgICAgICAgICAgIGNvZGVQb2ludCA9IGZpcnN0Qnl0ZVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgc2Vjb25kQnl0ZSA9IGJ1ZltpICsgMV1cbiAgICAgICAgICBpZiAoKHNlY29uZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCkge1xuICAgICAgICAgICAgdGVtcENvZGVQb2ludCA9IChmaXJzdEJ5dGUgJiAweDFGKSA8PCAweDYgfCAoc2Vjb25kQnl0ZSAmIDB4M0YpXG4gICAgICAgICAgICBpZiAodGVtcENvZGVQb2ludCA+IDB4N0YpIHtcbiAgICAgICAgICAgICAgY29kZVBvaW50ID0gdGVtcENvZGVQb2ludFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDM6XG4gICAgICAgICAgc2Vjb25kQnl0ZSA9IGJ1ZltpICsgMV1cbiAgICAgICAgICB0aGlyZEJ5dGUgPSBidWZbaSArIDJdXG4gICAgICAgICAgaWYgKChzZWNvbmRCeXRlICYgMHhDMCkgPT09IDB4ODAgJiYgKHRoaXJkQnl0ZSAmIDB4QzApID09PSAweDgwKSB7XG4gICAgICAgICAgICB0ZW1wQ29kZVBvaW50ID0gKGZpcnN0Qnl0ZSAmIDB4RikgPDwgMHhDIHwgKHNlY29uZEJ5dGUgJiAweDNGKSA8PCAweDYgfCAodGhpcmRCeXRlICYgMHgzRilcbiAgICAgICAgICAgIGlmICh0ZW1wQ29kZVBvaW50ID4gMHg3RkYgJiYgKHRlbXBDb2RlUG9pbnQgPCAweEQ4MDAgfHwgdGVtcENvZGVQb2ludCA+IDB4REZGRikpIHtcbiAgICAgICAgICAgICAgY29kZVBvaW50ID0gdGVtcENvZGVQb2ludFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDQ6XG4gICAgICAgICAgc2Vjb25kQnl0ZSA9IGJ1ZltpICsgMV1cbiAgICAgICAgICB0aGlyZEJ5dGUgPSBidWZbaSArIDJdXG4gICAgICAgICAgZm91cnRoQnl0ZSA9IGJ1ZltpICsgM11cbiAgICAgICAgICBpZiAoKHNlY29uZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCAmJiAodGhpcmRCeXRlICYgMHhDMCkgPT09IDB4ODAgJiYgKGZvdXJ0aEJ5dGUgJiAweEMwKSA9PT0gMHg4MCkge1xuICAgICAgICAgICAgdGVtcENvZGVQb2ludCA9IChmaXJzdEJ5dGUgJiAweEYpIDw8IDB4MTIgfCAoc2Vjb25kQnl0ZSAmIDB4M0YpIDw8IDB4QyB8ICh0aGlyZEJ5dGUgJiAweDNGKSA8PCAweDYgfCAoZm91cnRoQnl0ZSAmIDB4M0YpXG4gICAgICAgICAgICBpZiAodGVtcENvZGVQb2ludCA+IDB4RkZGRiAmJiB0ZW1wQ29kZVBvaW50IDwgMHgxMTAwMDApIHtcbiAgICAgICAgICAgICAgY29kZVBvaW50ID0gdGVtcENvZGVQb2ludFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoY29kZVBvaW50ID09PSBudWxsKSB7XG4gICAgICAvLyB3ZSBkaWQgbm90IGdlbmVyYXRlIGEgdmFsaWQgY29kZVBvaW50IHNvIGluc2VydCBhXG4gICAgICAvLyByZXBsYWNlbWVudCBjaGFyIChVK0ZGRkQpIGFuZCBhZHZhbmNlIG9ubHkgMSBieXRlXG4gICAgICBjb2RlUG9pbnQgPSAweEZGRkRcbiAgICAgIGJ5dGVzUGVyU2VxdWVuY2UgPSAxXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPiAweEZGRkYpIHtcbiAgICAgIC8vIGVuY29kZSB0byB1dGYxNiAoc3Vycm9nYXRlIHBhaXIgZGFuY2UpXG4gICAgICBjb2RlUG9pbnQgLT0gMHgxMDAwMFxuICAgICAgcmVzLnB1c2goY29kZVBvaW50ID4+PiAxMCAmIDB4M0ZGIHwgMHhEODAwKVxuICAgICAgY29kZVBvaW50ID0gMHhEQzAwIHwgY29kZVBvaW50ICYgMHgzRkZcbiAgICB9XG5cbiAgICByZXMucHVzaChjb2RlUG9pbnQpXG4gICAgaSArPSBieXRlc1BlclNlcXVlbmNlXG4gIH1cblxuICByZXR1cm4gZGVjb2RlQ29kZVBvaW50c0FycmF5KHJlcylcbn1cblxuLy8gQmFzZWQgb24gaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMjI3NDcyNzIvNjgwNzQyLCB0aGUgYnJvd3NlciB3aXRoXG4vLyB0aGUgbG93ZXN0IGxpbWl0IGlzIENocm9tZSwgd2l0aCAweDEwMDAwIGFyZ3MuXG4vLyBXZSBnbyAxIG1hZ25pdHVkZSBsZXNzLCBmb3Igc2FmZXR5XG52YXIgTUFYX0FSR1VNRU5UU19MRU5HVEggPSAweDEwMDBcblxuZnVuY3Rpb24gZGVjb2RlQ29kZVBvaW50c0FycmF5IChjb2RlUG9pbnRzKSB7XG4gIHZhciBsZW4gPSBjb2RlUG9pbnRzLmxlbmd0aFxuICBpZiAobGVuIDw9IE1BWF9BUkdVTUVOVFNfTEVOR1RIKSB7XG4gICAgcmV0dXJuIFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkoU3RyaW5nLCBjb2RlUG9pbnRzKSAvLyBhdm9pZCBleHRyYSBzbGljZSgpXG4gIH1cblxuICAvLyBEZWNvZGUgaW4gY2h1bmtzIHRvIGF2b2lkIFwiY2FsbCBzdGFjayBzaXplIGV4Y2VlZGVkXCIuXG4gIHZhciByZXMgPSAnJ1xuICB2YXIgaSA9IDBcbiAgd2hpbGUgKGkgPCBsZW4pIHtcbiAgICByZXMgKz0gU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShcbiAgICAgIFN0cmluZyxcbiAgICAgIGNvZGVQb2ludHMuc2xpY2UoaSwgaSArPSBNQVhfQVJHVU1FTlRTX0xFTkdUSClcbiAgICApXG4gIH1cbiAgcmV0dXJuIHJlc1xufVxuXG5mdW5jdGlvbiBhc2NpaVNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIHJldCA9ICcnXG4gIGVuZCA9IE1hdGgubWluKGJ1Zi5sZW5ndGgsIGVuZClcblxuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7ICsraSkge1xuICAgIHJldCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJ1ZltpXSAmIDB4N0YpXG4gIH1cbiAgcmV0dXJuIHJldFxufVxuXG5mdW5jdGlvbiBiaW5hcnlTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciByZXQgPSAnJ1xuICBlbmQgPSBNYXRoLm1pbihidWYubGVuZ3RoLCBlbmQpXG5cbiAgZm9yICh2YXIgaSA9IHN0YXJ0OyBpIDwgZW5kOyArK2kpIHtcbiAgICByZXQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShidWZbaV0pXG4gIH1cbiAgcmV0dXJuIHJldFxufVxuXG5mdW5jdGlvbiBoZXhTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciBsZW4gPSBidWYubGVuZ3RoXG5cbiAgaWYgKCFzdGFydCB8fCBzdGFydCA8IDApIHN0YXJ0ID0gMFxuICBpZiAoIWVuZCB8fCBlbmQgPCAwIHx8IGVuZCA+IGxlbikgZW5kID0gbGVuXG5cbiAgdmFyIG91dCA9ICcnXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgKytpKSB7XG4gICAgb3V0ICs9IHRvSGV4KGJ1ZltpXSlcbiAgfVxuICByZXR1cm4gb3V0XG59XG5cbmZ1bmN0aW9uIHV0ZjE2bGVTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciBieXRlcyA9IGJ1Zi5zbGljZShzdGFydCwgZW5kKVxuICB2YXIgcmVzID0gJydcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBieXRlcy5sZW5ndGg7IGkgKz0gMikge1xuICAgIHJlcyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJ5dGVzW2ldICsgYnl0ZXNbaSArIDFdICogMjU2KVxuICB9XG4gIHJldHVybiByZXNcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5zbGljZSA9IGZ1bmN0aW9uIHNsaWNlIChzdGFydCwgZW5kKSB7XG4gIHZhciBsZW4gPSB0aGlzLmxlbmd0aFxuICBzdGFydCA9IH5+c3RhcnRcbiAgZW5kID0gZW5kID09PSB1bmRlZmluZWQgPyBsZW4gOiB+fmVuZFxuXG4gIGlmIChzdGFydCA8IDApIHtcbiAgICBzdGFydCArPSBsZW5cbiAgICBpZiAoc3RhcnQgPCAwKSBzdGFydCA9IDBcbiAgfSBlbHNlIGlmIChzdGFydCA+IGxlbikge1xuICAgIHN0YXJ0ID0gbGVuXG4gIH1cblxuICBpZiAoZW5kIDwgMCkge1xuICAgIGVuZCArPSBsZW5cbiAgICBpZiAoZW5kIDwgMCkgZW5kID0gMFxuICB9IGVsc2UgaWYgKGVuZCA+IGxlbikge1xuICAgIGVuZCA9IGxlblxuICB9XG5cbiAgaWYgKGVuZCA8IHN0YXJ0KSBlbmQgPSBzdGFydFxuXG4gIHZhciBuZXdCdWZcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgbmV3QnVmID0gdGhpcy5zdWJhcnJheShzdGFydCwgZW5kKVxuICAgIG5ld0J1Zi5fX3Byb3RvX18gPSBCdWZmZXIucHJvdG90eXBlXG4gIH0gZWxzZSB7XG4gICAgdmFyIHNsaWNlTGVuID0gZW5kIC0gc3RhcnRcbiAgICBuZXdCdWYgPSBuZXcgQnVmZmVyKHNsaWNlTGVuLCB1bmRlZmluZWQpXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzbGljZUxlbjsgKytpKSB7XG4gICAgICBuZXdCdWZbaV0gPSB0aGlzW2kgKyBzdGFydF1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gbmV3QnVmXG59XG5cbi8qXG4gKiBOZWVkIHRvIG1ha2Ugc3VyZSB0aGF0IGJ1ZmZlciBpc24ndCB0cnlpbmcgdG8gd3JpdGUgb3V0IG9mIGJvdW5kcy5cbiAqL1xuZnVuY3Rpb24gY2hlY2tPZmZzZXQgKG9mZnNldCwgZXh0LCBsZW5ndGgpIHtcbiAgaWYgKChvZmZzZXQgJSAxKSAhPT0gMCB8fCBvZmZzZXQgPCAwKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignb2Zmc2V0IGlzIG5vdCB1aW50JylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGxlbmd0aCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ1RyeWluZyB0byBhY2Nlc3MgYmV5b25kIGJ1ZmZlciBsZW5ndGgnKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50TEUgPSBmdW5jdGlvbiByZWFkVUludExFIChvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgYnl0ZUxlbmd0aCwgdGhpcy5sZW5ndGgpXG5cbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0XVxuICB2YXIgbXVsID0gMVxuICB2YXIgaSA9IDBcbiAgd2hpbGUgKCsraSA8IGJ5dGVMZW5ndGggJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyBpXSAqIG11bFxuICB9XG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50QkUgPSBmdW5jdGlvbiByZWFkVUludEJFIChvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuICB9XG5cbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0ICsgLS1ieXRlTGVuZ3RoXVxuICB2YXIgbXVsID0gMVxuICB3aGlsZSAoYnl0ZUxlbmd0aCA+IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyAtLWJ5dGVMZW5ndGhdICogbXVsXG4gIH1cblxuICByZXR1cm4gdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQ4ID0gZnVuY3Rpb24gcmVhZFVJbnQ4IChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMSwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiB0aGlzW29mZnNldF1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDE2TEUgPSBmdW5jdGlvbiByZWFkVUludDE2TEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIHRoaXNbb2Zmc2V0XSB8ICh0aGlzW29mZnNldCArIDFdIDw8IDgpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQxNkJFID0gZnVuY3Rpb24gcmVhZFVJbnQxNkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiAodGhpc1tvZmZzZXRdIDw8IDgpIHwgdGhpc1tvZmZzZXQgKyAxXVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MzJMRSA9IGZ1bmN0aW9uIHJlYWRVSW50MzJMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuXG4gIHJldHVybiAoKHRoaXNbb2Zmc2V0XSkgfFxuICAgICAgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOCkgfFxuICAgICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgMTYpKSArXG4gICAgICAodGhpc1tvZmZzZXQgKyAzXSAqIDB4MTAwMDAwMClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDMyQkUgPSBmdW5jdGlvbiByZWFkVUludDMyQkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSAqIDB4MTAwMDAwMCkgK1xuICAgICgodGhpc1tvZmZzZXQgKyAxXSA8PCAxNikgfFxuICAgICh0aGlzW29mZnNldCArIDJdIDw8IDgpIHxcbiAgICB0aGlzW29mZnNldCArIDNdKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnRMRSA9IGZ1bmN0aW9uIHJlYWRJbnRMRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldF1cbiAgdmFyIG11bCA9IDFcbiAgdmFyIGkgPSAwXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgaV0gKiBtdWxcbiAgfVxuICBtdWwgKj0gMHg4MFxuXG4gIGlmICh2YWwgPj0gbXVsKSB2YWwgLT0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpXG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnRCRSA9IGZ1bmN0aW9uIHJlYWRJbnRCRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuXG4gIHZhciBpID0gYnl0ZUxlbmd0aFxuICB2YXIgbXVsID0gMVxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXQgKyAtLWldXG4gIHdoaWxlIChpID4gMCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIC0taV0gKiBtdWxcbiAgfVxuICBtdWwgKj0gMHg4MFxuXG4gIGlmICh2YWwgPj0gbXVsKSB2YWwgLT0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpXG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQ4ID0gZnVuY3Rpb24gcmVhZEludDggKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAxLCB0aGlzLmxlbmd0aClcbiAgaWYgKCEodGhpc1tvZmZzZXRdICYgMHg4MCkpIHJldHVybiAodGhpc1tvZmZzZXRdKVxuICByZXR1cm4gKCgweGZmIC0gdGhpc1tvZmZzZXRdICsgMSkgKiAtMSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MTZMRSA9IGZ1bmN0aW9uIHJlYWRJbnQxNkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldF0gfCAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KVxuICByZXR1cm4gKHZhbCAmIDB4ODAwMCkgPyB2YWwgfCAweEZGRkYwMDAwIDogdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDE2QkUgPSBmdW5jdGlvbiByZWFkSW50MTZCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXQgKyAxXSB8ICh0aGlzW29mZnNldF0gPDwgOClcbiAgcmV0dXJuICh2YWwgJiAweDgwMDApID8gdmFsIHwgMHhGRkZGMDAwMCA6IHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQzMkxFID0gZnVuY3Rpb24gcmVhZEludDMyTEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSkgfFxuICAgICh0aGlzW29mZnNldCArIDFdIDw8IDgpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCAxNikgfFxuICAgICh0aGlzW29mZnNldCArIDNdIDw8IDI0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQzMkJFID0gZnVuY3Rpb24gcmVhZEludDMyQkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSA8PCAyNCkgfFxuICAgICh0aGlzW29mZnNldCArIDFdIDw8IDE2KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgOCkgfFxuICAgICh0aGlzW29mZnNldCArIDNdKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRGbG9hdExFID0gZnVuY3Rpb24gcmVhZEZsb2F0TEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIHRydWUsIDIzLCA0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRGbG9hdEJFID0gZnVuY3Rpb24gcmVhZEZsb2F0QkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIGZhbHNlLCAyMywgNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRG91YmxlTEUgPSBmdW5jdGlvbiByZWFkRG91YmxlTEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA4LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIHRydWUsIDUyLCA4KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWREb3VibGVCRSA9IGZ1bmN0aW9uIHJlYWREb3VibGVCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDgsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgZmFsc2UsIDUyLCA4KVxufVxuXG5mdW5jdGlvbiBjaGVja0ludCAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBleHQsIG1heCwgbWluKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGJ1ZikpIHRocm93IG5ldyBUeXBlRXJyb3IoJ1wiYnVmZmVyXCIgYXJndW1lbnQgbXVzdCBiZSBhIEJ1ZmZlciBpbnN0YW5jZScpXG4gIGlmICh2YWx1ZSA+IG1heCB8fCB2YWx1ZSA8IG1pbikgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ1widmFsdWVcIiBhcmd1bWVudCBpcyBvdXQgb2YgYm91bmRzJylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGJ1Zi5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdJbmRleCBvdXQgb2YgcmFuZ2UnKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludExFID0gZnVuY3Rpb24gd3JpdGVVSW50TEUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICB2YXIgbWF4Qnl0ZXMgPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aCkgLSAxXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbWF4Qnl0ZXMsIDApXG4gIH1cblxuICB2YXIgbXVsID0gMVxuICB2YXIgaSA9IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICh2YWx1ZSAvIG11bCkgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludEJFID0gZnVuY3Rpb24gd3JpdGVVSW50QkUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICB2YXIgbWF4Qnl0ZXMgPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aCkgLSAxXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbWF4Qnl0ZXMsIDApXG4gIH1cblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHRoaXNbb2Zmc2V0ICsgaV0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKC0taSA+PSAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICh2YWx1ZSAvIG11bCkgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDggPSBmdW5jdGlvbiB3cml0ZVVJbnQ4ICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDEsIDB4ZmYsIDApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHZhbHVlID0gTWF0aC5mbG9vcih2YWx1ZSlcbiAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgcmV0dXJuIG9mZnNldCArIDFcbn1cblxuZnVuY3Rpb24gb2JqZWN0V3JpdGVVSW50MTYgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuKSB7XG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmICsgdmFsdWUgKyAxXG4gIGZvciAodmFyIGkgPSAwLCBqID0gTWF0aC5taW4oYnVmLmxlbmd0aCAtIG9mZnNldCwgMik7IGkgPCBqOyArK2kpIHtcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSAodmFsdWUgJiAoMHhmZiA8PCAoOCAqIChsaXR0bGVFbmRpYW4gPyBpIDogMSAtIGkpKSkpID4+PlxuICAgICAgKGxpdHRsZUVuZGlhbiA/IGkgOiAxIC0gaSkgKiA4XG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQxNkxFID0gZnVuY3Rpb24gd3JpdGVVSW50MTZMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweGZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MTZCRSA9IGZ1bmN0aW9uIHdyaXRlVUludDE2QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHhmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuZnVuY3Rpb24gb2JqZWN0V3JpdGVVSW50MzIgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuKSB7XG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmZmZmZiArIHZhbHVlICsgMVxuICBmb3IgKHZhciBpID0gMCwgaiA9IE1hdGgubWluKGJ1Zi5sZW5ndGggLSBvZmZzZXQsIDQpOyBpIDwgajsgKytpKSB7XG4gICAgYnVmW29mZnNldCArIGldID0gKHZhbHVlID4+PiAobGl0dGxlRW5kaWFuID8gaSA6IDMgLSBpKSAqIDgpICYgMHhmZlxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MzJMRSA9IGZ1bmN0aW9uIHdyaXRlVUludDMyTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHhmZmZmZmZmZiwgMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQzMkJFID0gZnVuY3Rpb24gd3JpdGVVSW50MzJCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweGZmZmZmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDI0KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDE2KVxuICAgIHRoaXNbb2Zmc2V0ICsgMl0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludExFID0gZnVuY3Rpb24gd3JpdGVJbnRMRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IDBcbiAgdmFyIG11bCA9IDFcbiAgdmFyIHN1YiA9IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgaWYgKHZhbHVlIDwgMCAmJiBzdWIgPT09IDAgJiYgdGhpc1tvZmZzZXQgKyBpIC0gMV0gIT09IDApIHtcbiAgICAgIHN1YiA9IDFcbiAgICB9XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICgodmFsdWUgLyBtdWwpID4+IDApIC0gc3ViICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIG9mZnNldCArIGJ5dGVMZW5ndGhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludEJFID0gZnVuY3Rpb24gd3JpdGVJbnRCRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHZhciBzdWIgPSAwXG4gIHRoaXNbb2Zmc2V0ICsgaV0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKC0taSA+PSAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgaWYgKHZhbHVlIDwgMCAmJiBzdWIgPT09IDAgJiYgdGhpc1tvZmZzZXQgKyBpICsgMV0gIT09IDApIHtcbiAgICAgIHN1YiA9IDFcbiAgICB9XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICgodmFsdWUgLyBtdWwpID4+IDApIC0gc3ViICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIG9mZnNldCArIGJ5dGVMZW5ndGhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDggPSBmdW5jdGlvbiB3cml0ZUludDggKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMSwgMHg3ZiwgLTB4ODApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHZhbHVlID0gTWF0aC5mbG9vcih2YWx1ZSlcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmICsgdmFsdWUgKyAxXG4gIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIHJldHVybiBvZmZzZXQgKyAxXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQxNkxFID0gZnVuY3Rpb24gd3JpdGVJbnQxNkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4N2ZmZiwgLTB4ODAwMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDE2QkUgPSBmdW5jdGlvbiB3cml0ZUludDE2QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHg3ZmZmLCAtMHg4MDAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDMyTEUgPSBmdW5jdGlvbiB3cml0ZUludDMyTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHg3ZmZmZmZmZiwgLTB4ODAwMDAwMDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlID4+PiAyNClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQzMkJFID0gZnVuY3Rpb24gd3JpdGVJbnQzMkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4N2ZmZmZmZmYsIC0weDgwMDAwMDAwKVxuICBpZiAodmFsdWUgPCAwKSB2YWx1ZSA9IDB4ZmZmZmZmZmYgKyB2YWx1ZSArIDFcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlID4+PiAyNClcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0ICsgM10gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbmZ1bmN0aW9uIGNoZWNrSUVFRTc1NCAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBleHQsIG1heCwgbWluKSB7XG4gIGlmIChvZmZzZXQgKyBleHQgPiBidWYubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignSW5kZXggb3V0IG9mIHJhbmdlJylcbiAgaWYgKG9mZnNldCA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdJbmRleCBvdXQgb2YgcmFuZ2UnKVxufVxuXG5mdW5jdGlvbiB3cml0ZUZsb2F0IChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrSUVFRTc1NChidWYsIHZhbHVlLCBvZmZzZXQsIDQsIDMuNDAyODIzNDY2Mzg1Mjg4NmUrMzgsIC0zLjQwMjgyMzQ2NjM4NTI4ODZlKzM4KVxuICB9XG4gIGllZWU3NTQud3JpdGUoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4sIDIzLCA0KVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlRmxvYXRMRSA9IGZ1bmN0aW9uIHdyaXRlRmxvYXRMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRmxvYXQodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSwgbm9Bc3NlcnQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVGbG9hdEJFID0gZnVuY3Rpb24gd3JpdGVGbG9hdEJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVGbG9hdCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSwgbm9Bc3NlcnQpXG59XG5cbmZ1bmN0aW9uIHdyaXRlRG91YmxlIChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrSUVFRTc1NChidWYsIHZhbHVlLCBvZmZzZXQsIDgsIDEuNzk3NjkzMTM0ODYyMzE1N0UrMzA4LCAtMS43OTc2OTMxMzQ4NjIzMTU3RSszMDgpXG4gIH1cbiAgaWVlZTc1NC53cml0ZShidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgNTIsIDgpXG4gIHJldHVybiBvZmZzZXQgKyA4XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVEb3VibGVMRSA9IGZ1bmN0aW9uIHdyaXRlRG91YmxlTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZURvdWJsZSh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlLCBub0Fzc2VydClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZURvdWJsZUJFID0gZnVuY3Rpb24gd3JpdGVEb3VibGVCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRG91YmxlKHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlLCBub0Fzc2VydClcbn1cblxuLy8gY29weSh0YXJnZXRCdWZmZXIsIHRhcmdldFN0YXJ0PTAsIHNvdXJjZVN0YXJ0PTAsIHNvdXJjZUVuZD1idWZmZXIubGVuZ3RoKVxuQnVmZmVyLnByb3RvdHlwZS5jb3B5ID0gZnVuY3Rpb24gY29weSAodGFyZ2V0LCB0YXJnZXRTdGFydCwgc3RhcnQsIGVuZCkge1xuICBpZiAoIXN0YXJ0KSBzdGFydCA9IDBcbiAgaWYgKCFlbmQgJiYgZW5kICE9PSAwKSBlbmQgPSB0aGlzLmxlbmd0aFxuICBpZiAodGFyZ2V0U3RhcnQgPj0gdGFyZ2V0Lmxlbmd0aCkgdGFyZ2V0U3RhcnQgPSB0YXJnZXQubGVuZ3RoXG4gIGlmICghdGFyZ2V0U3RhcnQpIHRhcmdldFN0YXJ0ID0gMFxuICBpZiAoZW5kID4gMCAmJiBlbmQgPCBzdGFydCkgZW5kID0gc3RhcnRcblxuICAvLyBDb3B5IDAgYnl0ZXM7IHdlJ3JlIGRvbmVcbiAgaWYgKGVuZCA9PT0gc3RhcnQpIHJldHVybiAwXG4gIGlmICh0YXJnZXQubGVuZ3RoID09PSAwIHx8IHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm4gMFxuXG4gIC8vIEZhdGFsIGVycm9yIGNvbmRpdGlvbnNcbiAgaWYgKHRhcmdldFN0YXJ0IDwgMCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCd0YXJnZXRTdGFydCBvdXQgb2YgYm91bmRzJylcbiAgfVxuICBpZiAoc3RhcnQgPCAwIHx8IHN0YXJ0ID49IHRoaXMubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc291cmNlU3RhcnQgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChlbmQgPCAwKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc291cmNlRW5kIG91dCBvZiBib3VuZHMnKVxuXG4gIC8vIEFyZSB3ZSBvb2I/XG4gIGlmIChlbmQgPiB0aGlzLmxlbmd0aCkgZW5kID0gdGhpcy5sZW5ndGhcbiAgaWYgKHRhcmdldC5sZW5ndGggLSB0YXJnZXRTdGFydCA8IGVuZCAtIHN0YXJ0KSB7XG4gICAgZW5kID0gdGFyZ2V0Lmxlbmd0aCAtIHRhcmdldFN0YXJ0ICsgc3RhcnRcbiAgfVxuXG4gIHZhciBsZW4gPSBlbmQgLSBzdGFydFxuICB2YXIgaVxuXG4gIGlmICh0aGlzID09PSB0YXJnZXQgJiYgc3RhcnQgPCB0YXJnZXRTdGFydCAmJiB0YXJnZXRTdGFydCA8IGVuZCkge1xuICAgIC8vIGRlc2NlbmRpbmcgY29weSBmcm9tIGVuZFxuICAgIGZvciAoaSA9IGxlbiAtIDE7IGkgPj0gMDsgLS1pKSB7XG4gICAgICB0YXJnZXRbaSArIHRhcmdldFN0YXJ0XSA9IHRoaXNbaSArIHN0YXJ0XVxuICAgIH1cbiAgfSBlbHNlIGlmIChsZW4gPCAxMDAwIHx8ICFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIC8vIGFzY2VuZGluZyBjb3B5IGZyb20gc3RhcnRcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuOyArK2kpIHtcbiAgICAgIHRhcmdldFtpICsgdGFyZ2V0U3RhcnRdID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIFVpbnQ4QXJyYXkucHJvdG90eXBlLnNldC5jYWxsKFxuICAgICAgdGFyZ2V0LFxuICAgICAgdGhpcy5zdWJhcnJheShzdGFydCwgc3RhcnQgKyBsZW4pLFxuICAgICAgdGFyZ2V0U3RhcnRcbiAgICApXG4gIH1cblxuICByZXR1cm4gbGVuXG59XG5cbi8vIFVzYWdlOlxuLy8gICAgYnVmZmVyLmZpbGwobnVtYmVyWywgb2Zmc2V0WywgZW5kXV0pXG4vLyAgICBidWZmZXIuZmlsbChidWZmZXJbLCBvZmZzZXRbLCBlbmRdXSlcbi8vICAgIGJ1ZmZlci5maWxsKHN0cmluZ1ssIG9mZnNldFssIGVuZF1dWywgZW5jb2RpbmddKVxuQnVmZmVyLnByb3RvdHlwZS5maWxsID0gZnVuY3Rpb24gZmlsbCAodmFsLCBzdGFydCwgZW5kLCBlbmNvZGluZykge1xuICAvLyBIYW5kbGUgc3RyaW5nIGNhc2VzOlxuICBpZiAodHlwZW9mIHZhbCA9PT0gJ3N0cmluZycpIHtcbiAgICBpZiAodHlwZW9mIHN0YXJ0ID09PSAnc3RyaW5nJykge1xuICAgICAgZW5jb2RpbmcgPSBzdGFydFxuICAgICAgc3RhcnQgPSAwXG4gICAgICBlbmQgPSB0aGlzLmxlbmd0aFxuICAgIH0gZWxzZSBpZiAodHlwZW9mIGVuZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgIGVuY29kaW5nID0gZW5kXG4gICAgICBlbmQgPSB0aGlzLmxlbmd0aFxuICAgIH1cbiAgICBpZiAodmFsLmxlbmd0aCA9PT0gMSkge1xuICAgICAgdmFyIGNvZGUgPSB2YWwuY2hhckNvZGVBdCgwKVxuICAgICAgaWYgKGNvZGUgPCAyNTYpIHtcbiAgICAgICAgdmFsID0gY29kZVxuICAgICAgfVxuICAgIH1cbiAgICBpZiAoZW5jb2RpbmcgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgZW5jb2RpbmcgIT09ICdzdHJpbmcnKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdlbmNvZGluZyBtdXN0IGJlIGEgc3RyaW5nJylcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBlbmNvZGluZyA9PT0gJ3N0cmluZycgJiYgIUJ1ZmZlci5pc0VuY29kaW5nKGVuY29kaW5nKSkge1xuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignVW5rbm93biBlbmNvZGluZzogJyArIGVuY29kaW5nKVxuICAgIH1cbiAgfSBlbHNlIGlmICh0eXBlb2YgdmFsID09PSAnbnVtYmVyJykge1xuICAgIHZhbCA9IHZhbCAmIDI1NVxuICB9XG5cbiAgLy8gSW52YWxpZCByYW5nZXMgYXJlIG5vdCBzZXQgdG8gYSBkZWZhdWx0LCBzbyBjYW4gcmFuZ2UgY2hlY2sgZWFybHkuXG4gIGlmIChzdGFydCA8IDAgfHwgdGhpcy5sZW5ndGggPCBzdGFydCB8fCB0aGlzLmxlbmd0aCA8IGVuZCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdPdXQgb2YgcmFuZ2UgaW5kZXgnKVxuICB9XG5cbiAgaWYgKGVuZCA8PSBzdGFydCkge1xuICAgIHJldHVybiB0aGlzXG4gIH1cblxuICBzdGFydCA9IHN0YXJ0ID4+PiAwXG4gIGVuZCA9IGVuZCA9PT0gdW5kZWZpbmVkID8gdGhpcy5sZW5ndGggOiBlbmQgPj4+IDBcblxuICBpZiAoIXZhbCkgdmFsID0gMFxuXG4gIHZhciBpXG4gIGlmICh0eXBlb2YgdmFsID09PSAnbnVtYmVyJykge1xuICAgIGZvciAoaSA9IHN0YXJ0OyBpIDwgZW5kOyArK2kpIHtcbiAgICAgIHRoaXNbaV0gPSB2YWxcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdmFyIGJ5dGVzID0gQnVmZmVyLmlzQnVmZmVyKHZhbClcbiAgICAgID8gdmFsXG4gICAgICA6IHV0ZjhUb0J5dGVzKG5ldyBCdWZmZXIodmFsLCBlbmNvZGluZykudG9TdHJpbmcoKSlcbiAgICB2YXIgbGVuID0gYnl0ZXMubGVuZ3RoXG4gICAgZm9yIChpID0gMDsgaSA8IGVuZCAtIHN0YXJ0OyArK2kpIHtcbiAgICAgIHRoaXNbaSArIHN0YXJ0XSA9IGJ5dGVzW2kgJSBsZW5dXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRoaXNcbn1cblxuLy8gSEVMUEVSIEZVTkNUSU9OU1xuLy8gPT09PT09PT09PT09PT09PVxuXG52YXIgSU5WQUxJRF9CQVNFNjRfUkUgPSAvW14rXFwvMC05QS1aYS16LV9dL2dcblxuZnVuY3Rpb24gYmFzZTY0Y2xlYW4gKHN0cikge1xuICAvLyBOb2RlIHN0cmlwcyBvdXQgaW52YWxpZCBjaGFyYWN0ZXJzIGxpa2UgXFxuIGFuZCBcXHQgZnJvbSB0aGUgc3RyaW5nLCBiYXNlNjQtanMgZG9lcyBub3RcbiAgc3RyID0gc3RyaW5ndHJpbShzdHIpLnJlcGxhY2UoSU5WQUxJRF9CQVNFNjRfUkUsICcnKVxuICAvLyBOb2RlIGNvbnZlcnRzIHN0cmluZ3Mgd2l0aCBsZW5ndGggPCAyIHRvICcnXG4gIGlmIChzdHIubGVuZ3RoIDwgMikgcmV0dXJuICcnXG4gIC8vIE5vZGUgYWxsb3dzIGZvciBub24tcGFkZGVkIGJhc2U2NCBzdHJpbmdzIChtaXNzaW5nIHRyYWlsaW5nID09PSksIGJhc2U2NC1qcyBkb2VzIG5vdFxuICB3aGlsZSAoc3RyLmxlbmd0aCAlIDQgIT09IDApIHtcbiAgICBzdHIgPSBzdHIgKyAnPSdcbiAgfVxuICByZXR1cm4gc3RyXG59XG5cbmZ1bmN0aW9uIHN0cmluZ3RyaW0gKHN0cikge1xuICBpZiAoc3RyLnRyaW0pIHJldHVybiBzdHIudHJpbSgpXG4gIHJldHVybiBzdHIucmVwbGFjZSgvXlxccyt8XFxzKyQvZywgJycpXG59XG5cbmZ1bmN0aW9uIHRvSGV4IChuKSB7XG4gIGlmIChuIDwgMTYpIHJldHVybiAnMCcgKyBuLnRvU3RyaW5nKDE2KVxuICByZXR1cm4gbi50b1N0cmluZygxNilcbn1cblxuZnVuY3Rpb24gdXRmOFRvQnl0ZXMgKHN0cmluZywgdW5pdHMpIHtcbiAgdW5pdHMgPSB1bml0cyB8fCBJbmZpbml0eVxuICB2YXIgY29kZVBvaW50XG4gIHZhciBsZW5ndGggPSBzdHJpbmcubGVuZ3RoXG4gIHZhciBsZWFkU3Vycm9nYXRlID0gbnVsbFxuICB2YXIgYnl0ZXMgPSBbXVxuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyArK2kpIHtcbiAgICBjb2RlUG9pbnQgPSBzdHJpbmcuY2hhckNvZGVBdChpKVxuXG4gICAgLy8gaXMgc3Vycm9nYXRlIGNvbXBvbmVudFxuICAgIGlmIChjb2RlUG9pbnQgPiAweEQ3RkYgJiYgY29kZVBvaW50IDwgMHhFMDAwKSB7XG4gICAgICAvLyBsYXN0IGNoYXIgd2FzIGEgbGVhZFxuICAgICAgaWYgKCFsZWFkU3Vycm9nYXRlKSB7XG4gICAgICAgIC8vIG5vIGxlYWQgeWV0XG4gICAgICAgIGlmIChjb2RlUG9pbnQgPiAweERCRkYpIHtcbiAgICAgICAgICAvLyB1bmV4cGVjdGVkIHRyYWlsXG4gICAgICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgICAgICAgY29udGludWVcbiAgICAgICAgfSBlbHNlIGlmIChpICsgMSA9PT0gbGVuZ3RoKSB7XG4gICAgICAgICAgLy8gdW5wYWlyZWQgbGVhZFxuICAgICAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgIH1cblxuICAgICAgICAvLyB2YWxpZCBsZWFkXG4gICAgICAgIGxlYWRTdXJyb2dhdGUgPSBjb2RlUG9pbnRcblxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICAvLyAyIGxlYWRzIGluIGEgcm93XG4gICAgICBpZiAoY29kZVBvaW50IDwgMHhEQzAwKSB7XG4gICAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgICAgICBsZWFkU3Vycm9nYXRlID0gY29kZVBvaW50XG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIC8vIHZhbGlkIHN1cnJvZ2F0ZSBwYWlyXG4gICAgICBjb2RlUG9pbnQgPSAobGVhZFN1cnJvZ2F0ZSAtIDB4RDgwMCA8PCAxMCB8IGNvZGVQb2ludCAtIDB4REMwMCkgKyAweDEwMDAwXG4gICAgfSBlbHNlIGlmIChsZWFkU3Vycm9nYXRlKSB7XG4gICAgICAvLyB2YWxpZCBibXAgY2hhciwgYnV0IGxhc3QgY2hhciB3YXMgYSBsZWFkXG4gICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICB9XG5cbiAgICBsZWFkU3Vycm9nYXRlID0gbnVsbFxuXG4gICAgLy8gZW5jb2RlIHV0ZjhcbiAgICBpZiAoY29kZVBvaW50IDwgMHg4MCkge1xuICAgICAgaWYgKCh1bml0cyAtPSAxKSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKGNvZGVQb2ludClcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA8IDB4ODAwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDIpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDYgfCAweEMwLFxuICAgICAgICBjb2RlUG9pbnQgJiAweDNGIHwgMHg4MFxuICAgICAgKVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50IDwgMHgxMDAwMCkge1xuICAgICAgaWYgKCh1bml0cyAtPSAzKSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHhDIHwgMHhFMCxcbiAgICAgICAgY29kZVBvaW50ID4+IDB4NiAmIDB4M0YgfCAweDgwLFxuICAgICAgICBjb2RlUG9pbnQgJiAweDNGIHwgMHg4MFxuICAgICAgKVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50IDwgMHgxMTAwMDApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gNCkgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChcbiAgICAgICAgY29kZVBvaW50ID4+IDB4MTIgfCAweEYwLFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHhDICYgMHgzRiB8IDB4ODAsXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDYgJiAweDNGIHwgMHg4MCxcbiAgICAgICAgY29kZVBvaW50ICYgMHgzRiB8IDB4ODBcbiAgICAgIClcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGNvZGUgcG9pbnQnKVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBieXRlc1xufVxuXG5mdW5jdGlvbiBhc2NpaVRvQnl0ZXMgKHN0cikge1xuICB2YXIgYnl0ZUFycmF5ID0gW11cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdHIubGVuZ3RoOyArK2kpIHtcbiAgICAvLyBOb2RlJ3MgY29kZSBzZWVtcyB0byBiZSBkb2luZyB0aGlzIGFuZCBub3QgJiAweDdGLi5cbiAgICBieXRlQXJyYXkucHVzaChzdHIuY2hhckNvZGVBdChpKSAmIDB4RkYpXG4gIH1cbiAgcmV0dXJuIGJ5dGVBcnJheVxufVxuXG5mdW5jdGlvbiB1dGYxNmxlVG9CeXRlcyAoc3RyLCB1bml0cykge1xuICB2YXIgYywgaGksIGxvXG4gIHZhciBieXRlQXJyYXkgPSBbXVxuICBmb3IgKHZhciBpID0gMDsgaSA8IHN0ci5sZW5ndGg7ICsraSkge1xuICAgIGlmICgodW5pdHMgLT0gMikgPCAwKSBicmVha1xuXG4gICAgYyA9IHN0ci5jaGFyQ29kZUF0KGkpXG4gICAgaGkgPSBjID4+IDhcbiAgICBsbyA9IGMgJSAyNTZcbiAgICBieXRlQXJyYXkucHVzaChsbylcbiAgICBieXRlQXJyYXkucHVzaChoaSlcbiAgfVxuXG4gIHJldHVybiBieXRlQXJyYXlcbn1cblxuZnVuY3Rpb24gYmFzZTY0VG9CeXRlcyAoc3RyKSB7XG4gIHJldHVybiBiYXNlNjQudG9CeXRlQXJyYXkoYmFzZTY0Y2xlYW4oc3RyKSlcbn1cblxuZnVuY3Rpb24gYmxpdEJ1ZmZlciAoc3JjLCBkc3QsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyArK2kpIHtcbiAgICBpZiAoKGkgKyBvZmZzZXQgPj0gZHN0Lmxlbmd0aCkgfHwgKGkgPj0gc3JjLmxlbmd0aCkpIGJyZWFrXG4gICAgZHN0W2kgKyBvZmZzZXRdID0gc3JjW2ldXG4gIH1cbiAgcmV0dXJuIGlcbn1cblxuZnVuY3Rpb24gaXNuYW4gKHZhbCkge1xuICByZXR1cm4gdmFsICE9PSB2YWwgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby1zZWxmLWNvbXBhcmVcbn1cbiIsImV4cG9ydHMucmVhZCA9IGZ1bmN0aW9uIChidWZmZXIsIG9mZnNldCwgaXNMRSwgbUxlbiwgbkJ5dGVzKSB7XG4gIHZhciBlLCBtXG4gIHZhciBlTGVuID0gbkJ5dGVzICogOCAtIG1MZW4gLSAxXG4gIHZhciBlTWF4ID0gKDEgPDwgZUxlbikgLSAxXG4gIHZhciBlQmlhcyA9IGVNYXggPj4gMVxuICB2YXIgbkJpdHMgPSAtN1xuICB2YXIgaSA9IGlzTEUgPyAobkJ5dGVzIC0gMSkgOiAwXG4gIHZhciBkID0gaXNMRSA/IC0xIDogMVxuICB2YXIgcyA9IGJ1ZmZlcltvZmZzZXQgKyBpXVxuXG4gIGkgKz0gZFxuXG4gIGUgPSBzICYgKCgxIDw8ICgtbkJpdHMpKSAtIDEpXG4gIHMgPj49ICgtbkJpdHMpXG4gIG5CaXRzICs9IGVMZW5cbiAgZm9yICg7IG5CaXRzID4gMDsgZSA9IGUgKiAyNTYgKyBidWZmZXJbb2Zmc2V0ICsgaV0sIGkgKz0gZCwgbkJpdHMgLT0gOCkge31cblxuICBtID0gZSAmICgoMSA8PCAoLW5CaXRzKSkgLSAxKVxuICBlID4+PSAoLW5CaXRzKVxuICBuQml0cyArPSBtTGVuXG4gIGZvciAoOyBuQml0cyA+IDA7IG0gPSBtICogMjU2ICsgYnVmZmVyW29mZnNldCArIGldLCBpICs9IGQsIG5CaXRzIC09IDgpIHt9XG5cbiAgaWYgKGUgPT09IDApIHtcbiAgICBlID0gMSAtIGVCaWFzXG4gIH0gZWxzZSBpZiAoZSA9PT0gZU1heCkge1xuICAgIHJldHVybiBtID8gTmFOIDogKChzID8gLTEgOiAxKSAqIEluZmluaXR5KVxuICB9IGVsc2Uge1xuICAgIG0gPSBtICsgTWF0aC5wb3coMiwgbUxlbilcbiAgICBlID0gZSAtIGVCaWFzXG4gIH1cbiAgcmV0dXJuIChzID8gLTEgOiAxKSAqIG0gKiBNYXRoLnBvdygyLCBlIC0gbUxlbilcbn1cblxuZXhwb3J0cy53cml0ZSA9IGZ1bmN0aW9uIChidWZmZXIsIHZhbHVlLCBvZmZzZXQsIGlzTEUsIG1MZW4sIG5CeXRlcykge1xuICB2YXIgZSwgbSwgY1xuICB2YXIgZUxlbiA9IG5CeXRlcyAqIDggLSBtTGVuIC0gMVxuICB2YXIgZU1heCA9ICgxIDw8IGVMZW4pIC0gMVxuICB2YXIgZUJpYXMgPSBlTWF4ID4+IDFcbiAgdmFyIHJ0ID0gKG1MZW4gPT09IDIzID8gTWF0aC5wb3coMiwgLTI0KSAtIE1hdGgucG93KDIsIC03NykgOiAwKVxuICB2YXIgaSA9IGlzTEUgPyAwIDogKG5CeXRlcyAtIDEpXG4gIHZhciBkID0gaXNMRSA/IDEgOiAtMVxuICB2YXIgcyA9IHZhbHVlIDwgMCB8fCAodmFsdWUgPT09IDAgJiYgMSAvIHZhbHVlIDwgMCkgPyAxIDogMFxuXG4gIHZhbHVlID0gTWF0aC5hYnModmFsdWUpXG5cbiAgaWYgKGlzTmFOKHZhbHVlKSB8fCB2YWx1ZSA9PT0gSW5maW5pdHkpIHtcbiAgICBtID0gaXNOYU4odmFsdWUpID8gMSA6IDBcbiAgICBlID0gZU1heFxuICB9IGVsc2Uge1xuICAgIGUgPSBNYXRoLmZsb29yKE1hdGgubG9nKHZhbHVlKSAvIE1hdGguTE4yKVxuICAgIGlmICh2YWx1ZSAqIChjID0gTWF0aC5wb3coMiwgLWUpKSA8IDEpIHtcbiAgICAgIGUtLVxuICAgICAgYyAqPSAyXG4gICAgfVxuICAgIGlmIChlICsgZUJpYXMgPj0gMSkge1xuICAgICAgdmFsdWUgKz0gcnQgLyBjXG4gICAgfSBlbHNlIHtcbiAgICAgIHZhbHVlICs9IHJ0ICogTWF0aC5wb3coMiwgMSAtIGVCaWFzKVxuICAgIH1cbiAgICBpZiAodmFsdWUgKiBjID49IDIpIHtcbiAgICAgIGUrK1xuICAgICAgYyAvPSAyXG4gICAgfVxuXG4gICAgaWYgKGUgKyBlQmlhcyA+PSBlTWF4KSB7XG4gICAgICBtID0gMFxuICAgICAgZSA9IGVNYXhcbiAgICB9IGVsc2UgaWYgKGUgKyBlQmlhcyA+PSAxKSB7XG4gICAgICBtID0gKHZhbHVlICogYyAtIDEpICogTWF0aC5wb3coMiwgbUxlbilcbiAgICAgIGUgPSBlICsgZUJpYXNcbiAgICB9IGVsc2Uge1xuICAgICAgbSA9IHZhbHVlICogTWF0aC5wb3coMiwgZUJpYXMgLSAxKSAqIE1hdGgucG93KDIsIG1MZW4pXG4gICAgICBlID0gMFxuICAgIH1cbiAgfVxuXG4gIGZvciAoOyBtTGVuID49IDg7IGJ1ZmZlcltvZmZzZXQgKyBpXSA9IG0gJiAweGZmLCBpICs9IGQsIG0gLz0gMjU2LCBtTGVuIC09IDgpIHt9XG5cbiAgZSA9IChlIDw8IG1MZW4pIHwgbVxuICBlTGVuICs9IG1MZW5cbiAgZm9yICg7IGVMZW4gPiAwOyBidWZmZXJbb2Zmc2V0ICsgaV0gPSBlICYgMHhmZiwgaSArPSBkLCBlIC89IDI1NiwgZUxlbiAtPSA4KSB7fVxuXG4gIGJ1ZmZlcltvZmZzZXQgKyBpIC0gZF0gfD0gcyAqIDEyOFxufVxuIiwidmFyIHRvU3RyaW5nID0ge30udG9TdHJpbmc7XG5cbm1vZHVsZS5leHBvcnRzID0gQXJyYXkuaXNBcnJheSB8fCBmdW5jdGlvbiAoYXJyKSB7XG4gIHJldHVybiB0b1N0cmluZy5jYWxsKGFycikgPT0gJ1tvYmplY3QgQXJyYXldJztcbn07XG4iLCJtb2R1bGUuZXhwb3J0cz17XG4gICAgXCJ2ZXJzaW9uXCI6IFwidjJcIlxufVxuIiwiLyoqXG4gKiBFcGljZW50ZXIgSmF2YXNjcmlwdCBsaWJyYXJpZXNcbiAqIHY8JT0gdmVyc2lvbiAlPlxuICogaHR0cHM6Ly9naXRodWIuY29tL2ZvcmlvL2VwaWNlbnRlci1qcy1saWJzXG4gKi9cblxudmFyIEYgPSB7XG4gICAgdXRpbDoge30sXG4gICAgZmFjdG9yeToge30sXG4gICAgdHJhbnNwb3J0OiB7fSxcbiAgICBzdG9yZToge30sXG4gICAgc2VydmljZToge30sXG4gICAgbWFuYWdlcjoge1xuICAgICAgICBzdHJhdGVneToge31cbiAgICB9LFxuXG59O1xuXG5GLmxvYWQgPSByZXF1aXJlKCcuL2Vudi1sb2FkJyk7XG5GLmxvYWQoKTtcblxuRi51dGlsLnF1ZXJ5ID0gcmVxdWlyZSgnLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbkYudXRpbC5tYWtlU2VxdWVuY2UgPSByZXF1aXJlKCcuL3V0aWwvbWFrZS1zZXF1ZW5jZScpO1xuRi51dGlsLnJ1biA9IHJlcXVpcmUoJy4vdXRpbC9ydW4tdXRpbCcpO1xuRi51dGlsLmNsYXNzRnJvbSA9IHJlcXVpcmUoJy4vdXRpbC9pbmhlcml0Jyk7XG5cbkYuZmFjdG9yeS5UcmFuc3BvcnQgPSByZXF1aXJlKCcuL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5GLnRyYW5zcG9ydC5BamF4ID0gcmVxdWlyZSgnLi90cmFuc3BvcnQvYWpheC1odHRwLXRyYW5zcG9ydCcpO1xuXG5GLnNlcnZpY2UuVVJMID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3VybC1jb25maWctc2VydmljZScpO1xuRi5zZXJ2aWNlLkNvbmZpZyA9IHJlcXVpcmUoJy4vc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbkYuc2VydmljZS5SdW4gPSByZXF1aXJlKCcuL3NlcnZpY2UvcnVuLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuRmlsZSA9IHJlcXVpcmUoJy4vc2VydmljZS9hZG1pbi1maWxlLXNlcnZpY2UnKTtcbkYuc2VydmljZS5WYXJpYWJsZXMgPSByZXF1aXJlKCcuL3NlcnZpY2UvdmFyaWFibGVzLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuRGF0YSA9IHJlcXVpcmUoJy4vc2VydmljZS9kYXRhLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuQXV0aCA9IHJlcXVpcmUoJy4vc2VydmljZS9hdXRoLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuV29ybGQgPSByZXF1aXJlKCcuL3NlcnZpY2Uvd29ybGQtYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5TdGF0ZSA9IHJlcXVpcmUoJy4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xuRi5zZXJ2aWNlLlVzZXIgPSByZXF1aXJlKCcuL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlcicpO1xuRi5zZXJ2aWNlLk1lbWJlciA9IHJlcXVpcmUoJy4vc2VydmljZS9tZW1iZXItYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5Bc3NldCA9IHJlcXVpcmUoJy4vc2VydmljZS9hc3NldC1hcGktYWRhcHRlcicpO1xuXG5GLnN0b3JlLkNvb2tpZSA9IHJlcXVpcmUoJy4vc3RvcmUvY29va2llLXN0b3JlJyk7XG5GLmZhY3RvcnkuU3RvcmUgPSByZXF1aXJlKCcuL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcblxuRi5tYW5hZ2VyLlNjZW5hcmlvTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvc2NlbmFyaW8tbWFuYWdlcicpO1xuRi5tYW5hZ2VyLlJ1bk1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1tYW5hZ2VyJyk7XG5GLm1hbmFnZXIuQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL2F1dGgtbWFuYWdlcicpO1xuRi5tYW5hZ2VyLldvcmxkTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvd29ybGQtbWFuYWdlcicpO1xuXG5GLm1hbmFnZXIuc3RyYXRlZ3lbJ2Fsd2F5cy1uZXcnXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvYWx3YXlzLW5ldy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5Wydjb25kaXRpb25hbC1jcmVhdGlvbiddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5LmlkZW50aXR5ID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9pZGVudGl0eS1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtbWlzc2luZyddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtbWlzc2luZyddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtcGVyc2lzdGVkJ10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1wZXJzaXN0ZWQtc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLWluaXRpYWxpemVkJ10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpO1xuXG5GLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXInKTtcbkYuc2VydmljZS5DaGFubmVsID0gcmVxdWlyZSgnLi9zZXJ2aWNlL2NoYW5uZWwtc2VydmljZScpO1xuXG5GLnZlcnNpb24gPSAnPCU9IHZlcnNpb24gJT4nO1xuRi5hcGkgPSByZXF1aXJlKCcuL2FwaS12ZXJzaW9uLmpzb24nKTtcblxuZ2xvYmFsLkYgPSBGO1xubW9kdWxlLmV4cG9ydHMgPSBGO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgdXJsQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcblxudmFyIGVudkxvYWQgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgICB2YXIgZW52UHJvbWlzZTtcbiAgICB2YXIgaG9zdDtcbiAgICB2YXIgdXJsU2VydmljZSA9IHVybENvbmZpZ1NlcnZpY2UoKTtcbiAgICB2YXIgZW52UGF0aCA9ICcvZXBpY2VudGVyL3YxL2NvbmZpZyc7XG4gICAgaWYgKHVybFNlcnZpY2UuaXNMb2NhbGhvc3QoKSkge1xuICAgICAgICBob3N0ID0gJ2h0dHBzOi8vZm9yaW8uY29tJztcbiAgICB9IGVsc2Uge1xuICAgICAgICBob3N0ID0gJyc7XG4gICAgfVxuICAgIHZhciBpbmZvVXJsID0gaG9zdCArIGVudlBhdGg7XG4gICAgZW52UHJvbWlzZSA9ICQuYWpheCh7IHVybDogaW5mb1VybCwgYXN5bmM6IGZhbHNlIH0pO1xuICAgIGVudlByb21pc2UuZG9uZShmdW5jdGlvbiAocmVzKSB7XG4gICAgICAgIHZhciBhcGkgPSByZXMuYXBpO1xuICAgICAgICAkLmV4dGVuZCh1cmxDb25maWdTZXJ2aWNlLCBhcGkpO1xuICAgIH0pLmZhaWwoZnVuY3Rpb24gKHJlcykge1xuICAgICAgICAvLyBFcGljZW50ZXIvd2Vic2VydmVyIG5vdCBwcm9wZXJseSBjb25maWd1cmVkXG4gICAgICAgIC8vIGZhbGxiYWNrIHRvIGFwaS5mb3Jpby5jb21cbiAgICAgICAgJC5leHRlbmQodXJsQ29uZmlnU2VydmljZSwgeyBwcm90b2NvbDogJ2h0dHBzJywgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH0pO1xuICAgIH0pO1xuICAgIHJldHVybiBlbnZQcm9taXNlLmRvbmUoY2FsbGJhY2spLmZhaWwoY2FsbGJhY2spO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBlbnZMb2FkO1xuIiwiLyoqXG4qICMjIEF1dGhvcml6YXRpb24gTWFuYWdlclxuKlxuKiBUaGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyIHByb3ZpZGVzIGFuIGVhc3kgd2F5IHRvIG1hbmFnZSB1c2VyIGF1dGhlbnRpY2F0aW9uIChsb2dnaW5nIGluIGFuZCBvdXQpIGFuZCBhdXRob3JpemF0aW9uIChrZWVwaW5nIHRyYWNrIG9mIHRva2Vucywgc2Vzc2lvbnMsIGFuZCBncm91cHMpIGZvciBwcm9qZWN0cy5cbipcbiogVGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBpcyBtb3N0IHVzZWZ1bCBmb3IgW3RlYW0gcHJvamVjdHNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN0ZWFtKSB3aXRoIGFuIGFjY2VzcyBsZXZlbCBvZiBbQXV0aGVudGljYXRlZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2FjY2VzcykuIFRoZXNlIHByb2plY3RzIGFyZSBhY2Nlc3NlZCBieSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiBvbmUgb3IgbW9yZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS5cbipcbiogIyMjIyBVc2luZyB0aGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyXG4qXG4qIFRvIHVzZSB0aGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyLCBpbnN0YW50aWF0ZSBpdC4gVGhlbiwgbWFrZSBjYWxscyB0byBhbnkgb2YgdGhlIG1ldGhvZHMgeW91IG5lZWQ6XG4qXG4qICAgICAgIHZhciBhdXRoTWdyID0gbmV3IEYubWFuYWdlci5BdXRoTWFuYWdlcih7XG4qICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgICB1c2VyTmFtZTogJ2VuZHVzZXIxJyxcbiogICAgICAgICAgIHBhc3N3b3JkOiAncGFzc3cwcmQnXG4qICAgICAgIH0pO1xuKiAgICAgICBhdXRoTWdyLmxvZ2luKCkudGhlbihmdW5jdGlvbiAoKSB7XG4qICAgICAgICAgICBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiogICAgICAgfSk7XG4qXG4qXG4qIFRoZSBgb3B0aW9uc2Agb2JqZWN0IHBhc3NlZCB0byB0aGUgYEYubWFuYWdlci5BdXRoTWFuYWdlcigpYCBjYWxsIGNhbiBpbmNsdWRlOlxuKlxuKiAgICogYGFjY291bnRgOiBUaGUgYWNjb3VudCBpZCBmb3IgdGhpcyBgdXNlck5hbWVgLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yIHRoZSAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS5cbiogICAqIGB1c2VyTmFtZWA6IEVtYWlsIG9yIHVzZXJuYW1lIHRvIHVzZSBmb3IgbG9nZ2luZyBpbi5cbiogICAqIGBwYXNzd29yZGA6IFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGUgcHJvamVjdCB0byBsb2cgdGhpcyB1c2VyIGludG8uIE9wdGlvbmFsLlxuKiAgICogYGdyb3VwSWRgOiBJZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggYHVzZXJOYW1lYCBiZWxvbmdzLiBSZXF1aXJlZCBmb3IgZW5kIHVzZXJzIGlmIHRoZSBgcHJvamVjdGAgaXMgc3BlY2lmaWVkLlxuKlxuKiBJZiB5b3UgcHJlZmVyIHN0YXJ0aW5nIGZyb20gYSB0ZW1wbGF0ZSwgdGhlIEVwaWNlbnRlciBKUyBMaWJzIFtMb2dpbiBDb21wb25lbnRdKC4uLy4uLyNjb21wb25lbnRzKSB1c2VzIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIgYXMgd2VsbC4gVGhpcyBzYW1wbGUgSFRNTCBwYWdlIChhbmQgYXNzb2NpYXRlZCBDU1MgYW5kIEpTIGZpbGVzKSBwcm92aWRlcyBhIGxvZ2luIGZvcm0gZm9yIHRlYW0gbWVtYmVycyBhbmQgZW5kIHVzZXJzIG9mIHlvdXIgcHJvamVjdC4gSXQgYWxzbyBpbmNsdWRlcyBhIGdyb3VwIHNlbGVjdG9yIGZvciBlbmQgdXNlcnMgdGhhdCBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBncm91cHMuXG4qL1xuXG4ndXNlIHN0cmljdCc7XG52YXIgQXV0aEFkYXB0ZXIgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL2F1dGgtYXBpLXNlcnZpY2UnKTtcbnZhciBNZW1iZXJBZGFwdGVyID0gcmVxdWlyZSgnLi4vc2VydmljZS9tZW1iZXItYXBpLWFkYXB0ZXInKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xudmFyIEJ1ZmZlciA9IHJlcXVpcmUoJ2J1ZmZlcicpLkJ1ZmZlcjtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHJlcXVpcmVzR3JvdXA6IHRydWVcbn07XG5cbmZ1bmN0aW9uIEF1dGhNYW5hZ2VyKG9wdGlvbnMpIHtcbiAgICBvcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKG9wdGlvbnMpO1xuICAgIHRoaXMub3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucygpO1xuXG4gICAgdGhpcy5pc0xvY2FsID0gdGhpcy5vcHRpb25zLmlzTG9jYWw7XG4gICAgdGhpcy5hdXRoQWRhcHRlciA9IG5ldyBBdXRoQWRhcHRlcih0aGlzLm9wdGlvbnMpO1xufVxuXG52YXIgX2ZpbmRVc2VySW5Hcm91cCA9IGZ1bmN0aW9uIChtZW1iZXJzLCBpZCkge1xuICAgIGZvciAodmFyIGogPSAwOyBqPG1lbWJlcnMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKG1lbWJlcnNbal0udXNlcklkID09PSBpZCkge1xuICAgICAgICAgICAgcmV0dXJuIG1lbWJlcnNbal07XG4gICAgICAgIH1cbiAgICB9XG5cblxuICAgIHJldHVybiBudWxsO1xufTtcblxuQXV0aE1hbmFnZXIucHJvdG90eXBlID0gJC5leHRlbmQoQXV0aE1hbmFnZXIucHJvdG90eXBlLCB7XG5cbiAgICAvKipcbiAgICAqIExvZ3MgdXNlciBpbi5cbiAgICAqXG4gICAgKiAqKkV4YW1wbGUqKlxuICAgICpcbiAgICAqICAgICAgIGF1dGhNZ3IubG9naW4oe1xuICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICogICAgICAgICAgIHVzZXJOYW1lOiAnZW5kdXNlcjEnLFxuICAgICogICAgICAgICAgIHBhc3N3b3JkOiAncGFzc3cwcmQnXG4gICAgKiAgICAgICB9KVxuICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHN0YXR1c09iaikge1xuICAgICogICAgICAgICAgICAgICAvLyBpZiBlbmR1c2VyMSBiZWxvbmdzIHRvIGV4YWN0bHkgb25lIGdyb3VwXG4gICAgKiAgICAgICAgICAgICAgIC8vIChvciBpZiB0aGUgbG9naW4oKSBjYWxsIGlzIG1vZGlmaWVkIHRvIGluY2x1ZGUgdGhlIGdyb3VwIGlkKVxuICAgICogICAgICAgICAgICAgICAvLyBjb250aW51ZSBoZXJlXG4gICAgKiAgICAgICAgICAgfSlcbiAgICAqICAgICAgICAgICAuZmFpbChmdW5jdGlvbihzdGF0dXNPYmopIHtcbiAgICAqICAgICAgICAgICAgICAgLy8gaWYgZW5kdXNlcjEgYmVsb25ncyB0byBtdWx0aXBsZSBncm91cHMsXG4gICAgKiAgICAgICAgICAgICAgIC8vIHRoZSBsb2dpbigpIGNhbGwgZmFpbHNcbiAgICAqICAgICAgICAgICAgICAgLy8gYW5kIHJldHVybnMgYWxsIGdyb3VwcyBvZiB3aGljaCB0aGUgdXNlciBpcyBhIG1lbWJlclxuICAgICogICAgICAgICAgICAgICBmb3IgKHZhciBpPTA7IGkgPCBzdGF0dXNPYmoudXNlckdyb3Vwcy5sZW5ndGg7IGkrKykge1xuICAgICogICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coc3RhdHVzT2JqLnVzZXJHcm91cHNbaV0ubmFtZSwgc3RhdHVzT2JqLnVzZXJHcm91cHNbaV0uZ3JvdXBJZCk7XG4gICAgKiAgICAgICAgICAgICAgIH1cbiAgICAqICAgICAgICAgICB9KTtcbiAgICAqXG4gICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICpcbiAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy4gSWYgbm90IHBhc3NlZCBpbiB3aGVuIGNyZWF0aW5nIGFuIGluc3RhbmNlIG9mIHRoZSBtYW5hZ2VyIChgRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyKClgKSwgdGhlc2Ugb3B0aW9ucyBzaG91bGQgaW5jbHVkZTpcbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5hY2NvdW50YCBUaGUgYWNjb3VudCBpZCBmb3IgdGhpcyBgdXNlck5hbWVgLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yIHRoZSAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy51c2VyTmFtZWAgRW1haWwgb3IgdXNlcm5hbWUgdG8gdXNlIGZvciBsb2dnaW5nIGluLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLnBhc3N3b3JkYCBQYXNzd29yZCBmb3Igc3BlY2lmaWVkIGB1c2VyTmFtZWAuXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gYG9wdGlvbnMucHJvamVjdGAgKE9wdGlvbmFsKSBUaGUgKipQcm9qZWN0IElEKiogZm9yIHRoZSBwcm9qZWN0IHRvIGxvZyB0aGlzIHVzZXIgaW50by5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5ncm91cElkYCBUaGUgaWQgb2YgdGhlIGdyb3VwIHRvIHdoaWNoIGB1c2VyTmFtZWAgYmVsb25ncy4gUmVxdWlyZWQgZm9yIFtlbmQgdXNlcnNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycykgaWYgdGhlIGBwcm9qZWN0YCBpcyBzcGVjaWZpZWQgYW5kIGlmIHRoZSBlbmQgdXNlcnMgYXJlIG1lbWJlcnMgb2YgbXVsdGlwbGUgW2dyb3Vwc10oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcyksIG90aGVyd2lzZSBvcHRpb25hbC5cbiAgICAqL1xuICAgIGxvZ2luOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgIHZhciBzZXNzaW9uTWFuYWdlciA9IHRoaXMuc2Vzc2lvbk1hbmFnZXI7XG4gICAgICAgIHZhciBhZGFwdGVyT3B0aW9ucyA9IHNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoeyBzdWNjZXNzOiAkLm5vb3AsIGVycm9yOiAkLm5vb3AgfSwgb3B0aW9ucyk7XG4gICAgICAgIHZhciBvdXRTdWNjZXNzID0gYWRhcHRlck9wdGlvbnMuc3VjY2VzcztcbiAgICAgICAgdmFyIG91dEVycm9yID0gYWRhcHRlck9wdGlvbnMuZXJyb3I7XG4gICAgICAgIHZhciBncm91cElkID0gYWRhcHRlck9wdGlvbnMuZ3JvdXBJZDtcblxuICAgICAgICB2YXIgZGVjb2RlVG9rZW4gPSBmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgICAgICAgIHZhciBlbmNvZGVkID0gdG9rZW4uc3BsaXQoJy4nKVsxXTtcbiAgICAgICAgICAgIHdoaWxlIChlbmNvZGVkLmxlbmd0aCAlIDQgIT09IDApIHtcbiAgICAgICAgICAgICAgICBlbmNvZGVkICs9ICc9JztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGRlY29kZSA9IHdpbmRvdy5hdG9iID8gd2luZG93LmF0b2IgOiBmdW5jdGlvbiAoZW5jb2RlZCkgeyByZXR1cm4gbmV3IEJ1ZmZlcihlbmNvZGVkLCAnYmFzZTY0JykudG9TdHJpbmcoJ2FzY2lpJyk7IH07XG5cbiAgICAgICAgICAgIHJldHVybiBKU09OLnBhcnNlKGRlY29kZShlbmNvZGVkKSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIGhhbmRsZUdyb3VwRXJyb3IgPSBmdW5jdGlvbiAobWVzc2FnZSwgc3RhdHVzQ29kZSwgZGF0YSkge1xuICAgICAgICAgICAgLy8gbG9nb3V0IHRoZSB1c2VyIHNpbmNlIGl0J3MgaW4gYW4gaW52YWxpZCBzdGF0ZSB3aXRoIG5vIGdyb3VwIHNlbGVjdGVkXG4gICAgICAgICAgICBfdGhpcy5sb2dvdXQoKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB2YXIgZXJyb3IgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGF0YSwgeyBzdGF0dXNUZXh0OiBtZXNzYWdlLCBzdGF0dXM6IHN0YXR1c0NvZGUgfSk7XG4gICAgICAgICAgICAgICAgJGQucmVqZWN0KGVycm9yKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIHZhciBoYW5kbGVTdWNjZXNzID0gZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICAvL2pzaGludCBjYW1lbGNhc2U6IGZhbHNlXG4gICAgICAgICAgICAvL2pzY3M6ZGlzYWJsZVxuICAgICAgICAgICAgdmFyIHRva2VuID0gcmVzcG9uc2UuYWNjZXNzX3Rva2VuO1xuICAgICAgICAgICAgdmFyIHVzZXJJbmZvID0gZGVjb2RlVG9rZW4odG9rZW4pO1xuICAgICAgICAgICAgdmFyIG9sZEdyb3VwcyA9IHNlc3Npb25NYW5hZ2VyLmdldFNlc3Npb24oKS5ncm91cHMgfHwge307XG4gICAgICAgICAgICB2YXIgdXNlckdyb3VwT3B0cyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBhZGFwdGVyT3B0aW9ucywgeyBzdWNjZXNzOiAkLm5vb3AgfSk7XG4gICAgICAgICAgICB2YXIgZGF0YSA9IHsgYXV0aDogcmVzcG9uc2UsIHVzZXI6IHVzZXJJbmZvIH07XG4gICAgICAgICAgICB2YXIgcHJvamVjdCA9IGFkYXB0ZXJPcHRpb25zLnByb2plY3Q7XG4gICAgICAgICAgICB2YXIgaXNUZWFtTWVtYmVyID0gdXNlckluZm8ucGFyZW50X2FjY291bnRfaWQgPT09IG51bGw7XG4gICAgICAgICAgICB2YXIgcmVxdWlyZXNHcm91cCA9IGFkYXB0ZXJPcHRpb25zLnJlcXVpcmVzR3JvdXAgJiYgcHJvamVjdDtcblxuICAgICAgICAgICAgdmFyIHNlc3Npb25JbmZvID0ge1xuICAgICAgICAgICAgICAgICdhdXRoX3Rva2VuJzogdG9rZW4sXG4gICAgICAgICAgICAgICAgJ2FjY291bnQnOiBhZGFwdGVyT3B0aW9ucy5hY2NvdW50LFxuICAgICAgICAgICAgICAgICdwcm9qZWN0JzogcHJvamVjdCxcbiAgICAgICAgICAgICAgICAndXNlcklkJzogdXNlckluZm8udXNlcl9pZCxcbiAgICAgICAgICAgICAgICAnZ3JvdXBzJzogb2xkR3JvdXBzLFxuICAgICAgICAgICAgICAgICdpc1RlYW1NZW1iZXInOiBpc1RlYW1NZW1iZXJcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICAvLyBUaGUgZ3JvdXAgaXMgbm90IHJlcXVpcmVkIGlmIHRoZSB1c2VyIGlzIG5vdCBsb2dnaW5nIGludG8gYSBwcm9qZWN0XG4gICAgICAgICAgICBpZiAoIXJlcXVpcmVzR3JvdXApIHtcbiAgICAgICAgICAgICAgICBzZXNzaW9uTWFuYWdlci5zYXZlU2Vzc2lvbihzZXNzaW9uSW5mbyk7XG4gICAgICAgICAgICAgICAgb3V0U3VjY2Vzcy5hcHBseSh0aGlzLCBbZGF0YV0pO1xuICAgICAgICAgICAgICAgICRkLnJlc29sdmUoZGF0YSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBfdGhpcy5nZXRVc2VyR3JvdXBzKHsgdXNlcklkOiB1c2VySW5mby51c2VyX2lkLCB0b2tlbjogdG9rZW4gfSwgdXNlckdyb3VwT3B0cykuZG9uZShmdW5jdGlvbiAobWVtYmVySW5mbykge1xuICAgICAgICAgICAgICAgIGRhdGEudXNlckdyb3VwcyA9IG1lbWJlckluZm87XG5cbiAgICAgICAgICAgICAgICB2YXIgZ3JvdXAgPSBudWxsO1xuICAgICAgICAgICAgICAgIGlmIChtZW1iZXJJbmZvLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICBoYW5kbGVHcm91cEVycm9yKCdUaGUgdXNlciBoYXMgbm8gZ3JvdXBzIGFzc29jaWF0ZWQgaW4gdGhpcyBhY2NvdW50JywgNDAxLCBkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAobWVtYmVySW5mby5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gU2VsZWN0IHRoZSBvbmx5IGdyb3VwXG4gICAgICAgICAgICAgICAgICAgIGdyb3VwID0gbWVtYmVySW5mb1swXTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKG1lbWJlckluZm8ubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZ3JvdXBJZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZpbHRlcmVkR3JvdXBzID0gJC5ncmVwKG1lbWJlckluZm8sIGZ1bmN0aW9uIChyZXNHcm91cCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiByZXNHcm91cC5ncm91cElkID09PSBncm91cElkO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IGZpbHRlcmVkR3JvdXBzLmxlbmd0aCA9PT0gMSA/IGZpbHRlcmVkR3JvdXBzWzBdIDogbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmIChncm91cCkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZ3JvdXBEYXRhID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgJ2dyb3VwSWQnOiBncm91cC5ncm91cElkLFxuICAgICAgICAgICAgICAgICAgICAgICAgJ2dyb3VwTmFtZSc6IGdyb3VwLm5hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAnaXNGYWMnOiBfZmluZFVzZXJJbkdyb3VwKGdyb3VwLm1lbWJlcnMsIHVzZXJJbmZvLnVzZXJfaWQpLnJvbGUgPT09ICdmYWNpbGl0YXRvcidcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHNlc3Npb25JbmZvV2l0aEdyb3VwID0gJC5leHRlbmQoe30sIHNlc3Npb25JbmZvLCBncm91cERhdGEpO1xuICAgICAgICAgICAgICAgICAgICBzZXNzaW9uSW5mby5ncm91cHNbcHJvamVjdF0gPSBncm91cERhdGE7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLnNlc3Npb25NYW5hZ2VyLnNhdmVTZXNzaW9uKHNlc3Npb25JbmZvV2l0aEdyb3VwLCBhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW2RhdGFdKTtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBoYW5kbGVHcm91cEVycm9yKCdUaGlzIHVzZXIgaXMgYXNzb2NpYXRlZCB3aXRoIG1vcmUgdGhhbiBvbmUgZ3JvdXAuIFBsZWFzZSBzcGVjaWZ5IGEgZ3JvdXAgaWQgdG8gbG9nIGludG8gYW5kIHRyeSBhZ2FpbicsIDQwMywgZGF0YSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSkuZmFpbCgkZC5yZWplY3QpO1xuICAgICAgICB9O1xuXG4gICAgICAgIGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3MgPSBoYW5kbGVTdWNjZXNzO1xuICAgICAgICBhZGFwdGVyT3B0aW9ucy5lcnJvciA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgaWYgKGFkYXB0ZXJPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgICAgICAgICAvLyBUcnkgdG8gbG9naW4gYXMgYSBzeXN0ZW0gdXNlclxuICAgICAgICAgICAgICAgIGFkYXB0ZXJPcHRpb25zLmFjY291bnQgPSBudWxsO1xuICAgICAgICAgICAgICAgIGFkYXB0ZXJPcHRpb25zLmVycm9yID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICBvdXRFcnJvci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAkZC5yZWplY3QocmVzcG9uc2UpO1xuICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICBfdGhpcy5hdXRoQWRhcHRlci5sb2dpbihhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBvdXRFcnJvci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgJGQucmVqZWN0KHJlc3BvbnNlKTtcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLmF1dGhBZGFwdGVyLmxvZ2luKGFkYXB0ZXJPcHRpb25zKTtcbiAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgKiBMb2dzIHVzZXIgb3V0IGJ5IGNsZWFyaW5nIGFsbCBzZXNzaW9uIGluZm9ybWF0aW9uLlxuICAgICpcbiAgICAqICoqRXhhbXBsZSoqXG4gICAgKlxuICAgICogICAgICAgYXV0aE1nci5sb2dvdXQoKTtcbiAgICAqXG4gICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICpcbiAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAqL1xuICAgIGxvZ291dDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIGFkYXB0ZXJPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciByZW1vdmVDb29raWVGbiA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgX3RoaXMuc2Vzc2lvbk1hbmFnZXIucmVtb3ZlU2Vzc2lvbigpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiB0aGlzLmF1dGhBZGFwdGVyLmxvZ291dChhZGFwdGVyT3B0aW9ucykuZG9uZShyZW1vdmVDb29raWVGbik7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGV4aXN0aW5nIHVzZXIgYWNjZXNzIHRva2VuIGlmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluLiBPdGhlcndpc2UsIGxvZ3MgdGhlIHVzZXIgaW4sIGNyZWF0aW5nIGEgbmV3IHVzZXIgYWNjZXNzIHRva2VuLCBhbmQgcmV0dXJucyB0aGUgbmV3IHRva2VuLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBhdXRoTWdyLmdldFRva2VuKClcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgKiAgICAgICAgICAgICAgY29uc29sZS5sb2coJ015IHRva2VuIGlzICcsIHRva2VuKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldFRva2VuOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMob3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldFNlc3Npb24oKTtcbiAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAvL2pzaGludCBjYW1lbGNhc2U6IGZhbHNlXG4gICAgICAgIC8vanNjczpkaXNhYmxlXG4gICAgICAgIGlmIChzZXNzaW9uLmF1dGhfdG9rZW4pIHtcbiAgICAgICAgICAgICRkLnJlc29sdmUoc2Vzc2lvbi5hdXRoX3Rva2VuKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMubG9naW4oaHR0cE9wdGlvbnMpLnRoZW4oJGQucmVzb2x2ZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhbiBhcnJheSBvZiBncm91cCByZWNvcmRzLCBvbmUgZm9yIGVhY2ggZ3JvdXAgb2Ygd2hpY2ggdGhlIGN1cnJlbnQgdXNlciBpcyBhIG1lbWJlci4gRWFjaCBncm91cCByZWNvcmQgaW5jbHVkZXMgdGhlIGdyb3VwIGBuYW1lYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgZ3JvdXBJZGAuXG4gICAgICpcbiAgICAgKiBJZiBzb21lIGVuZCB1c2VycyBpbiB5b3VyIHByb2plY3QgYXJlIG1lbWJlcnMgb2YgbXVsdGlwbGUgZ3JvdXBzLCB0aGlzIGlzIGEgdXNlZnVsIG1ldGhvZCB0byBjYWxsIG9uIHlvdXIgcHJvamVjdCdzIGxvZ2luIHBhZ2UuIFdoZW4gdGhlIHVzZXIgYXR0ZW1wdHMgdG8gbG9nIGluLCB5b3UgY2FuIHVzZSB0aGlzIHRvIGRpc3BsYXkgdGhlIGdyb3VwcyBvZiB3aGljaCB0aGUgdXNlciBpcyBtZW1iZXIsIGFuZCBoYXZlIHRoZSB1c2VyIHNlbGVjdCB0aGUgY29ycmVjdCBncm91cCB0byBsb2cgaW4gdG8gZm9yIHRoaXMgc2Vzc2lvbi5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIGN1cnJlbnQgdXNlclxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKiAgICAgIGF1dGhNZ3IuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogc2Vzc2lvbk9iai51c2VySWQsIHRva2VuOiBzZXNzaW9uT2JqLmF1dGhfdG9rZW4gfSlcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAoZ3JvdXBzKSB7XG4gICAgICogICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IGdyb3Vwcy5sZW5ndGg7IGkrKylcbiAgICAgKiAgICAgICAgICAgICAgICAgIHsgY29uc29sZS5sb2coZ3JvdXBzW2ldLm5hbWUpOyB9XG4gICAgICogICAgICAgICAgfSk7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIHBhcnRpY3VsYXIgdXNlclxuICAgICAqICAgICAgYXV0aE1nci5nZXRVc2VyR3JvdXBzKHt1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB0b2tlbjogc2F2ZWRQcm9qQWNjZXNzVG9rZW4gfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgcGFyYW1zYCBPYmplY3Qgd2l0aCBhIHVzZXJJZCBhbmQgdG9rZW4gcHJvcGVydGllcy5cbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gYHBhcmFtcy51c2VySWRgIFRoZSB1c2VySWQuIElmIGxvb2tpbmcgdXAgZ3JvdXBzIGZvciB0aGUgY3VycmVudGx5IGxvZ2dlZCBpbiB1c2VyLCB0aGlzIGlzIGluIHRoZSBzZXNzaW9uIGluZm9ybWF0aW9uLiBPdGhlcndpc2UsIHBhc3MgYSBzdHJpbmcuXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IGBwYXJhbXMudG9rZW5gIFRoZSBhdXRob3JpemF0aW9uIGNyZWRlbnRpYWxzIChhY2Nlc3MgdG9rZW4pIHRvIHVzZSBmb3IgY2hlY2tpbmcgdGhlIGdyb3VwcyBmb3IgdGhpcyB1c2VyLiBJZiBsb29raW5nIHVwIGdyb3VwcyBmb3IgdGhlIGN1cnJlbnRseSBsb2dnZWQgaW4gdXNlciwgdGhpcyBpcyBpbiB0aGUgc2Vzc2lvbiBpbmZvcm1hdGlvbi4gQSB0ZWFtIG1lbWJlcidzIHRva2VuIG9yIGEgcHJvamVjdCBhY2Nlc3MgdG9rZW4gY2FuIGFjY2VzcyBhbGwgdGhlIGdyb3VwcyBmb3IgYWxsIGVuZCB1c2VycyBpbiB0aGUgdGVhbSBvciBwcm9qZWN0LlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgKi9cbiAgICBnZXRVc2VyR3JvdXBzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBhZGFwdGVyT3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyh7IHN1Y2Nlc3M6ICQubm9vcCB9LCBvcHRpb25zKTtcbiAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgb3V0U3VjY2VzcyA9IGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3M7XG5cbiAgICAgICAgYWRhcHRlck9wdGlvbnMuc3VjY2VzcyA9IGZ1bmN0aW9uIChtZW1iZXJJbmZvKSB7XG4gICAgICAgICAgICAvLyBUaGUgbWVtYmVyIEFQSSBpcyBhdCB0aGUgYWNjb3VudCBzY29wZSwgd2UgZmlsdGVyIGJ5IHByb2plY3RcbiAgICAgICAgICAgIGlmIChhZGFwdGVyT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgbWVtYmVySW5mbyA9ICQuZ3JlcChtZW1iZXJJbmZvLCBmdW5jdGlvbiAoZ3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGdyb3VwLnByb2plY3QgPT09IGFkYXB0ZXJPcHRpb25zLnByb2plY3Q7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW21lbWJlckluZm9dKTtcbiAgICAgICAgICAgICRkLnJlc29sdmUobWVtYmVySW5mbyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIG1lbWJlckFkYXB0ZXIgPSBuZXcgTWVtYmVyQWRhcHRlcih7IHRva2VuOiBwYXJhbXMudG9rZW4gfSk7XG4gICAgICAgIG1lbWJlckFkYXB0ZXIuZ2V0R3JvdXBzRm9yVXNlcihwYXJhbXMsIGFkYXB0ZXJPcHRpb25zKS5mYWlsKCRkLnJlamVjdCk7XG4gICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgc2Vzc2lvbiBpbmZvcm1hdGlvbiBmb3IgdGhlIGN1cnJlbnQgdXNlciwgaW5jbHVkaW5nIHRoZSBgdXNlcklkYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGBncm91cElkYCwgYGdyb3VwTmFtZWAsIGBpc0ZhY2AgKHdoZXRoZXIgdGhlIGVuZCB1c2VyIGlzIGEgZmFjaWxpdGF0b3Igb2YgdGhpcyBncm91cCksIGFuZCBgYXV0aF90b2tlbmAgKHVzZXIgYWNjZXNzIHRva2VuKS5cbiAgICAgKlxuICAgICAqICpJbXBvcnRhbnQqOiBUaGlzIG1ldGhvZCBpcyBzeW5jaHJvbm91cy4gVGhlIHNlc3Npb24gaW5mb3JtYXRpb24gaXMgcmV0dXJuZWQgaW1tZWRpYXRlbHkgaW4gYW4gb2JqZWN0OyBubyBjYWxsYmFja3Mgb3IgcHJvbWlzZXMgYXJlIG5lZWRlZC5cbiAgICAgKlxuICAgICAqIFNlc3Npb24gaW5mb3JtYXRpb24gaXMgc3RvcmVkIGluIGEgY29va2llIGluIHRoZSBicm93c2VyLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm86IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldFNlc3Npb24ob3B0aW9ucyk7XG4gICAgfSxcblxuICAgIC8vIChyZXBsYWNlIHdpdGggLyogKi8gY29tbWVudCBibG9jaywgdG8gbWFrZSB2aXNpYmxlIGluIGRvY3MsIG9uY2UgRVBJQ0VOVEVSLTE5MzkgaXMgY29tcGxldGUpXG4gICAgLy9cbiAgICAvLyBBZGQgb25lIG9yIG1vcmUgZ3JvdXBzIHRvIHRoZSBjdXJyZW50IHNlc3Npb24uIFxuICAgIC8vXG4gICAgLy8gVGhpcyBtZXRob2QgYXNzdW1lcyB0aGF0IHRoZSBwcm9qZWN0IGFuZCBncm91cCBleGlzdCBhbmQgdGhlIHVzZXIgc3BlY2lmaWVkIGluIHRoZSBzZXNzaW9uIGlzIHBhcnQgb2YgdGhpcyBwcm9qZWN0IGFuZCBncm91cC5cbiAgICAvL1xuICAgIC8vIFJldHVybnMgdGhlIG5ldyBzZXNzaW9uIG9iamVjdC5cbiAgICAvL1xuICAgIC8vICoqRXhhbXBsZSoqXG4gICAgLy9cbiAgICAvLyAgICAgIGF1dGhNZ3IuYWRkR3JvdXBzKHsgcHJvamVjdDogJ2hlbGxvLXdvcmxkJywgZ3JvdXBOYW1lOiAnZ3JvdXBOYW1lJywgZ3JvdXBJZDogJ2dyb3VwSWQnIH0pO1xuICAgIC8vICAgICAgYXV0aE1nci5hZGRHcm91cHMoW3sgcHJvamVjdDogJ2hlbGxvLXdvcmxkJywgZ3JvdXBOYW1lOiAnZ3JvdXBOYW1lJywgZ3JvdXBJZDogJ2dyb3VwSWQnIH0sIHsgcHJvamVjdDogLi4uIH1dKTtcbiAgICAvL1xuICAgIC8vICoqUGFyYW1ldGVycyoqXG4gICAgLy8gQHBhcmFtIHtvYmplY3R8YXJyYXl9IGBncm91cHNgIChSZXF1aXJlZCkgVGhlIGdyb3VwIG9iamVjdCBtdXN0IGNvbnRhaW4gdGhlIGBwcm9qZWN0YCAoKipQcm9qZWN0IElEKiopIGFuZCBgZ3JvdXBOYW1lYCBwcm9wZXJ0aWVzLlxuICAgIC8vIEBwYXJhbSB7c3RyaW5nfSBgZ3JvdXAuaXNGYWNgIChvcHRpb25hbCkgRGVmYXVsdHMgdG8gYGZhbHNlYC4gU2V0IHRvIGB0cnVlYCBpZiB0aGUgdXNlciBpbiB0aGUgc2Vzc2lvbiBzaG91bGQgYmUgYSBmYWNpbGl0YXRvciBpbiB0aGlzIGdyb3VwLlxuICAgIC8vIEBwYXJhbSB7c3RyaW5nfSBgZ3JvdXAuZ3JvdXBJZGAgKG9wdGlvbmFsKSBEZWZhdWx0cyB0byB1bmRlZmluZWQuIE5lZWRlZCBtb3N0bHkgZm9yIHRoZSBNZW1iZXJzIEFQSS5cbiAgICAvL1xuICAgIGFkZEdyb3VwczogZnVuY3Rpb24gKGdyb3Vwcykge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICB2YXIgaXNBcnJheSA9IEFycmF5LmlzQXJyYXkoZ3JvdXBzKTtcbiAgICAgICAgZ3JvdXBzID0gaXNBcnJheSA/IGdyb3VwcyA6IFtncm91cHNdO1xuXG4gICAgICAgICQuZWFjaChncm91cHMsIGZ1bmN0aW9uIChpbmRleCwgZ3JvdXApIHtcbiAgICAgICAgICAgIHZhciBleHRlbmRlZEdyb3VwID0gJC5leHRlbmQoe30sIHsgaXNGYWM6IGZhbHNlIH0sIGdyb3VwKTtcbiAgICAgICAgICAgIHZhciBwcm9qZWN0ID0gZXh0ZW5kZWRHcm91cC5wcm9qZWN0O1xuICAgICAgICAgICAgdmFyIHZhbGlkUHJvcHMgPSBbJ2dyb3VwTmFtZScsICdncm91cElkJywgJ2lzRmFjJ107XG4gICAgICAgICAgICBpZiAoIXByb2plY3QgfHwgIWV4dGVuZGVkR3JvdXAuZ3JvdXBOYW1lKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBwcm9qZWN0IG9yIGdyb3VwTmFtZSBzcGVjaWZpZWQuJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBmaWx0ZXIgb2JqZWN0XG4gICAgICAgICAgICBleHRlbmRlZEdyb3VwID0gX3BpY2soZXh0ZW5kZWRHcm91cCwgdmFsaWRQcm9wcyk7XG4gICAgICAgICAgICBzZXNzaW9uLmdyb3Vwc1twcm9qZWN0XSA9IGV4dGVuZGVkR3JvdXA7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnNlc3Npb25NYW5hZ2VyLnNhdmVTZXNzaW9uKHNlc3Npb24pO1xuICAgICAgICByZXR1cm4gc2Vzc2lvbjtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBBdXRoTWFuYWdlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENoYW5uZWwgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL2NoYW5uZWwtc2VydmljZScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG5cbi8qKlxuICogIyMgQ2hhbm5lbCBNYW5hZ2VyXG4gKlxuICogVGhlcmUgYXJlIHR3byBtYWluIHVzZSBjYXNlcyBmb3IgdGhlIGNoYW5uZWw6IGV2ZW50IG5vdGlmaWNhdGlvbnMgYW5kIGNoYXQgbWVzc2FnZXMuXG4gKlxuICogVGhlIENoYW5uZWwgTWFuYWdlciBpcyBhIHdyYXBwZXIgYXJvdW5kIHRoZSBkZWZhdWx0IFtjb21ldGQgSmF2YVNjcmlwdCBsaWJyYXJ5XShodHRwOi8vZG9jcy5jb21ldGQub3JnLzIvcmVmZXJlbmNlL2phdmFzY3JpcHQuaHRtbCksIGAkLmNvbWV0ZGAuIEl0IHByb3ZpZGVzIGEgZmV3IG5pY2UgZmVhdHVyZXMgdGhhdCBgJC5jb21ldGRgIGRvZXNuJ3QsIGluY2x1ZGluZzpcbiAqXG4gKiAqIEF1dG9tYXRpYyByZS1zdWJzY3JpcHRpb24gdG8gY2hhbm5lbHMgaWYgeW91IGxvc2UgeW91ciBjb25uZWN0aW9uXG4gKiAqIE9ubGluZSAvIE9mZmxpbmUgbm90aWZpY2F0aW9uc1xuICogKiAnRXZlbnRzJyBmb3IgY29tZXRkIG5vdGlmaWNhdGlvbnMgKGluc3RlYWQgb2YgaGF2aW5nIHRvIGxpc3RlbiBvbiBzcGVjaWZpYyBtZXRhIGNoYW5uZWxzKVxuICpcbiAqIFdoaWxlIHlvdSBjYW4gd29yayBkaXJlY3RseSB3aXRoIHRoZSBDaGFubmVsIE1hbmFnZXIgdGhyb3VnaCBOb2RlLmpzIChmb3IgZXhhbXBsZSwgYHJlcXVpcmUoJ21hbmFnZXIvY2hhbm5lbC1tYW5hZ2VyJylgKSAtLSBvciBldmVuIHdvcmsgZGlyZWN0bHkgd2l0aCBgJC5jb21ldGRgIGFuZCBFcGljZW50ZXIncyB1bmRlcmx5aW5nIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIC0tIG1vc3Qgb2Z0ZW4gaXQgd2lsbCBiZSBlYXNpZXN0IHRvIHdvcmsgd2l0aCB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKS4gVGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaXMgYSB3cmFwcGVyIHRoYXQgaW5zdGFudGlhdGVzIGEgQ2hhbm5lbCBNYW5hZ2VyIHdpdGggRXBpY2VudGVyLXNwZWNpZmljIGRlZmF1bHRzLlxuICpcbiAqIFlvdSdsbCBuZWVkIHRvIGluY2x1ZGUgdGhlIGBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzYCBsaWJyYXJ5IGluIGFkZGl0aW9uIHRvIHRoZSBgZXBpY2VudGVyLmpzYCBsaWJyYXJ5IGluIHlvdXIgcHJvamVjdCB0byB1c2UgdGhlIENoYW5uZWwgTWFuYWdlci4gKFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLilcbiAqXG4gKiBUbyB1c2UgdGhlIENoYW5uZWwgTWFuYWdlciBpbiBjbGllbnQtc2lkZSBKYXZhU2NyaXB0LCBpbnN0YW50aWF0ZSB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKSwgZ2V0IHRoZSBjaGFubmVsLCB0aGVuIHVzZSB0aGUgY2hhbm5lbCdzIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gc3Vic2NyaWJlIHRvIHRvcGljcyBvciBwdWJsaXNoIGRhdGEgdG8gdG9waWNzLlxuICpcbiAqICAgICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gKiAgICAgICAgdmFyIGNoYW5uZWwgPSBjbS5nZXRDaGFubmVsKCk7XG4gKlxuICogICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCd0b3BpYycsIGNhbGxiYWNrKTtcbiAqICAgICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIFRoZSBvcHRpb25zIG9iamVjdCB0byBjb25maWd1cmUgdGhlIENoYW5uZWwgTWFuYWdlci4gQmVzaWRlcyB0aGUgY29tbW9uIG9wdGlvbnMgbGlzdGVkIGhlcmUsIHNlZSBodHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0Lmh0bWwgZm9yIG90aGVyIHN1cHBvcnRlZCBvcHRpb25zLlxuICogKiBgb3B0aW9ucy51cmxgIFRoZSBDb21ldGQgZW5kcG9pbnQgVVJMLlxuICogKiBgb3B0aW9ucy53ZWJzb2NrZXRFbmFibGVkYCBXaGV0aGVyIHdlYnNvY2tldCBzdXBwb3J0IGlzIGFjdGl2ZSAoYm9vbGVhbikuXG4gKiAqIGBvcHRpb25zLmNoYW5uZWxgIE90aGVyIGRlZmF1bHRzIHRvIHBhc3Mgb24gdG8gaW5zdGFuY2VzIG9mIHRoZSB1bmRlcmx5aW5nIENoYW5uZWwgU2VydmljZS4gU2VlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pIGZvciBkZXRhaWxzLlxuICpcbiAqL1xudmFyIENoYW5uZWxNYW5hZ2VyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICBpZiAoISQuY29tZXRkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignQ29tZXRkIGxpYnJhcnkgbm90IGZvdW5kLiBQbGVhc2UgaW5jbHVkZSBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzJyk7XG4gICAgfVxuICAgIGlmICghb3B0aW9ucyB8fCAhb3B0aW9ucy51cmwpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhbiB1cmwgZm9yIHRoZSBjb21ldGQgc2VydmVyJyk7XG4gICAgfVxuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIENvbWV0ZCBlbmRwb2ludCBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1cmw6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbG9nIGxldmVsIGZvciB0aGUgY2hhbm5lbCAobG9ncyB0byBjb25zb2xlKS5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGxvZ0xldmVsOiAnaW5mbycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFdoZXRoZXIgd2Vic29ja2V0IHN1cHBvcnQgaXMgYWN0aXZlLiBEZWZhdWx0cyB0byBgZmFsc2VgOyBFcGljZW50ZXIgZG9lc24ndCBjdXJyZW50bHkgc3VwcG9ydCBjb21tdW5pY2F0aW9uIHRocm91Z2ggd2Vic29ja2V0cy5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICB3ZWJzb2NrZXRFbmFibGVkOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogSWYgZmFsc2UgZWFjaCBpbnN0YW5jZSBvZiBDaGFubmVsIHdpbGwgaGF2ZSBhIHNlcGFyYXRlIGNvbWV0ZCBjb25uZWN0aW9uIHRvIHNlcnZlciwgd2hpY2ggY291bGQgYmUgbm9pc3kuIFNldCB0byB0cnVlIHRvIHJlLXVzZSB0aGUgc2FtZSBjb25uZWN0aW9uIGFjcm9zcyBpbnN0YW5jZXMuXG4gICAgICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAgICAgKi9cbiAgICAgICAgc2hhcmVDb25uZWN0aW9uOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3RoZXIgZGVmYXVsdHMgdG8gcGFzcyBvbiB0byBpbnN0YW5jZXMgb2YgdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLyksIHdoaWNoIGFyZSBjcmVhdGVkIHRocm91Z2ggYGdldENoYW5uZWwoKWAuXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBjaGFubmVsOiB7XG5cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIHRvIHRoZSBjaGFubmVsIGhhbmRzaGFrZS5cbiAgICAgICAgICpcbiAgICAgICAgICogRm9yIGV4YW1wbGUsIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pIHBhc3NlcyBgZXh0YCBhbmQgYXV0aG9yaXphdGlvbiBpbmZvcm1hdGlvbi4gTW9yZSBpbmZvcm1hdGlvbiBvbiBwb3NzaWJsZSBvcHRpb25zIGlzIGluIHRoZSBkZXRhaWxzIG9mIHRoZSB1bmRlcmx5aW5nIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgaGFuZHNoYWtlOiB1bmRlZmluZWRcbiAgICB9O1xuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgZGVmYXVsdENvbWV0T3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyhkZWZhdWx0cywgb3B0aW9ucyk7XG4gICAgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucyA9IFtdO1xuICAgIHRoaXMub3B0aW9ucyA9IGRlZmF1bHRDb21ldE9wdGlvbnM7XG5cbiAgICBpZiAoZGVmYXVsdENvbWV0T3B0aW9ucy5zaGFyZUNvbm5lY3Rpb24gJiYgQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQpIHtcbiAgICAgICAgdGhpcy5jb21ldGQgPSBDaGFubmVsTWFuYWdlci5wcm90b3R5cGUuX2NvbWV0ZDtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuICAgIHZhciBjb21ldGQgPSBuZXcgJC5Db21ldGQoKTtcbiAgICBDaGFubmVsTWFuYWdlci5wcm90b3R5cGUuX2NvbWV0ZCA9IGNvbWV0ZDtcblxuICAgIGNvbWV0ZC53ZWJzb2NrZXRFbmFibGVkID0gZGVmYXVsdENvbWV0T3B0aW9ucy53ZWJzb2NrZXRFbmFibGVkO1xuXG4gICAgdGhpcy5pc0Nvbm5lY3RlZCA9IGZhbHNlO1xuICAgIHZhciBjb25uZWN0aW9uQnJva2VuID0gZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyKCdkaXNjb25uZWN0JywgbWVzc2FnZSk7XG4gICAgfTtcbiAgICB2YXIgY29ubmVjdGlvblN1Y2NlZWRlZCA9IGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQodGhpcykudHJpZ2dlcignY29ubmVjdCcsIG1lc3NhZ2UpO1xuICAgIH07XG4gICAgdmFyIG1lID0gdGhpcztcblxuICAgIGNvbWV0ZC5jb25maWd1cmUoZGVmYXVsdENvbWV0T3B0aW9ucyk7XG5cbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL2Nvbm5lY3QnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICB2YXIgd2FzQ29ubmVjdGVkID0gdGhpcy5pc0Nvbm5lY3RlZDtcbiAgICAgICAgdGhpcy5pc0Nvbm5lY3RlZCA9IChtZXNzYWdlLnN1Y2Nlc3NmdWwgPT09IHRydWUpO1xuICAgICAgICBpZiAoIXdhc0Nvbm5lY3RlZCAmJiB0aGlzLmlzQ29ubmVjdGVkKSB7IC8vQ29ubmVjdGluZyBmb3IgdGhlIGZpcnN0IHRpbWVcbiAgICAgICAgICAgIGNvbm5lY3Rpb25TdWNjZWVkZWQuY2FsbCh0aGlzLCBtZXNzYWdlKTtcbiAgICAgICAgfSBlbHNlIGlmICh3YXNDb25uZWN0ZWQgJiYgIXRoaXMuaXNDb25uZWN0ZWQpIHsgLy9Pbmx5IHRocm93IGRpc2Nvbm5lY3RlZCBtZXNzYWdlIGZybyB0aGUgZmlyc3QgZGlzY29ubmVjdCwgbm90IG9uY2UgcGVyIHRyeVxuICAgICAgICAgICAgY29ubmVjdGlvbkJyb2tlbi5jYWxsKHRoaXMsIG1lc3NhZ2UpO1xuICAgICAgICB9XG4gICAgfS5iaW5kKHRoaXMpKTtcblxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvZGlzY29ubmVjdCcsIGNvbm5lY3Rpb25Ccm9rZW4pO1xuXG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9oYW5kc2hha2UnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICBpZiAobWVzc2FnZS5zdWNjZXNzZnVsKSB7XG4gICAgICAgICAgICAvL2h0dHA6Ly9kb2NzLmNvbWV0ZC5vcmcvcmVmZXJlbmNlL2phdmFzY3JpcHRfc3Vic2NyaWJlLmh0bWwjamF2YXNjcmlwdF9zdWJzY3JpYmVfbWV0YV9jaGFubmVsc1xuICAgICAgICAgICAgLy8gXiBcImR5bmFtaWMgc3Vic2NyaXB0aW9ucyBhcmUgY2xlYXJlZCAobGlrZSBhbnkgb3RoZXIgc3Vic2NyaXB0aW9uKSBhbmQgdGhlIGFwcGxpY2F0aW9uIG5lZWRzIHRvIGZpZ3VyZSBvdXQgd2hpY2ggZHluYW1pYyBzdWJzY3JpcHRpb24gbXVzdCBiZSBwZXJmb3JtZWQgYWdhaW5cIlxuICAgICAgICAgICAgY29tZXRkLmJhdGNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAkKG1lLmN1cnJlbnRTdWJzY3JpcHRpb25zKS5lYWNoKGZ1bmN0aW9uIChpbmRleCwgc3Vicykge1xuICAgICAgICAgICAgICAgICAgICBjb21ldGQucmVzdWJzY3JpYmUoc3Vicyk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgLy9PdGhlciBpbnRlcmVzdGluZyBldmVudHMgZm9yIHJlZmVyZW5jZVxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvc3Vic2NyaWJlJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJChtZSkudHJpZ2dlcignc3Vic2NyaWJlJywgbWVzc2FnZSk7XG4gICAgfSk7XG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS91bnN1YnNjcmliZScsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3Vuc3Vic2NyaWJlJywgbWVzc2FnZSk7XG4gICAgfSk7XG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9wdWJsaXNoJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJChtZSkudHJpZ2dlcigncHVibGlzaCcsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvdW5zdWNjZXNzZnVsJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJChtZSkudHJpZ2dlcignZXJyb3InLCBtZXNzYWdlKTtcbiAgICB9KTtcblxuICAgIGNvbWV0ZC5oYW5kc2hha2UoZGVmYXVsdENvbWV0T3B0aW9ucy5oYW5kc2hha2UpO1xuXG4gICAgdGhpcy5jb21ldGQgPSBjb21ldGQ7XG59O1xuXG5cbkNoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZSA9ICQuZXh0ZW5kKENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZSwge1xuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbmQgcmV0dXJucyBhIGNoYW5uZWwsIHRoYXQgaXMsIGFuIGluc3RhbmNlIG9mIGEgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgICB2YXIgY2hhbm5lbCA9IGNtLmdldENoYW5uZWwoKTtcbiAgICAgKlxuICAgICAqICAgICAgY2hhbm5lbC5zdWJzY3JpYmUoJ3RvcGljJywgY2FsbGJhY2spO1xuICAgICAqICAgICAgY2hhbm5lbC5wdWJsaXNoKCd0b3BpYycsIHsgbXlEYXRhOiAxMDAgfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fFN0cmluZ30gYG9wdGlvbnNgIChPcHRpb25hbCkgSWYgc3RyaW5nLCBhc3N1bWVkIHRvIGJlIHRoZSBiYXNlIGNoYW5uZWwgdXJsLiBJZiBvYmplY3QsIGFzc3VtZWQgdG8gYmUgY29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgY29uc3RydWN0b3IuXG4gICAgICovXG4gICAgZ2V0Q2hhbm5lbDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgLy9JZiB5b3UganVzdCB3YW50IHRvIHBhc3MgaW4gYSBzdHJpbmdcbiAgICAgICAgaWYgKG9wdGlvbnMgJiYgISQuaXNQbGFpbk9iamVjdChvcHRpb25zKSkge1xuICAgICAgICAgICAgb3B0aW9ucyA9IHtcbiAgICAgICAgICAgICAgICBiYXNlOiBvcHRpb25zXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgICAgIHRyYW5zcG9ydDogdGhpcy5jb21ldGRcbiAgICAgICAgfTtcbiAgICAgICAgdmFyIGNoYW5uZWwgPSBuZXcgQ2hhbm5lbCgkLmV4dGVuZCh0cnVlLCB7fSwgdGhpcy5vcHRpb25zLmNoYW5uZWwsIGRlZmF1bHRzLCBvcHRpb25zKSk7XG5cblxuICAgICAgICAvL1dyYXAgc3VicyBhbmQgdW5zdWJzIHNvIHdlIGNhbiB1c2UgaXQgdG8gcmUtYXR0YWNoIGhhbmRsZXJzIGFmdGVyIGJlaW5nIGRpc2Nvbm5lY3RlZFxuICAgICAgICB2YXIgc3VicyA9IGNoYW5uZWwuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnN1YnNjcmliZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBzdWJpZCA9IHN1YnMuYXBwbHkoY2hhbm5lbCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMgID0gdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucy5jb25jYXQoc3ViaWQpO1xuICAgICAgICAgICAgcmV0dXJuIHN1YmlkO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cblxuICAgICAgICB2YXIgdW5zdWJzID0gY2hhbm5lbC51bnN1YnNjcmliZTtcbiAgICAgICAgY2hhbm5lbC51bnN1YnNjcmliZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciByZW1vdmVkID0gdW5zdWJzLmFwcGx5KGNoYW5uZWwsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5jdXJyZW50U3Vic2NyaXB0aW9uc1tpXS5pZCA9PT0gcmVtb3ZlZC5pZCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zLnNwbGljZShpLCAxKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gcmVtb3ZlZDtcbiAgICAgICAgfS5iaW5kKHRoaXMpO1xuXG4gICAgICAgIHJldHVybiBjaGFubmVsO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTdGFydCBsaXN0ZW5pbmcgZm9yIGV2ZW50cyBvbiB0aGlzIGluc3RhbmNlLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29uLy5cbiAgICAgKlxuICAgICAqIFN1cHBvcnRlZCBldmVudHMgYXJlOiBgY29ubmVjdGAsIGBkaXNjb25uZWN0YCwgYHN1YnNjcmliZWAsIGB1bnN1YnNjcmliZWAsIGBwdWJsaXNoYCwgYGVycm9yYC5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vbi8uXG4gICAgICovXG4gICAgb246IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLm9uLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0b3AgbGlzdGVuaW5nIGZvciBldmVudHMgb24gdGhpcyBpbnN0YW5jZS4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vZmYvLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICovXG4gICAgb2ZmOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS5vZmYuYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVHJpZ2dlciBldmVudHMgYW5kIGV4ZWN1dGUgaGFuZGxlcnMuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vdHJpZ2dlci8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vdHJpZ2dlci8uXG4gICAgICovXG4gICAgdHJpZ2dlcjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykudHJpZ2dlci5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IENoYW5uZWxNYW5hZ2VyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqICMjIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJcbiAqXG4gKiBUaGUgRXBpY2VudGVyIHBsYXRmb3JtIHByb3ZpZGVzIGEgcHVzaCBjaGFubmVsLCB3aGljaCBhbGxvd3MgeW91IHRvIHB1Ymxpc2ggYW5kIHN1YnNjcmliZSB0byBtZXNzYWdlcyB3aXRoaW4gYSBbcHJvamVjdF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3Byb2plY3RzKSwgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSwgb3IgW211bHRpcGxheWVyIHdvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLiBUaGVyZSBhcmUgdHdvIG1haW4gdXNlIGNhc2VzIGZvciB0aGUgY2hhbm5lbDogZXZlbnQgbm90aWZpY2F0aW9ucyBhbmQgY2hhdCBtZXNzYWdlcy5cbiAqXG4gKiBUaGUgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpcyBhIHdyYXBwZXIgYXJvdW5kIHRoZSAobW9yZSBnZW5lcmljKSBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSwgdG8gaW5zdGFudGlhdGUgaXQgd2l0aCBFcGljZW50ZXItc3BlY2lmaWMgZGVmYXVsdHMuIElmIHlvdSBhcmUgaW50ZXJlc3RlZCBpbiBpbmNsdWRpbmcgYSBub3RpZmljYXRpb24gb3IgY2hhdCBmZWF0dXJlIGluIHlvdXIgcHJvamVjdCwgdXNpbmcgYW4gRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpcyBwcm9iYWJseSB0aGUgZWFzaWVzdCB3YXkgdG8gZ2V0IHN0YXJ0ZWQuXG4gKlxuICogWW91J2xsIG5lZWQgdG8gaW5jbHVkZSB0aGUgYGVwaWNlbnRlci1tdWx0aXBsYXllci1kZXBlbmRlbmNpZXMuanNgIGxpYnJhcnkgaW4gYWRkaXRpb24gdG8gdGhlIGBlcGljZW50ZXIuanNgIGxpYnJhcnkgaW4geW91ciBwcm9qZWN0IHRvIHVzZSB0aGUgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlci4gU2VlIFtJbmNsdWRpbmcgRXBpY2VudGVyLmpzXSguLi8uLi8jaW5jbHVkZSkuXG4gKlxuICogVG8gdXNlIHRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyOiBpbnN0YW50aWF0ZSBpdCwgZ2V0IHRoZSBjaGFubmVsIG9mIHRoZSBzY29wZSB5b3Ugd2FudCAoW3VzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycyksIFt3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKSwgb3IgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSksIHRoZW4gdXNlIHRoZSBjaGFubmVsJ3MgYHN1YnNjcmliZSgpYCBhbmQgYHB1Ymxpc2goKWAgbWV0aG9kcyB0byBzdWJzY3JpYmUgdG8gdG9waWNzIG9yIHB1Ymxpc2ggZGF0YSB0byB0b3BpY3MuXG4gKlxuICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAqICAgICB2YXIgZ2MgPSBjbS5nZXRHcm91cENoYW5uZWwoKTtcbiAqICAgICBnYy5zdWJzY3JpYmUoJ2Jyb2FkY2FzdHMnLCBjYWxsYmFjayk7XG4gKlxuICogRm9yIGFkZGl0aW9uYWwgYmFja2dyb3VuZCBvbiBFcGljZW50ZXIncyBwdXNoIGNoYW5uZWwsIHNlZSB0aGUgaW50cm9kdWN0b3J5IG5vdGVzIG9uIHRoZSBbUHVzaCBDaGFubmVsIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL2NoYW5uZWwvKSBwYWdlLlxuICpcbiAqIFRoZSBwYXJhbWV0ZXJzIGZvciBpbnN0YW50aWF0aW5nIGFuIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaW5jbHVkZTpcbiAqXG4gKiAqIGBvcHRpb25zYCBPYmplY3Qgd2l0aCBkZXRhaWxzIGFib3V0IHRoZSBFcGljZW50ZXIgcHJvamVjdCBmb3IgdGhpcyBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGluc3RhbmNlLlxuICogKiBgb3B0aW9ucy5hY2NvdW50YCBUaGUgRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICogKiBgb3B0aW9ucy5wcm9qZWN0YCBFcGljZW50ZXIgcHJvamVjdCBpZC5cbiAqICogYG9wdGlvbnMudXNlck5hbWVgIEVwaWNlbnRlciB1c2VyTmFtZSB1c2VkIGZvciBhdXRoZW50aWNhdGlvbi5cbiAqICogYG9wdGlvbnMudXNlcklkYCBFcGljZW50ZXIgdXNlciBpZCB1c2VkIGZvciBhdXRoZW50aWNhdGlvbi4gT3B0aW9uYWw7IGBvcHRpb25zLnVzZXJOYW1lYCBpcyBwcmVmZXJyZWQuXG4gKiAqIGBvcHRpb25zLnRva2VuYCBFcGljZW50ZXIgdG9rZW4gdXNlZCBmb3IgYXV0aGVudGljYXRpb24uIChZb3UgY2FuIHJldHJpZXZlIHRoaXMgdXNpbmcgYGF1dGhNYW5hZ2VyLmdldFRva2VuKClgIGZyb20gdGhlIFtBdXRob3JpemF0aW9uIE1hbmFnZXJdKC4uL2F1dGgtbWFuYWdlci8pLilcbiAqICogYG9wdGlvbnMuYWxsb3dBbGxDaGFubmVsc2AgSWYgbm90IGluY2x1ZGVkIG9yIGlmIHNldCB0byBgZmFsc2VgLCBhbGwgY2hhbm5lbCBwYXRocyBhcmUgdmFsaWRhdGVkOyBpZiB5b3VyIHByb2plY3QgcmVxdWlyZXMgW1B1c2ggQ2hhbm5lbCBBdXRob3JpemF0aW9uXSguLi8uLi8uLi91cGRhdGluZ195b3VyX3NldHRpbmdzLyksIHlvdSBzaG91bGQgdXNlIHRoaXMgb3B0aW9uLiBJZiB5b3Ugd2FudCB0byBhbGxvdyBvdGhlciBjaGFubmVsIHBhdGhzLCBzZXQgdG8gYHRydWVgOyB0aGlzIGlzIG5vdCBjb21tb24uXG4gKi9cblxudmFyIENoYW5uZWxNYW5hZ2VyID0gcmVxdWlyZSgnLi9jaGFubmVsLW1hbmFnZXInKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi91dGlsL2luaGVyaXQnKTtcbnZhciB1cmxTZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xuXG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL2F1dGgtbWFuYWdlcicpO1xuXG52YXIgdmFsaWRUeXBlcyA9IHtcbiAgICBwcm9qZWN0OiB0cnVlLFxuICAgIGdyb3VwOiB0cnVlLFxuICAgIHdvcmxkOiB0cnVlLFxuICAgIHVzZXI6IHRydWUsXG4gICAgZGF0YTogdHJ1ZSxcbiAgICBnZW5lcmFsOiB0cnVlLFxuICAgIGNoYXQ6IHRydWVcbn07XG52YXIgc2Vzc2lvbiA9IG5ldyBBdXRoTWFuYWdlcigpO1xudmFyIGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IgPSBmdW5jdGlvbiAodmFsdWUsIHNlc3Npb25LZXlOYW1lLCBzZXR0aW5ncykge1xuICAgIGlmICghdmFsdWUpIHtcbiAgICAgICAgdmFyIHVzZXJJbmZvID0gc2Vzc2lvbi5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgIGlmIChzZXR0aW5ncyAmJiBzZXR0aW5nc1tzZXNzaW9uS2V5TmFtZV0pIHtcbiAgICAgICAgICAgIHZhbHVlID0gc2V0dGluZ3Nbc2Vzc2lvbktleU5hbWVdO1xuICAgICAgICB9IGVsc2UgaWYgKHVzZXJJbmZvW3Nlc3Npb25LZXlOYW1lXSkge1xuICAgICAgICAgICAgdmFsdWUgPSB1c2VySW5mb1tzZXNzaW9uS2V5TmFtZV07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3Ioc2Vzc2lvbktleU5hbWUgKyAnIG5vdCBmb3VuZC4gUGxlYXNlIGxvZy1pbiBhZ2Fpbiwgb3Igc3BlY2lmeSAnICsgc2Vzc2lvbktleU5hbWUgKyAnIGV4cGxpY2l0bHknKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdmFsdWU7XG59O1xudmFyIF9fc3VwZXIgPSBDaGFubmVsTWFuYWdlci5wcm90b3R5cGU7XG52YXIgRXBpY2VudGVyQ2hhbm5lbE1hbmFnZXIgPSBjbGFzc0Zyb20oQ2hhbm5lbE1hbmFnZXIsIHtcbiAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5zZXNzaW9uTWFuYWdlciA9IG5ldyBTZXNzaW9uTWFuYWdlcigpO1xuICAgICAgICB2YXIgZGVmYXVsdENvbWV0T3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyhvcHRpb25zKTtcblxuICAgICAgICB2YXIgdXJsT3B0cyA9IHVybFNlcnZpY2UoZGVmYXVsdENvbWV0T3B0aW9ucy5zZXJ2ZXIpO1xuICAgICAgICBpZiAoIWRlZmF1bHRDb21ldE9wdGlvbnMudXJsKSB7XG4gICAgICAgICAgICAvL0RlZmF1bHQgZXBpY2VudGVyIGNvbWV0ZCBlbmRwb2ludFxuICAgICAgICAgICAgZGVmYXVsdENvbWV0T3B0aW9ucy51cmwgPSB1cmxPcHRzLnByb3RvY29sICsgJzovLycgKyB1cmxPcHRzLmhvc3QgKyAnL2NoYW5uZWwvc3Vic2NyaWJlJztcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChkZWZhdWx0Q29tZXRPcHRpb25zLmhhbmRzaGFrZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICB2YXIgdXNlck5hbWUgPSBkZWZhdWx0Q29tZXRPcHRpb25zLnVzZXJOYW1lO1xuICAgICAgICAgICAgdmFyIHVzZXJJZCA9IGRlZmF1bHRDb21ldE9wdGlvbnMudXNlcklkO1xuICAgICAgICAgICAgdmFyIHRva2VuID0gZGVmYXVsdENvbWV0T3B0aW9ucy50b2tlbjtcbiAgICAgICAgICAgIGlmICgodXNlck5hbWUgfHwgdXNlcklkKSAmJiB0b2tlbikge1xuICAgICAgICAgICAgICAgIHZhciB1c2VyUHJvcCA9IHVzZXJOYW1lID8gJ3VzZXJOYW1lJyA6ICd1c2VySWQnO1xuICAgICAgICAgICAgICAgIHZhciBleHQgPSB7XG4gICAgICAgICAgICAgICAgICAgIGF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIHRva2VuXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICBleHRbdXNlclByb3BdID0gdXNlck5hbWUgPyB1c2VyTmFtZSA6IHVzZXJJZDtcblxuICAgICAgICAgICAgICAgIGRlZmF1bHRDb21ldE9wdGlvbnMuaGFuZHNoYWtlID0ge1xuICAgICAgICAgICAgICAgICAgICBleHQ6IGV4dFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLm9wdGlvbnMgPSBkZWZhdWx0Q29tZXRPcHRpb25zO1xuICAgICAgICByZXR1cm4gX19zdXBlci5jb25zdHJ1Y3Rvci5jYWxsKHRoaXMsIGRlZmF1bHRDb21ldE9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgY2hhbm5lbCwgdGhhdCBpcywgYW4gaW5zdGFuY2Ugb2YgYSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKS5cbiAgICAgKlxuICAgICAqIFRoaXMgbWV0aG9kIGVuZm9yY2VzIEVwaWNlbnRlci1zcGVjaWZpYyBjaGFubmVsIG5hbWluZzogYWxsIGNoYW5uZWxzIHJlcXVlc3RlZCBtdXN0IGJlIGluIHRoZSBmb3JtIGAve3R5cGV9L3thY2NvdW50IGlkfS97cHJvamVjdCBpZH0vey4uLn1gLCB3aGVyZSBgdHlwZWAgaXMgb25lIG9mIGBydW5gLCBgZGF0YWAsIGB1c2VyYCwgYHdvcmxkYCwgb3IgYGNoYXRgLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5FcGljZW50ZXJDaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICAgdmFyIGNoYW5uZWwgPSBjbS5nZXRDaGFubmVsKCcvZ3JvdXAvYWNtZS9zdXBwbHktY2hhaW4tZ2FtZS8nKTtcbiAgICAgKlxuICAgICAqICAgICAgY2hhbm5lbC5zdWJzY3JpYmUoJ3RvcGljJywgY2FsbGJhY2spO1xuICAgICAqICAgICAgY2hhbm5lbC5wdWJsaXNoKCd0b3BpYycsIHsgbXlEYXRhOiAxMDAgfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fFN0cmluZ30gYG9wdGlvbnNgIChPcHRpb25hbCkgSWYgc3RyaW5nLCBhc3N1bWVkIHRvIGJlIHRoZSBiYXNlIGNoYW5uZWwgdXJsLiBJZiBvYmplY3QsIGFzc3VtZWQgdG8gYmUgY29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgY29uc3RydWN0b3IuXG4gICAgICovXG4gICAgZ2V0Q2hhbm5lbDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMgJiYgdHlwZW9mIG9wdGlvbnMgIT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICBvcHRpb25zID0ge1xuICAgICAgICAgICAgICAgIGJhc2U6IG9wdGlvbnNcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGNoYW5uZWxPcHRzID0gJC5leHRlbmQoe30sIHRoaXMub3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgIHZhciBiYXNlID0gY2hhbm5lbE9wdHMuYmFzZTtcbiAgICAgICAgaWYgKCFiYXNlKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGJhc2UgdG9waWMgd2FzIHByb3ZpZGVkJyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIWNoYW5uZWxPcHRzLmFsbG93QWxsQ2hhbm5lbHMpIHtcbiAgICAgICAgICAgIHZhciBiYXNlUGFydHMgPSBiYXNlLnNwbGl0KCcvJyk7XG4gICAgICAgICAgICB2YXIgY2hhbm5lbFR5cGUgPSBiYXNlUGFydHNbMV07XG4gICAgICAgICAgICBpZiAoYmFzZVBhcnRzLmxlbmd0aCA8IDQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgY2hhbm5lbCBiYXNlIG5hbWUsIGl0IG11c3QgYmUgaW4gdGhlIGZvcm0gL3t0eXBlfS97YWNjb3VudCBpZH0ve3Byb2plY3QgaWR9L3suLi59Jyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIXZhbGlkVHlwZXNbY2hhbm5lbFR5cGVdKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGNoYW5uZWwgdHlwZScpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmdldENoYW5uZWwuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIFtncm91cF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcykuIFRoZSBncm91cCBtdXN0IGV4aXN0IGluIHRoZSBhY2NvdW50ICh0ZWFtKSBhbmQgcHJvamVjdCBwcm92aWRlZC5cbiAgICAgKlxuICAgICAqIFRoZXJlIGFyZSBubyBub3RpZmljYXRpb25zIGZyb20gRXBpY2VudGVyIG9uIHRoaXMgY2hhbm5lbDsgYWxsIG1lc3NhZ2VzIGFyZSB1c2VyLW9yaWdpbmF0ZWQuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIGdjID0gY20uZ2V0R3JvdXBDaGFubmVsKCk7XG4gICAgICogICAgIGdjLnN1YnNjcmliZSgnYnJvYWRjYXN0cycsIGNhbGxiYWNrKTtcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRvIGJyb2FkY2FzdCB0by4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCBncm91cCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICovXG4gICAgZ2V0R3JvdXBDaGFubmVsOiBmdW5jdGlvbiAoZ3JvdXBOYW1lKSB7XG4gICAgICAgIGdyb3VwTmFtZSA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIGFjY291bnQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAnYWNjb3VudCcsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIHZhciBwcm9qZWN0ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ3Byb2plY3QnLCB0aGlzLm9wdGlvbnMpO1xuXG4gICAgICAgIHZhciBiYXNlVG9waWMgPSBbJy9ncm91cCcsIGFjY291bnQsIHByb2plY3QsIGdyb3VwTmFtZV0uam9pbignLycpO1xuICAgICAgICByZXR1cm4gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhbmQgcmV0dXJuIGEgcHVibGlzaC9zdWJzY3JpYmUgY2hhbm5lbCAoZnJvbSB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSkgZm9yIHRoZSBnaXZlbiBbd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuXG4gICAgICpcbiAgICAgKiBUaGlzIGlzIHR5cGljYWxseSB1c2VkIHRvZ2V0aGVyIHdpdGggdGhlIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgd29ybGRNYW5hZ2VyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuICAgICAqICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAqICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgKiAgICAgICAgIGdyb3VwOiAndGVhbTEnLFxuICAgICAqICAgICAgICAgcnVuOiB7IG1vZGVsOiAnbW9kZWwuZXFuJyB9XG4gICAgICogICAgIH0pO1xuICAgICAqICAgICB3b3JsZE1hbmFnZXIuZ2V0Q3VycmVudFdvcmxkKCkudGhlbihmdW5jdGlvbiAod29ybGRPYmplY3QsIHdvcmxkQWRhcHRlcikge1xuICAgICAqICAgICAgICAgdmFyIHdvcmxkQ2hhbm5lbCA9IGNtLmdldFdvcmxkQ2hhbm5lbCh3b3JsZE9iamVjdCk7XG4gICAgICogICAgICAgICB3b3JsZENoYW5uZWwuc3Vic2NyaWJlKCcnLCBmdW5jdGlvbiAoZGF0YSkge1xuICAgICAqICAgICAgICAgICAgIGNvbnNvbGUubG9nKGRhdGEpO1xuICAgICAqICAgICAgICAgfSk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHdvcmxkYCBUaGUgd29ybGQgb2JqZWN0IG9yIGlkLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBHcm91cCB0aGUgd29ybGQgZXhpc3RzIGluLiBJZiBub3QgcHJvdmlkZWQsIHBpY2tzIHVwIGdyb3VwIGZyb20gY3VycmVudCBzZXNzaW9uIGlmIGVuZCB1c2VyIGlzIGxvZ2dlZCBpbi5cbiAgICAgKi9cbiAgICBnZXRXb3JsZENoYW5uZWw6IGZ1bmN0aW9uICh3b3JsZCwgZ3JvdXBOYW1lKSB7XG4gICAgICAgIHZhciB3b3JsZGlkID0gKCQuaXNQbGFpbk9iamVjdCh3b3JsZCkgJiYgd29ybGQuaWQpID8gd29ybGQuaWQgOiB3b3JsZDtcbiAgICAgICAgaWYgKCF3b3JsZGlkKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBzcGVjaWZ5IGEgd29ybGQgaWQnKTtcbiAgICAgICAgfVxuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvd29ybGQnLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWUsIHdvcmxkaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgY3VycmVudCBbZW5kIHVzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycykgaW4gdGhhdCB1c2VyJ3MgY3VycmVudCBbd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuXG4gICAgICpcbiAgICAgKiBUaGlzIGlzIHR5cGljYWxseSB1c2VkIHRvZ2V0aGVyIHdpdGggdGhlIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyKS4gTm90ZSB0aGF0IHRoaXMgY2hhbm5lbCBvbmx5IGdldHMgbm90aWZpY2F0aW9ucyBmb3Igd29ybGRzIGN1cnJlbnRseSBpbiBtZW1vcnkuIChTZWUgbW9yZSBiYWNrZ3JvdW5kIG9uIFtwZXJzaXN0ZW5jZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlKS4pXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIHdvcmxkTWFuYWdlciA9IG5ldyBGLm1hbmFnZXIuV29ybGRNYW5hZ2VyKHtcbiAgICAgKiAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgKiAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICogICAgICAgICBncm91cDogJ3RlYW0xJyxcbiAgICAgKiAgICAgICAgIHJ1bjogeyBtb2RlbDogJ21vZGVsLmVxbicgfVxuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgKiAgICAgICAgIHZhciB1c2VyQ2hhbm5lbCA9IGNtLmdldFVzZXJDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHVzZXJDaGFubmVsLnN1YnNjcmliZSgnJywgZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgKiAgICAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKiAgICAgICAgIH0pO1xuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHdvcmxkYCBXb3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHVzZXJgIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFVzZXJDaGFubmVsOiBmdW5jdGlvbiAod29ybGQsIHVzZXIsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVzZXJpZCA9ICgkLmlzUGxhaW5PYmplY3QodXNlcikgJiYgdXNlci5pZCkgPyB1c2VyLmlkIDogdXNlcjtcbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGFjY291bnQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAnYWNjb3VudCcsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIHZhciBwcm9qZWN0ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ3Byb2plY3QnLCB0aGlzLm9wdGlvbnMpO1xuXG4gICAgICAgIHZhciBiYXNlVG9waWMgPSBbJy91c2VyJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkLCB1c2VyaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIHRoYXQgYXV0b21hdGljYWxseSB0cmFja3MgdGhlIHByZXNlbmNlIG9mIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgdGhhdCBpcywgd2hldGhlciB0aGUgZW5kIHVzZXIgaXMgY3VycmVudGx5IG9ubGluZSBpbiB0aGlzIGdyb3VwIGFuZCB3b3JsZC4gTm90aWZpY2F0aW9ucyBhcmUgYXV0b21hdGljYWxseSBzZW50IHdoZW4gdGhlIGVuZCB1c2VyIGNvbWVzIG9ubGluZSwgYW5kIHdoZW4gdGhlIGVuZCB1c2VyIGdvZXMgb2ZmbGluZSAobm90IHByZXNlbnQgZm9yIG1vcmUgdGhhbiAyIG1pbnV0ZXMpLiBVc2VmdWwgaW4gbXVsdGlwbGF5ZXIgZ2FtZXMgZm9yIGxldHRpbmcgZWFjaCBlbmQgdXNlciBrbm93IHdoZXRoZXIgb3RoZXIgdXNlcnMgaW4gdGhlaXIgc2hhcmVkIHdvcmxkIGFyZSBhbHNvIG9ubGluZS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgd29ybGRNYW5hZ2VyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuICAgICAqICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAqICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgKiAgICAgICAgIG1vZGVsOiAnbW9kZWwuZXFuJ1xuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZFNlcnZpY2UpIHtcbiAgICAgKiAgICAgICAgIHZhciBwcmVzZW5jZUNoYW5uZWwgPSBjbS5nZXRQcmVzZW5jZUNoYW5uZWwod29ybGRPYmplY3QpO1xuICAgICAqICAgICAgICAgcHJlc2VuY2VDaGFubmVsLm9uKCdwcmVzZW5jZScsIGZ1bmN0aW9uIChldnQsIG5vdGlmaWNhdGlvbikge1xuICAgICAqICAgICAgICAgICAgICBjb25zb2xlLmxvZyhub3RpZmljYXRpb24ub25saW5lLCBub3RpZmljYXRpb24udXNlcklkKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB3b3JsZGAgV29ybGQgb2JqZWN0IG9yIGlkLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB1c2VyaWRgIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFByZXNlbmNlQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCB1c2VyaWQsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGFjY291bnQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAnYWNjb3VudCcsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIHZhciBwcm9qZWN0ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ3Byb2plY3QnLCB0aGlzLm9wdGlvbnMpO1xuXG4gICAgICAgIHZhciBiYXNlVG9waWMgPSBbJy91c2VyJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG5cbiAgICAgICAgdmFyIGxhc3RQaW5nVGltZSA9IHsgfTtcblxuICAgICAgICB2YXIgUElOR19JTlRFUlZBTCA9IDYwMDA7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCdpbnRlcm5hbC1waW5nLWNoYW5uZWwnLCBmdW5jdGlvbiAobm90aWZpY2F0aW9uKSB7XG4gICAgICAgICAgICB2YXIgaW5jb21pbmdVc2VySWQgPSBub3RpZmljYXRpb24uZGF0YS51c2VyO1xuICAgICAgICAgICAgaWYgKCFsYXN0UGluZ1RpbWVbaW5jb21pbmdVc2VySWRdICYmIGluY29taW5nVXNlcklkICE9PSB1c2VyaWQpIHtcbiAgICAgICAgICAgICAgICBjaGFubmVsLnRyaWdnZXIuY2FsbChjaGFubmVsLCAncHJlc2VuY2UnLCB7IHVzZXJJZDogaW5jb21pbmdVc2VySWQsIG9ubGluZTogdHJ1ZSB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxhc3RQaW5nVGltZVtpbmNvbWluZ1VzZXJJZF0gPSAobmV3IERhdGUoKSkudmFsdWVPZigpO1xuICAgICAgICB9KTtcblxuICAgICAgICBzZXRJbnRlcnZhbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBjaGFubmVsLnB1Ymxpc2goJ2ludGVybmFsLXBpbmctY2hhbm5lbCcsIHsgdXNlcjogdXNlcmlkIH0pO1xuXG4gICAgICAgICAgICAkLmVhY2gobGFzdFBpbmdUaW1lLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHZhciBub3cgPSAobmV3IERhdGUoKSkudmFsdWVPZigpO1xuICAgICAgICAgICAgICAgIGlmICh2YWx1ZSAmJiB2YWx1ZSArIChQSU5HX0lOVEVSVkFMICogMikgPCBub3cpIHtcbiAgICAgICAgICAgICAgICAgICAgbGFzdFBpbmdUaW1lW2tleV0gPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICBjaGFubmVsLnRyaWdnZXIuY2FsbChjaGFubmVsLCAncHJlc2VuY2UnLCB7IHVzZXJJZDoga2V5LCBvbmxpbmU6IGZhbHNlIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LCBQSU5HX0lOVEVSVkFMKTtcblxuICAgICAgICByZXR1cm4gY2hhbm5lbDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIGNvbGxlY3Rpb24uIChUaGUgY29sbGVjdGlvbiBuYW1lIGlzIHNwZWNpZmllZCBpbiB0aGUgYHJvb3RgIGFyZ3VtZW50IHdoZW4gdGhlIFtEYXRhIFNlcnZpY2VdKC4uL2RhdGEtYXBpLXNlcnZpY2UvKSBpcyBpbnN0YW50aWF0ZWQuKSBNdXN0IGJlIG9uZSBvZiB0aGUgY29sbGVjdGlvbnMgaW4gdGhpcyBhY2NvdW50ICh0ZWFtKSBhbmQgcHJvamVjdC5cbiAgICAgKlxuICAgICAqIFRoZXJlIGFyZSBhdXRvbWF0aWMgbm90aWZpY2F0aW9ucyBmcm9tIEVwaWNlbnRlciBvbiB0aGlzIGNoYW5uZWwgd2hlbiBkYXRhIGlzIGNyZWF0ZWQsIHVwZGF0ZWQsIG9yIGRlbGV0ZWQgaW4gdGhpcyBjb2xsZWN0aW9uLiBTZWUgbW9yZSBvbiBbYXV0b21hdGljIG1lc3NhZ2VzIHRvIHRoZSBkYXRhIGNoYW5uZWxdKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLyNkYXRhLW1lc3NhZ2VzKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgZGMgPSBjbS5nZXREYXRhQ2hhbm5lbCgnc3VydmV5LXJlc3BvbnNlcycpO1xuICAgICAqICAgICBkYy5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uKGRhdGEsIG1ldGEpIHtcbiAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKlxuICAgICAqICAgICAgICAgIC8vIG1ldGEuZGF0ZSBpcyB0aW1lIG9mIGNoYW5nZSxcbiAgICAgKiAgICAgICAgICAvLyBtZXRhLnN1YlR5cGUgaXMgdGhlIGtpbmQgb2YgY2hhbmdlOiBuZXcsIHVwZGF0ZSwgb3IgZGVsZXRlXG4gICAgICogICAgICAgICAgLy8gbWV0YS5wYXRoIGlzIHRoZSBmdWxsIHBhdGggdG8gdGhlIGNoYW5nZWQgZGF0YVxuICAgICAqICAgICAgICAgIGNvbnNvbGUubG9nKG1ldGEpO1xuICAgICAqICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgY29sbGVjdGlvbmAgTmFtZSBvZiBjb2xsZWN0aW9uIHdob3NlIGF1dG9tYXRpYyBub3RpZmljYXRpb25zIHlvdSB3YW50IHRvIHJlY2VpdmUuXG4gICAgICovXG4gICAgZ2V0RGF0YUNoYW5uZWw6IGZ1bmN0aW9uIChjb2xsZWN0aW9uKSB7XG4gICAgICAgIGlmICghY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIGNvbGxlY3Rpb24gdG8gbGlzdGVuIG9uLicpO1xuICAgICAgICB9XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2RhdGEnLCBhY2NvdW50LCBwcm9qZWN0LCBjb2xsZWN0aW9uXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG5cbiAgICAgICAgLy9UT0RPOiBGaXggYWZ0ZXIgRXBpY2VudGVyIGJ1ZyBpcyByZXNvbHZlZFxuICAgICAgICB2YXIgb2xkc3VicyA9IGNoYW5uZWwuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnN1YnNjcmliZSA9IGZ1bmN0aW9uICh0b3BpYywgY2FsbGJhY2ssIGNvbnRleHQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBjYWxsYmFja1dpdGhDbGVhbkRhdGEgPSBmdW5jdGlvbiAocGF5bG9hZCkge1xuICAgICAgICAgICAgICAgIHZhciBtZXRhID0ge1xuICAgICAgICAgICAgICAgICAgICBwYXRoOiBwYXlsb2FkLmNoYW5uZWwsXG4gICAgICAgICAgICAgICAgICAgIHN1YlR5cGU6IHBheWxvYWQuZGF0YS5zdWJUeXBlLFxuICAgICAgICAgICAgICAgICAgICBkYXRlOiBwYXlsb2FkLmRhdGEuZGF0ZVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdmFyIGFjdHVhbERhdGEgPSBwYXlsb2FkLmRhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICBpZiAoYWN0dWFsRGF0YS5kYXRhKSB7IC8vRGVsZXRlIG5vdGlmaWNhdGlvbnMgYXJlIG9uZSBkYXRhLWxldmVsIGJlaGluZCBvZiBjb3Vyc2VcbiAgICAgICAgICAgICAgICAgICAgYWN0dWFsRGF0YSA9IGFjdHVhbERhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBjYWxsYmFjay5jYWxsKGNvbnRleHQsIGFjdHVhbERhdGEsIG1ldGEpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiBvbGRzdWJzLmNhbGwoY2hhbm5lbCwgdG9waWMsIGNhbGxiYWNrV2l0aENsZWFuRGF0YSwgY29udGV4dCwgb3B0aW9ucyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gRXBpY2VudGVyQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIEVQSV9TRVNTSU9OX0tFWTogJ2VwaWNlbnRlcmpzLnNlc3Npb24nLFxuICAgIFNUUkFURUdZX1NFU1NJT05fS0VZOiAnZXBpY2VudGVyLXNjZW5hcmlvJ1xufTsiLCIvKipcbiogIyMgUnVuIE1hbmFnZXJcbipcbiogVGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBhY2Nlc3MgdG8gcnVucyBmb3IgeW91ciBwcm9qZWN0LiBUaGlzIGFsbG93cyB5b3UgdG8gcmVhZCBhbmQgdXBkYXRlIHZhcmlhYmxlcywgY2FsbCBvcGVyYXRpb25zLCBldGMuIEFkZGl0aW9uYWxseSwgdGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBjb250cm9sIG92ZXIgcnVuIGNyZWF0aW9uIGRlcGVuZGluZyBvbiBydW4gc3RhdGVzLiBTcGVjaWZpY2FsbHksIHlvdSBjYW4gc2VsZWN0IFtydW4gY3JlYXRpb24gc3RyYXRlZ2llcyAocnVsZXMpXSguLi8uLi9zdHJhdGVneS8pIGZvciB3aGljaCBydW5zIGVuZCB1c2VycyBvZiB5b3VyIHByb2plY3Qgd29yayB3aXRoIHdoZW4gdGhleSBsb2cgaW4gdG8geW91ciBwcm9qZWN0LlxuKlxuKiBUaGVyZSBhcmUgbWFueSB3YXlzIHRvIGNyZWF0ZSBuZXcgcnVucywgaW5jbHVkaW5nIHRoZSBFcGljZW50ZXIuanMgW1J1biBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSwgdGhlIFJFU0ZUZnVsIFtSdW4gQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkpIGFuZCB0aGUgW01vZGVsIFJ1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9vdGhlcl9hcGlzL21vZGVsX2FwaXMvcnVuLykuIEhvd2V2ZXIsIGZvciBzb21lIHByb2plY3RzIGl0IG1ha2VzIG1vcmUgc2Vuc2UgdG8gcGljayB1cCB3aGVyZSB0aGUgdXNlciBsZWZ0IG9mZiwgdXNpbmcgYW4gZXhpc3RpbmcgcnVuLiBBbmQgaW4gc29tZSBwcm9qZWN0cywgd2hldGhlciB0byBjcmVhdGUgYSBuZXcgcnVuIG9yIHVzZSBhbiBleGlzdGluZyBvbmUgaXMgY29uZGl0aW9uYWwsIGZvciBleGFtcGxlIGJhc2VkIG9uIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgZXhpc3RpbmcgcnVuIG9yIHlvdXIgb3duIGtub3dsZWRnZSBhYm91dCB0aGUgbW9kZWwuIFRoZSBSdW4gTWFuYWdlciBwcm92aWRlcyB0aGlzIGxldmVsIG9mIGNvbnRyb2w6IHlvdXIgY2FsbCB0byBgZ2V0UnVuKClgLCByYXRoZXIgdGhhbiBhbHdheXMgcmV0dXJuaW5nIGEgbmV3IHJ1biwgcmV0dXJucyBhIHJ1biBiYXNlZCBvbiB0aGUgc3RyYXRlZ3kgeW91J3ZlIHNwZWNpZmllZC4gKE5vdGUgdGhhdCBtYW55IG9mIHRoZSBFcGljZW50ZXIgc2FtcGxlIHByb2plY3RzIHVzZSBhIFJ1biBTZXJ2aWNlIGRpcmVjdGx5LCBiZWNhdXNlIGdlbmVyYWxseSB0aGUgc2FtcGxlIHByb2plY3RzIGFyZSBwbGF5ZWQgaW4gb25lIGVuZCB1c2VyIHNlc3Npb24gYW5kIGRvbid0IGNhcmUgYWJvdXQgcnVuIHN0YXRlcyBvciBydW4gc3RyYXRlZ2llcy4pXG4qXG4qXG4qICMjIyBVc2luZyB0aGUgUnVuIE1hbmFnZXIgdG8gY3JlYXRlIGFuZCBhY2Nlc3MgcnVuc1xuKlxuKiBUbyB1c2UgdGhlIFJ1biBNYW5hZ2VyLCBpbnN0YW50aWF0ZSBpdCBieSBwYXNzaW5nIGluOlxuKlxuKiAgICogYHJ1bmA6IChyZXF1aXJlZCkgUnVuIG9iamVjdC4gTXVzdCBjb250YWluOlxuKiAgICAgICAqIGBhY2NvdW50YDogRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuKiAgICAgICAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4qICAgICAgICogYG1vZGVsYDogVGhlIG5hbWUgb2YgeW91ciBwcmltYXJ5IG1vZGVsIGZpbGUuIChTZWUgbW9yZSBvbiBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4pXG4qICAgICAgICogYHNjb3BlYDogKG9wdGlvbmFsKSBTY29wZSBvYmplY3QgZm9yIHRoZSBydW4sIGZvciBleGFtcGxlIGBzY29wZS5ncm91cGAgd2l0aCB2YWx1ZSBvZiB0aGUgbmFtZSBvZiB0aGUgZ3JvdXAuXG4qICAgICAgICogYHNlcnZlcmA6IChvcHRpb25hbCkgQW4gb2JqZWN0IHdpdGggb25lIGZpZWxkLCBgaG9zdGAuIFRoZSB2YWx1ZSBvZiBgaG9zdGAgaXMgdGhlIHN0cmluZyBgYXBpLmZvcmlvLmNvbWAsIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4qICAgICAgICogYGZpbGVzYDogKG9wdGlvbmFsKSBJZiBhbmQgb25seSBpZiB5b3UgYXJlIHVzaW5nIGEgVmVuc2ltIG1vZGVsIGFuZCB5b3UgaGF2ZSBhZGRpdGlvbmFsIGRhdGEgdG8gcGFzcyBpbiB0byB5b3VyIG1vZGVsLCB5b3UgY2FuIHBhc3MgYSBgZmlsZXNgIG9iamVjdCB3aXRoIHRoZSBuYW1lcyBvZiB0aGUgZmlsZXMsIGZvciBleGFtcGxlOiBgXCJmaWxlc1wiOiB7XCJkYXRhXCI6IFwibXlFeHRyYURhdGEueGxzXCJ9YC4gKE5vdGUgdGhhdCB5b3UnbGwgYWxzbyBuZWVkIHRvIGFkZCB0aGlzIHNhbWUgZmlsZXMgb2JqZWN0IHRvIHlvdXIgVmVuc2ltIFtjb25maWd1cmF0aW9uIGZpbGVdKC4uLy4uLy4uL21vZGVsX2NvZGUvdmVuc2ltLykuKSBTZWUgdGhlIFt1bmRlcmx5aW5nIE1vZGVsIFJ1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9vdGhlcl9hcGlzL21vZGVsX2FwaXMvcnVuLyNwb3N0LWNyZWF0aW5nLWEtbmV3LXJ1bi1mb3ItdGhpcy1wcm9qZWN0KSBmb3IgYWRkaXRpb25hbCBpbmZvcm1hdGlvbi5cbipcbiogICAqIGBzdHJhdGVneWA6IChvcHRpb25hbCkgUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgZGV0YWlscy4gRGVmYXVsdHMgdG8gYG5ldy1pZi1pbml0aWFsaXplZGAuXG4qXG4qICAgKiBgc2Vzc2lvbktleWA6IChvcHRpb25hbCkgTmFtZSBvZiBicm93c2VyIGNvb2tpZSBpbiB3aGljaCB0byBzdG9yZSBydW4gaW5mb3JtYXRpb24sIGluY2x1ZGluZyBydW4gaWQuIE1hbnkgY29uZGl0aW9uYWwgc3RyYXRlZ2llcywgaW5jbHVkaW5nIHRoZSBwcm92aWRlZCBzdHJhdGVnaWVzLCByZWx5IG9uIHRoaXMgYnJvd3NlciBjb29raWUgdG8gc3RvcmUgdGhlIHJ1biBpZCBhbmQgaGVscCBtYWtlIHRoZSBkZWNpc2lvbiBvZiB3aGV0aGVyIHRvIGNyZWF0ZSBhIG5ldyBydW4gb3IgdXNlIGFuIGV4aXN0aW5nIG9uZS4gVGhlIG5hbWUgb2YgdGhpcyBjb29raWUgZGVmYXVsdHMgdG8gYGVwaWNlbnRlci1zY2VuYXJpb2AgYW5kIGNhbiBiZSBzZXQgd2l0aCB0aGUgYHNlc3Npb25LZXlgIHBhcmFtZXRlci5cbipcbipcbiogQWZ0ZXIgaW5zdGFudGlhdGluZyBhIFJ1biBNYW5hZ2VyLCBtYWtlIGEgY2FsbCB0byBgZ2V0UnVuKClgIHdoZW5ldmVyIHlvdSBuZWVkIHRvIGFjY2VzcyBhIHJ1biBmb3IgdGhpcyBlbmQgdXNlci4gVGhlIGBSdW5NYW5hZ2VyLnJ1bmAgY29udGFpbnMgdGhlIGluc3RhbnRpYXRlZCBbUnVuIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLiBUaGUgUnVuIFNlcnZpY2UgYWxsb3dzIHlvdSB0byBhY2Nlc3MgdmFyaWFibGVzLCBjYWxsIG9wZXJhdGlvbnMsIGV0Yy5cbipcbiogKipFeGFtcGxlKipcbipcbiogICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiogICAgICAgICAgIHJ1bjoge1xuKiAgICAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5LWNoYWluLW1vZGVsLmpsJyxcbiogICAgICAgICAgICAgICBzZXJ2ZXI6IHsgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH1cbiogICAgICAgICAgIH0sXG4qICAgICAgICAgICBzdHJhdGVneTogJ2Fsd2F5cy1uZXcnLFxuKiAgICAgICAgICAgc2Vzc2lvbktleTogJ2VwaWNlbnRlci1zZXNzaW9uJ1xuKiAgICAgICB9KTtcbiogICAgICAgcm0uZ2V0UnVuKClcbiogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1bikge1xuKiAgICAgICAgICAgICAgIC8vIHRoZSByZXR1cm4gdmFsdWUgb2YgZ2V0UnVuKCkgaXMgYSBydW4gb2JqZWN0XG4qICAgICAgICAgICAgICAgdmFyIHRoaXNSdW5JZCA9IHJ1bi5pZDtcbiogICAgICAgICAgICAgICAvLyB0aGUgUnVuTWFuYWdlci5ydW4gYWxzbyBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFJ1biBTZXJ2aWNlLFxuKiAgICAgICAgICAgICAgIC8vIHNvIGFueSBSdW4gU2VydmljZSBtZXRob2QgaXMgdmFsaWQgaGVyZVxuKiAgICAgICAgICAgICAgIHJtLnJ1bi5kbygncnVuTW9kZWwnKTtcbiogICAgICAgfSlcbipcbiovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBzdHJhdGVnaWVzTWFwID0gcmVxdWlyZSgnLi9ydW4tc3RyYXRlZ2llcy9zdHJhdGVnaWVzLW1hcCcpO1xudmFyIHNwZWNpYWxPcGVyYXRpb25zID0gcmVxdWlyZSgnLi9zcGVjaWFsLW9wZXJhdGlvbnMnKTtcbnZhciBSdW5TZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9ydW4tYXBpLXNlcnZpY2UnKTtcblxuXG5mdW5jdGlvbiBwYXRjaFJ1blNlcnZpY2Uoc2VydmljZSwgbWFuYWdlcikge1xuICAgIGlmIChzZXJ2aWNlLnBhdGNoZWQpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2U7XG4gICAgfVxuXG4gICAgdmFyIG9yaWcgPSBzZXJ2aWNlLmRvO1xuICAgIHNlcnZpY2UuZG8gPSBmdW5jdGlvbiAob3BlcmF0aW9uLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHJlc2VydmVkT3BzID0gT2JqZWN0LmtleXMoc3BlY2lhbE9wZXJhdGlvbnMpO1xuICAgICAgICBpZiAocmVzZXJ2ZWRPcHMuaW5kZXhPZihvcGVyYXRpb24pID09PSAtMSkge1xuICAgICAgICAgICAgcmV0dXJuIG9yaWcuYXBwbHkoc2VydmljZSwgYXJndW1lbnRzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBzcGVjaWFsT3BlcmF0aW9uc1tvcGVyYXRpb25dLmNhbGwoc2VydmljZSwgcGFyYW1zLCBvcHRpb25zLCBtYW5hZ2VyKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBzZXJ2aWNlLnBhdGNoZWQgPSB0cnVlO1xuXG4gICAgcmV0dXJuIHNlcnZpY2U7XG59XG5cblxuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgLyoqXG4gICAgICogUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgZGV0YWlscy4gRGVmYXVsdHMgdG8gYG5ldy1pZi1pbml0aWFsaXplZGAuXG4gICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgKi9cblxuICAgIHN0cmF0ZWd5OiAnbmV3LWlmLWluaXRpYWxpemVkJ1xufTtcblxuZnVuY3Rpb24gUnVuTWFuYWdlcihvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcblxuICAgIGlmICh0aGlzLm9wdGlvbnMucnVuIGluc3RhbmNlb2YgUnVuU2VydmljZSkge1xuICAgICAgICB0aGlzLnJ1biA9IHRoaXMub3B0aW9ucy5ydW47XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5ydW4gPSBuZXcgUnVuU2VydmljZSh0aGlzLm9wdGlvbnMucnVuKTtcbiAgICB9XG5cbiAgICBwYXRjaFJ1blNlcnZpY2UodGhpcy5ydW4sIHRoaXMpO1xuXG4gICAgdmFyIFN0cmF0ZWd5Q3RvciA9IHR5cGVvZiB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kgPT09ICdmdW5jdGlvbicgPyB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kgOiBzdHJhdGVnaWVzTWFwW3RoaXMub3B0aW9ucy5zdHJhdGVneV07XG5cbiAgICBpZiAoIVN0cmF0ZWd5Q3Rvcikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NwZWNpZmllZCBydW4gY3JlYXRpb24gc3RyYXRlZ3kgd2FzIGludmFsaWQ6JywgdGhpcy5vcHRpb25zLnN0cmF0ZWd5KTtcbiAgICB9XG5cbiAgICB0aGlzLnN0cmF0ZWd5ID0gbmV3IFN0cmF0ZWd5Q3Rvcih0aGlzLnJ1biwgdGhpcy5vcHRpb25zKTtcbn1cblxuUnVuTWFuYWdlci5wcm90b3R5cGUgPSB7XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSAnZ29vZCcgcnVuLlxuICAgICAqXG4gICAgICogQSBnb29kIHJ1biBpcyBkZWZpbmVkIGJ5IHRoZSBzdHJhdGVneS4gRm9yIGV4YW1wbGUsIGlmIHRoZSBzdHJhdGVneSBpcyBgYWx3YXlzLW5ld2AsIHRoZSBjYWxsXG4gICAgICogdG8gYGdldFJ1bigpYCBhbHdheXMgcmV0dXJucyBhIG5ld2x5IGNyZWF0ZWQgcnVuOyBpZiB0aGUgc3RyYXRlZ3kgaXMgYG5ldy1pZi1wZXJzaXN0ZWRgLFxuICAgICAqIGBnZXRSdW4oKWAgY3JlYXRlcyBhIG5ldyBydW4gaWYgdGhlIHByZXZpb3VzIHJ1biBpcyBpbiBhIHBlcnNpc3RlZCBzdGF0ZSwgb3RoZXJ3aXNlXG4gICAgICogaXQgcmV0dXJucyB0aGUgcHJldmlvdXMgcnVuLiBTZWUgW1J1biBNYW5hZ2VyIFN0cmF0ZWdpZXNdKC4uLy4uL3N0cmF0ZWd5LykgZm9yIG1vcmUgb24gc3RyYXRlZ2llcy5cbiAgICAgKlxuICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBybS5nZXRSdW4oKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqIEByZXR1cm4geyRwcm9taXNlfSBQcm9taXNlIHRvIGNvbXBsZXRlIHRoZSBjYWxsLlxuICAgICAqL1xuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zdHJhdGVneVxuICAgICAgICAgICAgICAgIC5nZXRSdW4oKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSBuZXcgcnVuLCByZWdhcmRsZXNzIG9mIHN0cmF0ZWd5OiBmb3JjZSBjcmVhdGlvbiBvZiBhIG5ldyBydW4uXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgcm0ucmVzZXQoKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIChuZXcpIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBydW5TZXJ2aWNlT3B0aW9uc2AgVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGUgUnVuIFNlcnZpY2UuIFNlZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSBmb3IgbW9yZS5cbiAgICAgKi9cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0cmF0ZWd5LnJlc2V0KHJ1blNlcnZpY2VPcHRpb25zKTtcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJ1bk1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIC8vIGFsd2F5cyBjcmVhdGUgYSBuZXcgcnVuIVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIG1ha2VTZXEgPSByZXF1aXJlKCcuLi8uLi91dGlsL21ha2Utc2VxdWVuY2UnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFNlc3Npb25TdG9yZSA9IHJlcXVpcmUoJy4uLy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBVcmxTZXJ2aWNlID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4uL2F1dGgtbWFuYWdlcicpO1xuXG52YXIgc2Vzc2lvblN0b3JlID0gbmV3IFNlc3Npb25TdG9yZSh7fSk7XG52YXIgdXJsU2VydmljZSA9IG5ldyBVcmxTZXJ2aWNlKCk7XG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuLi9rZXktbmFtZXMnKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHNlc3Npb25LZXk6IGtleU5hbWVzLlNUUkFURUdZX1NFU1NJT05fS0VZLFxuICAgIHBhdGg6ICcnXG59O1xuXG5mdW5jdGlvbiBzZXRSdW5JblNlc3Npb24oc2Vzc2lvbktleSwgcnVuLCBwYXRoKSB7XG4gICAgaWYgKCFwYXRoKSB7XG4gICAgICAgIGlmICghdXJsU2VydmljZS5pc0xvY2FsaG9zdCgpKSB7XG4gICAgICAgICAgICBwYXRoID0gJy8nICsgW3VybFNlcnZpY2UuYXBwUGF0aCwgdXJsU2VydmljZS5hY2NvdW50UGF0aCwgdXJsU2VydmljZS5wcm9qZWN0UGF0aF0uam9pbignLycpO1xuICAgICAgICAgICAgLy8gbWFrZSBzdXJlIHdlIGRvbid0IGdldCBjb25zZWN1dGVpdmUgJy8nIHNvIHdlIGhhdmUgYSB2YWxpZCBwYXRoIGZvciB0aGUgc2Vzc2lvblxuICAgICAgICAgICAgcGF0aCA9IHBhdGgucmVwbGFjZSgvXFwvezIsfS9nLCcvJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwYXRoID0gJyc7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gc2V0IHRoZSBzZWVzaW9uS2V5IGZvciB0aGUgcnVuXG4gICAgc2Vzc2lvblN0b3JlLnNldChzZXNzaW9uS2V5LCBKU09OLnN0cmluZ2lmeSh7IHJ1bklkOiBydW4uaWQgfSksIHsgcm9vdDogcGF0aCB9KTtcbn1cblxuLyoqXG4qIENvbmRpdGlvbmFsIENyZWF0aW9uIFN0cmF0ZWd5XG4qIFRoaXMgc3RyYXRlZ3kgd2lsbCB0cnkgdG8gZ2V0IHRoZSBydW4gc3RvcmVkIGluIHRoZSBjb29raWUgYW5kXG4qIGV2YWx1YXRlIGlmIG5lZWRzIHRvIGNyZWF0ZSBhIG5ldyBydW4gYnkgY2FsbGluZyB0aGUgJ2NvbmRpdGlvbicgZnVuY3Rpb25cbiovXG5cbi8qIGpzaGludCBlcW51bGw6IHRydWUgKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIFN0cmF0ZWd5KHJ1blNlcnZpY2UsIGNvbmRpdGlvbiwgb3B0aW9ucykge1xuXG4gICAgICAgIGlmIChjb25kaXRpb24gPT0gbnVsbCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb25kaXRpb25hbCBzdHJhdGVneSBuZWVkcyBhIGNvbmRpdGlvbiB0byBjcmVhdGV0ZSBhIHJ1bicpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fYXV0aCA9IG5ldyBBdXRoTWFuYWdlcigpO1xuICAgICAgICB0aGlzLnJ1biA9IG1ha2VTZXEocnVuU2VydmljZSk7XG4gICAgICAgIHRoaXMuY29uZGl0aW9uID0gdHlwZW9mIGNvbmRpdGlvbiAhPT0gJ2Z1bmN0aW9uJyA/IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGNvbmRpdGlvbjsgfSA6IGNvbmRpdGlvbjtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICB9LFxuXG4gICAgcnVuT3B0aW9uc1dpdGhTY29wZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgdXNlclNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiB1c2VyU2Vzc2lvbi5ncm91cE5hbWUgfVxuICAgICAgICB9LCB0aGlzLnJ1bk9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBvcHQgPSB0aGlzLnJ1bk9wdGlvbnNXaXRoU2NvcGUoKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5ydW5cbiAgICAgICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgc2V0UnVuSW5TZXNzaW9uKF90aGlzLm9wdGlvbnMuc2Vzc2lvbktleSwgcnVuLCBfdGhpcy5vcHRpb25zLnBhdGgpO1xuICAgICAgICAgICAgICAgIHJ1bi5mcmVzaGx5Q3JlYXRlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuc3RhcnQoKTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBydW5TZXNzaW9uID0gSlNPTi5wYXJzZShzZXNzaW9uU3RvcmUuZ2V0KHRoaXMub3B0aW9ucy5zZXNzaW9uS2V5KSk7XG5cbiAgICAgICAgaWYgKHJ1blNlc3Npb24gJiYgcnVuU2Vzc2lvbi5ydW5JZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2xvYWRBbmRDaGVjayhydW5TZXNzaW9uKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJlc2V0KCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgX2xvYWRBbmRDaGVjazogZnVuY3Rpb24gKHJ1blNlc3Npb24pIHtcbiAgICAgICAgdmFyIHNob3VsZENyZWF0ZSA9IGZhbHNlO1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1blxuICAgICAgICAgICAgLmxvYWQocnVuU2Vzc2lvbi5ydW5JZCwgbnVsbCwge1xuICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZ1bmN0aW9uIChydW4sIG1zZywgaGVhZGVycykge1xuICAgICAgICAgICAgICAgICAgICBzaG91bGRDcmVhdGUgPSBfdGhpcy5jb25kaXRpb24uY2FsbChfdGhpcywgcnVuLCBoZWFkZXJzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIGlmIChzaG91bGRDcmVhdGUpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9wdCA9IF90aGlzLnJ1bk9wdGlvbnNXaXRoU2NvcGUoKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gd2UgbmVlZCB0byBkbyB0aGlzLCBvbiB0aGUgb3JpZ2luYWwgcnVuU2VydmljZSAoaWUgbm90IHNlcXVlbmNpYWxpemVkKVxuICAgICAgICAgICAgICAgICAgICAvLyBzbyB3ZSBkb24ndCBnZXQgaW4gdGhlIG1pZGRsZSBvZiB0aGUgcXVldWVcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1bi5vcmlnaW5hbC5jcmVhdGUob3B0KVxuICAgICAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRSdW5JblNlc3Npb24oX3RoaXMub3B0aW9ucy5zZXNzaW9uS2V5LCBydW4pO1xuICAgICAgICAgICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnN0YXJ0KCk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0ge307XG5cbi8vIEludGVyZmFjZSB0aGF0IGFsbCBzdHJhdGVnaWVzIG5lZWQgdG8gaW1wbGVtZW50XG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuU2VydmljZSAgPSBydW5TZXJ2aWNlO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSBuZXdseSBjcmVhdGVkIHJ1blxuICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlc29sdmUoKS5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSB1c2FibGUgcnVuXG4gICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVzb2x2ZSh0aGlzLnJ1blNlcnZpY2UpLnByb21pc2UoKTtcbiAgICB9XG59KTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xuXG52YXIgSWRlbnRpdHlTdHJhdGVneSA9IHJlcXVpcmUoJy4vaWRlbnRpdHktc3RyYXRlZ3knKTtcbnZhciBXb3JsZEFwaUFkYXB0ZXIgPSByZXF1aXJlKCcuLi8uLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuLi9hdXRoLW1hbmFnZXInKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHN0b3JlOiB7XG4gICAgICAgIHN5bmNocm9ub3VzOiB0cnVlXG4gICAgfVxufTtcblxudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKElkZW50aXR5U3RyYXRlZ3ksIHtcblxuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICB0aGlzLnJ1blNlcnZpY2UgPSBydW5TZXJ2aWNlO1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMud29ybGRBcGkgPSBuZXcgV29ybGRBcGlBZGFwdGVyKHRoaXMub3B0aW9ucy5ydW4pO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICB2YXIgY3VyVXNlcklkID0gc2Vzc2lvbi51c2VySWQ7XG4gICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaVxuICAgICAgICAgICAgLmdldEN1cnJlbnRXb3JsZEZvclVzZXIoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaS5uZXdSdW5Gb3JXb3JsZCh3b3JsZC5pZCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIGN1clVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICB2YXIgY3VyR3JvdXBOYW1lID0gc2Vzc2lvbi5ncm91cE5hbWU7XG4gICAgICAgIHZhciB3b3JsZEFwaSA9IHRoaXMud29ybGRBcGk7XG4gICAgICAgIHZhciBtb2RlbCA9IHRoaXMub3B0aW9ucy5tb2RlbDtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcblxuICAgICAgICBpZiAoIWN1clVzZXJJZCkge1xuICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDAsIGVycm9yOiAnV2UgbmVlZCBhbiBhdXRoZW50aWNhdGVkIHVzZXIgdG8gam9pbiBhIG11bHRpcGxheWVyIHdvcmxkLiAoRVJSOiBubyB1c2VySWQgaW4gc2Vzc2lvbiknIH0sIHNlc3Npb24pLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBsb2FkUnVuRnJvbVdvcmxkID0gZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICBpZiAoIXdvcmxkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDQsIGVycm9yOiAnVGhlIHVzZXIgaXMgbm90IGluIGFueSB3b3JsZC4nIH0sIHsgb3B0aW9uczogdGhpcy5vcHRpb25zLCBzZXNzaW9uOiBzZXNzaW9uIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gd29ybGRBcGkuZ2V0Q3VycmVudFJ1bklkKHsgbW9kZWw6IG1vZGVsLCBmaWx0ZXI6IHdvcmxkLmlkIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oX3RoaXMuX2xvYWRSdW4pXG4gICAgICAgICAgICAgICAgLnRoZW4oZHRkLnJlc29sdmUpXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHNlcnZlckVycm9yID0gZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAvLyBpcyB0aGlzIHBvc3NpYmxlP1xuICAgICAgICAgICAgZHRkLnJlamVjdChlcnJvciwgc2Vzc2lvbiwgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLndvcmxkQXBpXG4gICAgICAgICAgICAuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcihjdXJVc2VySWQsIGN1ckdyb3VwTmFtZSlcbiAgICAgICAgICAgIC50aGVuKGxvYWRSdW5Gcm9tV29ybGQpXG4gICAgICAgICAgICAuZmFpbChzZXJ2ZXJFcnJvcik7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIF9sb2FkUnVuOiBmdW5jdGlvbiAoaWQsIG9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5sb2FkKGlkLCBudWxsLCBvcHRpb25zKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIHJldHVybiBoZWFkZXJzLmdldFJlc3BvbnNlSGVhZGVyKCdwcmFnbWEnKSA9PT0gJ3BlcnNpc3RlbnQnIHx8IHJ1bi5pbml0aWFsaXplZDtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbi8qXG4qICBjcmVhdGUgYSBuZXcgcnVuIG9ubHkgaWYgbm90aGluZyBpcyBzdG9yZWQgaW4gdGhlIGNvb2tpZVxuKiAgdGhpcyBpcyB1c2VmdWwgZm9yIGJhc2VSdW5zLlxuKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgLy8gaWYgd2UgYXJlIGhlcmUsIGl0IG1lYW5zIHRoYXQgdGhlIHJ1biBleGlzdHMuLi4gc28gd2UgZG9uJ3QgbmVlZCBhIG5ldyBvbmVcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgcmV0dXJuIGhlYWRlcnMuZ2V0UmVzcG9uc2VIZWFkZXIoJ3ByYWdtYScpID09PSAncGVyc2lzdGVudCc7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBJZGVudGl0eVN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIFN0YXRlQXBpID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xudmFyIEF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4uL2tleS1uYW1lcycpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgc3RvcmU6IHtcbiAgICAgICAgc3luY2hyb25vdXM6IHRydWVcbiAgICB9XG59O1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oSWRlbnRpdHlTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiBTdHJhdGVneShydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICAgICAgdGhpcy5fc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkodGhpcy5vcHRpb25zLnN0b3JlKTtcbiAgICAgICAgdGhpcy5zdGF0ZUFwaSA9IG5ldyBTdGF0ZUFwaSgpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG5cbiAgICAgICAgdGhpcy5fbG9hZEFuZENoZWNrID0gdGhpcy5fbG9hZEFuZENoZWNrLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX3Jlc3RvcmVSdW4gPSB0aGlzLl9yZXN0b3JlUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2dldEFsbFJ1bnMgPSB0aGlzLl9nZXRBbGxSdW5zLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAocnVuU2VydmljZU9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiBzZXNzaW9uLmdyb3VwTmFtZSB9XG4gICAgICAgIH0sIHRoaXMucnVuT3B0aW9ucyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuXG4gICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0QWxsUnVucygpXG4gICAgICAgICAgICAudGhlbih0aGlzLl9sb2FkQW5kQ2hlY2spO1xuICAgIH0sXG5cbiAgICBfZ2V0QWxsUnVuczogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IEpTT04ucGFyc2UodGhpcy5fc3RvcmUuZ2V0KGtleU5hbWVzLkVQSV9TRVNTSU9OX0tFWSkgfHwgJ3t9Jyk7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5xdWVyeSh7XG4gICAgICAgICAgICAndXNlci5pZCc6IHNlc3Npb24udXNlcklkIHx8ICcwMDAwJyxcbiAgICAgICAgICAgICdzY29wZS5ncm91cCc6IHNlc3Npb24uZ3JvdXBOYW1lXG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICBfbG9hZEFuZENoZWNrOiBmdW5jdGlvbiAocnVucykge1xuICAgICAgICBpZiAoIXJ1bnMgfHwgIXJ1bnMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yZXNldCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGRhdGVDb21wID0gZnVuY3Rpb24gKGEsIGIpIHsgcmV0dXJuIG5ldyBEYXRlKGIuZGF0ZSkgLSBuZXcgRGF0ZShhLmRhdGUpOyB9O1xuICAgICAgICB2YXIgbGF0ZXN0UnVuID0gcnVucy5zb3J0KGRhdGVDb21wKVswXTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIHNob3VsZFJlcGxheSA9IGZhbHNlO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5sb2FkKGxhdGVzdFJ1bi5pZCwgbnVsbCwge1xuICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKHJ1biwgbXNnLCBoZWFkZXJzKSB7XG4gICAgICAgICAgICAgICAgc2hvdWxkUmVwbGF5ID0gaGVhZGVycy5nZXRSZXNwb25zZUhlYWRlcigncHJhZ21hJykgPT09ICdwZXJzaXN0ZW50JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSkudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICByZXR1cm4gc2hvdWxkUmVwbGF5ID8gX3RoaXMuX3Jlc3RvcmVSdW4ocnVuLmlkKSA6IHJ1bjtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIF9yZXN0b3JlUnVuOiBmdW5jdGlvbiAocnVuSWQpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGVBcGkucmVwbGF5KHsgcnVuSWQ6IHJ1bklkIH0pXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzcCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5fbG9hZFJ1bihyZXNwLnJ1bik7XG4gICAgICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgX2xvYWRSdW46IGZ1bmN0aW9uIChpZCwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5ydW4ubG9hZChpZCwgbnVsbCwgb3B0aW9ucyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIm1vZHVsZS5leHBvcnRzID0ge1xuICAgICduZXctaWYtaW5pdGlhbGl6ZWQnOiByZXF1aXJlKCcuL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpLFxuICAgICduZXctaWYtcGVyc2lzdGVkJzogcmVxdWlyZSgnLi9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5JyksXG4gICAgJ25ldy1pZi1taXNzaW5nJzogcmVxdWlyZSgnLi9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpLFxuICAgICdhbHdheXMtbmV3JzogcmVxdWlyZSgnLi9hbHdheXMtbmV3LXN0cmF0ZWd5JyksXG4gICAgJ211bHRpcGxheWVyJzogcmVxdWlyZSgnLi9tdWx0aXBsYXllci1zdHJhdGVneScpLFxuICAgICdwZXJzaXN0ZW50LXNpbmdsZS1wbGF5ZXInOiByZXF1aXJlKCcuL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneScpLFxuICAgICdub25lJzogcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpXG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIFJ1blNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgdmFsaWRGaWx0ZXI6IHsgc2F2ZWQ6IHRydWUgfVxufTtcblxuZnVuY3Rpb24gU2NlbmFyaW9NYW5hZ2VyKG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMucnVuU2VydmljZSA9IHRoaXMub3B0aW9ucy5ydW4gfHwgbmV3IFJ1blNlcnZpY2UodGhpcy5vcHRpb25zKTtcbn1cblxuU2NlbmFyaW9NYW5hZ2VyLnByb3RvdHlwZSA9IHtcbiAgICBnZXRSdW5zOiBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgIHRoaXMuZmlsdGVyID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMub3B0aW9ucy52YWxpZEZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5xdWVyeSh0aGlzLmZpbHRlcik7XG4gICAgfSxcblxuICAgIGxvYWRWYXJpYWJsZXM6IGZ1bmN0aW9uICh2YXJzKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1blNlcnZpY2UucXVlcnkodGhpcy5maWx0ZXIsIHsgaW5jbHVkZTogdmFycyB9KTtcbiAgICB9LFxuXG4gICAgc2F2ZTogZnVuY3Rpb24gKHJ1biwgbWV0YSkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0U2VydmljZShydW4pLnNhdmUoJC5leHRlbmQodHJ1ZSwge30sIHsgc2F2ZWQ6IHRydWUgfSwgbWV0YSkpO1xuICAgIH0sXG5cbiAgICBhcmNoaXZlOiBmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9nZXRTZXJ2aWNlKHJ1bikuc2F2ZSh7IHNhdmVkOiBmYWxzZSB9KTtcbiAgICB9LFxuXG4gICAgX2dldFNlcnZpY2U6IGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW4gfSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdvYmplY3QnICYmIHJ1biBpbnN0YW5jZW9mIFJ1blNlcnZpY2UpIHtcbiAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgIH1cblxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NhdmUgbWV0aG9kIHJlcXVpcmVzIGEgcnVuIHNlcnZpY2Ugb3IgYSBydW5JZCcpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW5JZCB9KSk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTY2VuYXJpb01hbmFnZXI7XG5cbiIsIid1c2Ugc3RyaWN0JztcblxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICByZXNldDogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucywgbWFuYWdlcikge1xuICAgICAgICByZXR1cm4gbWFuYWdlci5yZXNldChvcHRpb25zKTtcbiAgICB9XG59O1xuIiwiLyoqXG4qICMjIFdvcmxkIE1hbmFnZXJcbipcbiogQXMgZGlzY3Vzc2VkIHVuZGVyIHRoZSBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLyksIGEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsLiBGb3IgYnVpbGRpbmcgbXVsdGlwbGF5ZXIgc2ltdWxhdGlvbnMgeW91IHR5cGljYWxseSB3YW50IG11bHRpcGxlIGVuZCB1c2VycyB0byBzaGFyZSB0aGUgc2FtZSBzZXQgb2YgaW50ZXJhY3Rpb25zLCBhbmQgd29yayB3aXRoaW4gYSBjb21tb24gc3RhdGUuIEVwaWNlbnRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSBcIndvcmxkc1wiIHRvIGhhbmRsZSBzdWNoIGNhc2VzLlxuKlxuKiBUaGUgV29ybGQgTWFuYWdlciBwcm92aWRlcyBhbiBlYXN5IHdheSB0byB0cmFjayBhbmQgYWNjZXNzIHRoZSBjdXJyZW50IHdvcmxkIGFuZCBydW4gZm9yIHBhcnRpY3VsYXIgZW5kIHVzZXJzLiBJdCBpcyB0eXBpY2FsbHkgdXNlZCBpbiBwYWdlcyB0aGF0IGVuZCB1c2VycyB3aWxsIGludGVyYWN0IHdpdGguIChUaGUgcmVsYXRlZCBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLykgaGFuZGxlcyBjcmVhdGluZyBtdWx0aXBsYXllciB3b3JsZHMsIGFuZCBhZGRpbmcgYW5kIHJlbW92aW5nIGVuZCB1c2VycyBhbmQgcnVucyBmcm9tIGEgd29ybGQuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4pXG4qXG4qICMjIyBVc2luZyB0aGUgV29ybGQgTWFuYWdlclxuKlxuKiBUbyB1c2UgdGhlIFdvcmxkIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LiBUaGVuLCBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbipcbiogV2hlbiB5b3UgaW5zdGFudGlhdGUgYSBXb3JsZCBNYW5hZ2VyLCB0aGUgd29ybGQncyBhY2NvdW50IGlkLCBwcm9qZWN0IGlkLCBhbmQgZ3JvdXAgYXJlIGF1dG9tYXRpY2FsbHkgdGFrZW4gZnJvbSB0aGUgc2Vzc2lvbiAodGhhbmtzIHRvIHRoZSBbQXV0aGVudGljYXRpb24gU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZSkpLlxuKlxuKiBOb3RlIHRoYXQgdGhlIFdvcmxkIE1hbmFnZXIgZG9lcyAqbm90KiBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkuIChUaGlzIGlzIGRpZmZlcmVudCB0aGFuIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyKS4pIEhvd2V2ZXIsIHlvdSBjYW4gcGFzcyBpbiBzcGVjaWZpYyBvcHRpb25zIHRvIGFueSBydW5zIGNyZWF0ZWQgYnkgdGhlIG1hbmFnZXIsIHVzaW5nIGEgYHJ1bmAgb2JqZWN0LlxuKlxuKiBUaGUgcGFyYW1ldGVycyBmb3IgY3JlYXRpbmcgYSBXb3JsZCBNYW5hZ2VyIGFyZTpcbipcbiogICAqIGBhY2NvdW50YDogVGhlICoqVGVhbSBJRCoqIGluIHRoZSBFcGljZW50ZXIgdXNlciBpbnRlcmZhY2UgZm9yIHRoaXMgcHJvamVjdC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGlzIHByb2plY3QuXG4qICAgKiBgZ3JvdXBgOiBUaGUgKipHcm91cCBOYW1lKiogZm9yIHRoaXMgd29ybGQuXG4qICAgKiBgcnVuYDogT3B0aW9ucyB0byB1c2Ugd2hlbiBjcmVhdGluZyBuZXcgcnVucyB3aXRoIHRoZSBtYW5hZ2VyLCBlLmcuIGBydW46IHsgZmlsZXM6IFsnZGF0YS54bHMnXSB9YC5cbiogICAqIGBydW4ubW9kZWxgOiBUaGUgbmFtZSBvZiB0aGUgcHJpbWFyeSBtb2RlbCBmaWxlIGZvciB0aGlzIHByb2plY3QuIFJlcXVpcmVkIGlmIHlvdSBoYXZlIG5vdCBhbHJlYWR5IHBhc3NlZCBpdCBpbiBhcyBwYXJ0IG9mIHRoZSBgb3B0aW9uc2AgcGFyYW1ldGVyIGZvciBhbiBlbmNsb3NpbmcgY2FsbC5cbipcbiogRm9yIGV4YW1wbGU6XG4qXG4qICAgICAgIHZhciB3TWdyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4qICAgICAgICAgIHJ1bjogeyBtb2RlbDogJ3N1cHBseS1jaGFpbi5weScgfSxcbiogICAgICAgICAgZ3JvdXA6ICd0ZWFtMSdcbiogICAgICAgfSk7XG4qXG4qICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bigpO1xuKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgV29ybGRBcGkgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgUnVuTWFuYWdlciA9ICByZXF1aXJlKCcuL3J1bi1tYW5hZ2VyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL2F1dGgtbWFuYWdlcicpO1xudmFyIHdvcmxkQXBpO1xuXG4vLyB2YXIgZGVmYXVsdHMgPSB7XG4vLyAgYWNjb3VudDogJycsXG4vLyAgcHJvamVjdDogJycsXG4vLyAgZ3JvdXA6ICcnLFxuLy8gIHRyYW5zcG9ydDoge1xuLy8gIH1cbi8vIH07XG5cblxuZnVuY3Rpb24gYnVpbGRTdHJhdGVneSh3b3JsZElkLCBkdGQpIHtcblxuICAgIHJldHVybiBmdW5jdGlvbiBDdG9yKHJ1blNlcnZpY2UsIG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5ydW5TZXJ2aWNlID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcblxuICAgICAgICAkLmV4dGVuZCh0aGlzLCB7XG4gICAgICAgICAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbm90IGltcGxlbWVudGQuIE5lZWQgYXBpIGNoYW5nZXMnKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgICAgICAgICAgLy9nZXQgb3IgY3JlYXRlIVxuICAgICAgICAgICAgICAgIC8vIE1vZGVsIGlzIHJlcXVpcmVkIGluIHRoZSBvcHRpb25zXG4gICAgICAgICAgICAgICAgdmFyIG1vZGVsID0gdGhpcy5vcHRpb25zLnJ1bi5tb2RlbCB8fCB0aGlzLm9wdGlvbnMubW9kZWw7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHdvcmxkQXBpLmdldEN1cnJlbnRSdW5JZCh7IG1vZGVsOiBtb2RlbCwgZmlsdGVyOiB3b3JsZElkIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1blNlcnZpY2UubG9hZChydW5JZCk7XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlLmNhbGwodGhpcywgcnVuLCBfdGhpcy5ydW5TZXJ2aWNlKTtcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH07XG59XG5cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnMgfHwgeyBydW46IHt9LCB3b3JsZDoge30gfTtcblxuICAgICQuZXh0ZW5kKHRydWUsIHRoaXMub3B0aW9ucywgdGhpcy5vcHRpb25zLnJ1bik7XG4gICAgJC5leHRlbmQodHJ1ZSwgdGhpcy5vcHRpb25zLCB0aGlzLm9wdGlvbnMud29ybGQpO1xuXG4gICAgd29ybGRBcGkgPSBuZXcgV29ybGRBcGkodGhpcy5vcHRpb25zKTtcbiAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgIHZhciBhcGkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0dXJucyB0aGUgY3VycmVudCB3b3JsZCAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtXb3JsZCBBUEkgQWRhcHRlcl0oLi4vd29ybGQtYXBpLWFkYXB0ZXIvKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB3TWdyLmdldEN1cnJlbnRXb3JsZCgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkLCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdvcmxkQWRhcHRlci5nZXRDdXJyZW50UnVuSWQoKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgdXNlcklkYCAoT3B0aW9uYWwpIFRoZSBpZCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZCBpcyBiZWluZyBhY2Nlc3NlZC4gRGVmYXVsdHMgdG8gdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgZ3JvdXAgd2hvc2Ugd29ybGQgaXMgYmVpbmcgYWNjZXNzZWQuIERlZmF1bHRzIHRvIHRoZSBncm91cCBmb3IgdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFdvcmxkOiBmdW5jdGlvbiAodXNlcklkLCBncm91cE5hbWUpIHtcbiAgICAgICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5fYXV0aC5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgICAgICBpZiAoIXVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFncm91cE5hbWUpIHtcbiAgICAgICAgICAgICAgICBncm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB3b3JsZEFwaS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKHVzZXJJZCwgZ3JvdXBOYW1lKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHJ1biAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bih7bW9kZWw6ICdteU1vZGVsLnB5J30pXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1biwgcnVuU2VydmljZSkge1xuICAgICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2cocnVuLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHJ1blNlcnZpY2UuZG8oJ3N0YXJ0R2FtZScpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBtb2RlbGAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgbW9kZWwgZmlsZS4gUmVxdWlyZWQgaWYgbm90IGFscmVhZHkgcGFzc2VkIGluIGFzIGBydW4ubW9kZWxgIHdoZW4gdGhlIFdvcmxkIE1hbmFnZXIgaXMgY3JlYXRlZC5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFJ1bjogZnVuY3Rpb24gKG1vZGVsKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgICAgIHZhciBjdXJVc2VySWQgPSBzZXNzaW9uLnVzZXJJZDtcbiAgICAgICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICAgICAgZnVuY3Rpb24gZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bih3b3JsZCkge1xuICAgICAgICAgICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBlcnJvcjogJ1RoZSB1c2VyIGlzIG5vdCBwYXJ0IG9mIGFueSB3b3JsZCEnIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBjdXJyZW50V29ybGRJZCA9IHdvcmxkLmlkO1xuICAgICAgICAgICAgICAgIHZhciBydW5PcHRzID0gJC5leHRlbmQodHJ1ZSwgX3RoaXMub3B0aW9ucywgeyBtb2RlbDogbW9kZWwgfSk7XG4gICAgICAgICAgICAgICAgdmFyIHN0cmF0ZWd5ID0gYnVpbGRTdHJhdGVneShjdXJyZW50V29ybGRJZCwgZHRkKTtcbiAgICAgICAgICAgICAgICB2YXIgb3B0ID0gJC5leHRlbmQodHJ1ZSwge30sIHtcbiAgICAgICAgICAgICAgICAgICAgc3RyYXRlZ3k6IHN0cmF0ZWd5LFxuICAgICAgICAgICAgICAgICAgICBydW46IHJ1bk9wdHNcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB2YXIgcm0gPSBuZXcgUnVuTWFuYWdlcihvcHQpO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJtLmdldFJ1bigpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHJ1biwgcm0ucnVuU2VydmljZSwgcm0pO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5nZXRDdXJyZW50V29ybGQoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAgICAgLnRoZW4oZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bik7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIGFwaSk7XG59O1xuIiwiLyoqXG4gKiAjIyBGaWxlIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhpcyBpcyB1c2VkIHRvIHVwbG9hZC9kb3dubG9hZCBmaWxlcyBkaXJlY3RseSBvbnRvIEVwaWNlbnRlciwgYW5hbG9nb3VzIHRvIHVzaW5nIHRoZSBGaWxlIE1hbmFnZXIgVUkgaW4gRXBpY2VudGVyIGRpcmVjdGx5IG9yIFNGVFBpbmcgZmlsZXMgaW4uIFRoZSBBc3NldCBBUEkgaXMgdHlwaWNhbGx5IHVzZWQgZm9yIGFsbCBwcm9qZWN0IHVzZS1jYXNlcywgYW5kIGl0J3MgdW5saWtlbHkgdGhpcyBGaWxlIFNlcnZpY2Ugd2lsbCBiZSB1c2VkIGRpcmVjdGx5IGV4Y2VwdCBieSBBZG1pbiB0b29scyAoZS5nLiBGbG93IEluc3BlY3RvcikuXG4gKlxuICogUGFydGlhbGx5IGltcGxlbWVudGVkLlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRva2VuOiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBmb2xkZXIgdHlwZS4gIE9uZSBvZiBNb2RlbHxTdGF0aWN8Tm9kZVxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZm9sZGVyVHlwZTogJ3N0YXRpYycsXG5cblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9XG4gICAgfTtcblxuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHVybENvbmZpZy5hY2NvdW50UGF0aCA9IHNlcnZpY2VPcHRpb25zLmFjY291bnQ7XG4gICAgfVxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHVybENvbmZpZy5wcm9qZWN0UGF0aCA9IHNlcnZpY2VPcHRpb25zLnByb2plY3Q7XG4gICAgfVxuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdmaWxlJylcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBc3luY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBhIGRpcmVjdG9yeSBsaXN0aW5nLCBvciBjb250ZW50cyBvZiBhIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBgZmlsZVBhdGhgICAgUGF0aCB0byB0aGUgZmlsZVxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgZ2V0Q29udGVudHM6IGZ1bmN0aW9uIChmaWxlUGF0aCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhdGggPSBzZXJ2aWNlT3B0aW9ucy5mb2xkZXJUeXBlICsgJy8nICsgZmlsZVBhdGg7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdmaWxlJykgKyBwYXRoXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldCgnJywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBXcml0ZXMgdG8gdGhlIGdpdmVuIGZpbGUgcGF0aDsgcmVwbGFjZXMgdGhlIGV4aXN0aW5nIGZpbGUgaWYgaXQgZXhpc3RzXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGZpbGVQYXRoYCBQYXRoIHRvIHRoZSBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGNvbnRlbnRzYCBDb250ZW50cyB0byB3cml0ZSB0byBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gYG9wdGlvbnNgICAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAgICAgICAqL1xuICAgICAgICB3cml0ZVRvRmlsZTogZnVuY3Rpb24gKGZpbGVQYXRoLCBjb250ZW50cywgb3B0aW9ucykge1xuICAgICAgICAgICAgZmlsZVBhdGggPSBmaWxlUGF0aC5zcGxpdCgnLycpO1xuICAgICAgICAgICAgdmFyIGZpbGVOYW1lID0gZmlsZVBhdGgucG9wKCk7XG4gICAgICAgICAgICBmaWxlUGF0aCA9IGZpbGVQYXRoLmpvaW4oJy8nKTtcbiAgICAgICAgICAgIHZhciBwYXRoID0gc2VydmljZU9wdGlvbnMuZm9sZGVyVHlwZSArICcvJyArIGZpbGVQYXRoO1xuICAgICAgICAgICAgdmFyIGJvdW5kYXJ5ID0gJy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLTdkYTI0ZjJlNTAwNDYnO1xuXG4gICAgICAgICAgICB2YXIgYm9keSA9ICctLScgKyBib3VuZGFyeSArICdcXHJcXG4nICtcbiAgICAgICAgICAgICAgICAnQ29udGVudC1EaXNwb3NpdGlvbjogZm9ybS1kYXRhOyBuYW1lPVwiZmlsZVwiOycgK1xuICAgICAgICAgICAgICAgICdmaWxlbmFtZT1cIicgKyBmaWxlTmFtZSArICdcIlxcclxcbicgK1xuICAgICAgICAgICAgICAgICdDb250ZW50LXR5cGU6IHRleHQvaHRtbFxcclxcblxcclxcbicgK1xuICAgICAgICAgICAgICAgIGNvbnRlbnRzICsgJ1xcclxcbicgK1xuICAgICAgICAgICAgICAgICctLScgKyBib3VuZGFyeSArICctLSc7XG5cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2ZpbGUnKSArIHBhdGgsXG4gICAgICAgICAgICAgICAgZGF0YTogYm9keSxcbiAgICAgICAgICAgICAgICBjb250ZW50VHlwZTogJ211bHRpcGFydC9mb3JtLWRhdGE7IGJvdW5kYXJ5PScgKyBib3VuZGFyeVxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnB1dChib2R5LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMgdGhlIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBgZmlsZVBhdGhgIFBhdGggdG8gdGhlIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBgb3B0aW9uc2AgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnNcbiAgICAgICAgICovXG4gICAgICAgIHJlbW92ZTogZnVuY3Rpb24gKGZpbGVQYXRoLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHNlcnZpY2VPcHRpb25zLmZvbGRlclR5cGUgKyAnLycgKyBmaWxlUGF0aDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2ZpbGUnKSArIHBhdGhcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVuYW1lIHRoZSBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gZmlsZVBhdGggUGF0aCB0byB0aGUgZmlsZVxuICAgICAgICAgKiBAcGFyYW0gIHtTdGlybmd9IG5ld05hbWUgIE5ldyBuYW1lIG9mIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBvcHRpb25zICAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAgICAgICAqL1xuICAgICAgICByZW5hbWU6IGZ1bmN0aW9uIChmaWxlUGF0aCwgbmV3TmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhdGggPSBzZXJ2aWNlT3B0aW9ucy5mb2xkZXJUeXBlICsgJy8nICsgZmlsZVBhdGg7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdmaWxlJykgKyBwYXRoXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKHsgJ25hbWUnOiBuZXdOYW1lIH0sIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBc3luY0FQSSk7XG59O1xuIiwiLyoqXG4gKiAjIyBBc3NldCBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBBc3NldCBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHN0b3JlIGFzc2V0cyAtLSByZXNvdXJjZXMgb3IgZmlsZXMgb2YgYW55IGtpbmQgLS0gdXNlZCBieSBhIHByb2plY3Qgd2l0aCBhIHNjb3BlIHRoYXQgaXMgc3BlY2lmaWMgdG8gcHJvamVjdCwgZ3JvdXAsIG9yIGVuZCB1c2VyLlxuICpcbiAqIEFzc2V0cyBhcmUgdXNlZCB3aXRoIFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9wcm9qZWN0X2FkbWluLyN0ZWFtKS4gT25lIGNvbW1vbiB1c2UgY2FzZSBpcyBoYXZpbmcgZW5kIHVzZXJzIGluIGEgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSBvciBpbiBhIFttdWx0aXBsYXllciB3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKSB1cGxvYWQgZGF0YSAtLSB2aWRlb3MgY3JlYXRlZCBkdXJpbmcgZ2FtZSBwbGF5LCBwcm9maWxlIHBpY3R1cmVzIGZvciBjdXN0b21pemluZyB0aGVpciBleHBlcmllbmNlLCBldGMuIC0tIGFzIHBhcnQgb2YgcGxheWluZyB0aHJvdWdoIHRoZSBwcm9qZWN0LlxuICpcbiAqIFJlc291cmNlcyBjcmVhdGVkIHVzaW5nIHRoZSBBc3NldCBBZGFwdGVyIGFyZSBzY29wZWQ6XG4gKlxuICogICogUHJvamVjdCBhc3NldHMgYXJlIHdyaXRhYmxlIG9ubHkgYnkgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pLCB0aGF0IGlzLCBFcGljZW50ZXIgYXV0aG9ycy5cbiAqICAqIEdyb3VwIGFzc2V0cyBhcmUgd3JpdGFibGUgYnkgYW55b25lIHdpdGggYWNjZXNzIHRvIHRoZSBwcm9qZWN0IHRoYXQgaXMgcGFydCBvZiB0aGF0IHBhcnRpY3VsYXIgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS4gVGhpcyBpbmNsdWRlcyBhbGwgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIChFcGljZW50ZXIgYXV0aG9ycykgYW5kIGFueSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiB0aGUgZ3JvdXAgLS0gYm90aCBmYWNpbGl0YXRvcnMgYW5kIHN0YW5kYXJkIGVuZCB1c2Vycy5cbiAqICAqIFVzZXIgYXNzZXRzIGFyZSB3cml0YWJsZSBieSB0aGUgc3BlY2lmaWMgZW5kIHVzZXIsIGFuZCBieSB0aGUgZmFjaWxpdGF0b3Igb2YgdGhlIGdyb3VwLlxuICogICogQWxsIGFzc2V0cyBhcmUgcmVhZGFibGUgYnkgYW55b25lIHdpdGggdGhlIGV4YWN0IFVSSS5cbiAqXG4gKiBUbyB1c2UgdGhlIEFzc2V0IEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSkgYW5kIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKS4gVGhlIGdyb3VwIG5hbWUgaXMgcmVxdWlyZWQgZm9yIGFzc2V0cyB3aXRoIGEgZ3JvdXAgc2NvcGUsIGFuZCB0aGUgZ3JvdXAgbmFtZSBhbmQgdXNlcklkIGFyZSByZXF1aXJlZCBmb3IgYXNzZXRzIHdpdGggYSB1c2VyIHNjb3BlLiBJZiBub3QgaW5jbHVkZWQsIHRoZXkgYXJlIHRha2VuIGZyb20gdGhlIGxvZ2dlZCBpbiB1c2VyJ3Mgc2Vzc2lvbiBpbmZvcm1hdGlvbiBpZiBuZWVkZWQuXG4gKlxuICogV2hlbiBjcmVhdGluZyBhbiBhc3NldCwgeW91IGNhbiBwYXNzIGluIHRleHQgKGVuY29kZWQgZGF0YSkgdG8gdGhlIGBjcmVhdGUoKWAgY2FsbC4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBtYWtlIHRoZSBgY3JlYXRlKClgIGNhbGwgYXMgcGFydCBvZiBhbiBIVE1MIGZvcm0gYW5kIHBhc3MgaW4gYSBmaWxlIHVwbG9hZGVkIHZpYSB0aGUgZm9ybS5cbiAqXG4gKiAgICAgICAvLyBpbnN0YW50aWF0ZSB0aGUgQXNzZXQgQWRhcHRlclxuICogICAgICAgdmFyIGFhID0gbmV3IEYuc2VydmljZS5Bc3NldCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gKiAgICAgICAgICB1c2VySWQ6ICcxMjM0NSdcbiAqICAgICAgIH0pO1xuICpcbiAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAqICAgICAgIGFhLmNyZWF0ZSgndGVzdC50eHQnLCB7XG4gKiAgICAgICAgICAgZW5jb2Rpbmc6ICdCQVNFXzY0JyxcbiAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICogICAgICAgfSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICpcbiAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAqICAgICAgIC8vIHRoaXMgc2FtcGxlIGNvZGUgZ29lcyB3aXRoIGFuIGh0bWwgZm9ybSB0aGF0IGxvb2tzIGxpa2UgdGhpczpcbiAqICAgICAgIC8vXG4gKiAgICAgICAvLyA8Zm9ybSBpZD1cInVwbG9hZC1maWxlXCI+XG4gKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlVwbG9hZCBteUZpbGU8L2J1dHRvbj5cbiAqICAgICAgIC8vIDwvZm9ybT5cbiAqICAgICAgIC8vXG4gKiAgICAgICAkKCcjdXBsb2FkLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAqICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAqXG4gKiAgICAgICAgICBhYS5jcmVhdGUoZmlsZW5hbWUsIGRhdGEsIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAqICAgICAgIH0pO1xuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xuXG52YXIgYXBpRW5kcG9pbnQgPSAnYXNzZXQnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcHJvamVjdCBpZC4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBncm91cCBuYW1lLiBEZWZhdWx0cyB0byBzZXNzaW9uJ3MgYGdyb3VwTmFtZWAuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBncm91cDogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHVzZXIgaWQuIERlZmF1bHRzIHRvIHNlc3Npb24ncyBgdXNlcklkYC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHNjb3BlIGZvciB0aGUgYXNzZXQuIFZhbGlkIHZhbHVlcyBhcmU6IGB1c2VyYCwgYGdyb3VwYCwgYW5kIGBwcm9qZWN0YC4gU2VlIGFib3ZlIGZvciB0aGUgcmVxdWlyZWQgcGVybWlzc2lvbnMgdG8gd3JpdGUgdG8gZWFjaCBzY29wZS4gRGVmYXVsdHMgdG8gYHVzZXJgLCBtZWFuaW5nIHRoZSBjdXJyZW50IGVuZCB1c2VyIG9yIGEgZmFjaWxpdGF0b3IgaW4gdGhlIGVuZCB1c2VyJ3MgZ3JvdXAgY2FuIGVkaXQgdGhlIGFzc2V0LlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgc2NvcGU6ICd1c2VyJyxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIERldGVybWluZXMgaWYgYSByZXF1ZXN0IHRvIGxpc3QgdGhlIGFzc2V0cyBpbiBhIHNjb3BlIGluY2x1ZGVzIHRoZSBjb21wbGV0ZSBVUkwgZm9yIGVhY2ggYXNzZXQgKGB0cnVlYCksIG9yIG9ubHkgdGhlIGZpbGUgbmFtZXMgb2YgdGhlIGFzc2V0cyAoYGZhbHNlYCkuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBmdWxsVXJsOiB0cnVlLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHRyYW5zcG9ydCBvYmplY3QgY29udGFpbnMgdGhlIG9wdGlvbnMgcGFzc2VkIHRvIHRoZSBYSFIgcmVxdWVzdC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge1xuICAgICAgICAgICAgcHJvY2Vzc0RhdGE6IGZhbHNlXG4gICAgICAgIH1cbiAgICB9O1xuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuXG4gICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLmFjY291bnQgPSB1cmxDb25maWcuYWNjb3VudFBhdGg7XG4gICAgfVxuXG4gICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLnByb2plY3QgPSB1cmxDb25maWcucHJvamVjdFBhdGg7XG4gICAgfVxuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgYXNzZXRBcGlQYXJhbXMgPSBbJ2VuY29kaW5nJywgJ2RhdGEnLCAnY29udGVudFR5cGUnXTtcbiAgICB2YXIgc2NvcGVDb25maWcgPSB7XG4gICAgICAgIHVzZXI6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJywgJ3VzZXJJZCddLFxuICAgICAgICBncm91cDogWydzY29wZScsICdhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSxcbiAgICAgICAgcHJvamVjdDogWydzY29wZScsICdhY2NvdW50JywgJ3Byb2plY3QnXSxcbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlRmlsZW5hbWUgPSBmdW5jdGlvbiAoZmlsZW5hbWUpIHtcbiAgICAgICAgaWYgKCFmaWxlbmFtZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdmaWxlbmFtZSBpcyBuZWVkZWQuJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlVXJsUGFyYW1zID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHBhcnRLZXlzID0gc2NvcGVDb25maWdbb3B0aW9ucy5zY29wZV07XG4gICAgICAgIGlmICghcGFydEtleXMpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignc2NvcGUgcGFyYW1ldGVyIGlzIG5lZWRlZC4nKTtcbiAgICAgICAgfVxuXG4gICAgICAgICQuZWFjaChwYXJ0S2V5cywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKCFvcHRpb25zW3RoaXNdKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHRoaXMgKyAnIHBhcmFtZXRlciBpcyBuZWVkZWQuJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICB2YXIgYnVpbGRVcmwgPSBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFsaWRhdGVVcmxQYXJhbXMob3B0aW9ucyk7XG4gICAgICAgIHZhciBwYXJ0S2V5cyA9IHNjb3BlQ29uZmlnW29wdGlvbnMuc2NvcGVdO1xuICAgICAgICB2YXIgcGFydHMgPSAkLm1hcChwYXJ0S2V5cywgZnVuY3Rpb24gKGtleSkge1xuICAgICAgICAgICAgcmV0dXJuIG9wdGlvbnNba2V5XTtcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChmaWxlbmFtZSkge1xuICAgICAgICAgICAgLy8gVGhpcyBwcmV2ZW50cyBhZGRpbmcgYSB0cmFpbGluZyAvIGluIHRoZSBVUkwgYXMgdGhlIEFzc2V0IEFQSVxuICAgICAgICAgICAgLy8gZG9lcyBub3Qgd29yayBjb3JyZWN0bHkgd2l0aCBpdFxuICAgICAgICAgICAgZmlsZW5hbWUgPSAnLycgKyBmaWxlbmFtZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcGFydHMuam9pbignLycpICsgZmlsZW5hbWU7XG4gICAgfTtcblxuICAgIC8vIFByaXZhdGUgZnVuY3Rpb24sIGFsbCByZXF1ZXN0cyBmb2xsb3cgYSBtb3JlIG9yIGxlc3Mgc2FtZSBhcHByb2FjaCB0b1xuICAgIC8vIHVzZSB0aGUgQXNzZXQgQVBJIGFuZCB0aGUgZGlmZmVyZW5jZSBpcyB0aGUgSFRUUCB2ZXJiXG4gICAgLy9cbiAgICAvLyBAcGFyYW0ge3N0cmluZ30gYG1ldGhvZGAgKFJlcXVpcmVkKSBIVFRQIHZlcmJcbiAgICAvLyBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gZGVsZXRlL3JlcGxhY2UvY3JlYXRlXG4gICAgLy8gQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSVxuICAgIC8vIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICB2YXIgdXBsb2FkID0gZnVuY3Rpb24gKG1ldGhvZCwgZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICB2YWxpZGF0ZUZpbGVuYW1lKGZpbGVuYW1lKTtcbiAgICAgICAgLy8gbWFrZSBzdXJlIHRoZSBwYXJhbWV0ZXIgaXMgY2xlYW5cbiAgICAgICAgbWV0aG9kID0gbWV0aG9kLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIHZhciBjb250ZW50VHlwZSA9IHBhcmFtcyBpbnN0YW5jZW9mIEZvcm1EYXRhID09PSB0cnVlID8gZmFsc2UgOiAnYXBwbGljYXRpb24vanNvbic7XG4gICAgICAgIGlmIChjb250ZW50VHlwZSA9PT0gJ2FwcGxpY2F0aW9uL2pzb24nKSB7XG4gICAgICAgICAgICAvLyB3aGl0ZWxpc3QgdGhlIGZpZWxkcyB0aGF0IHdlIGFjdHVhbGx5IGNhbiBzZW5kIHRvIHRoZSBhcGlcbiAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgYXNzZXRBcGlQYXJhbXMpO1xuICAgICAgICB9IGVsc2UgeyAvLyBlbHNlIHdlJ3JlIHNlbmRpbmcgZm9ybSBkYXRhIHdoaWNoIGdvZXMgZGlyZWN0bHkgaW4gcmVxdWVzdCBib2R5XG4gICAgICAgICAgICAvLyBGb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSB1cGxvYWRzIHRoZSBmaWxlbmFtZSBpcyBub3Qgc2V0IGluIHRoZSBVUkwsXG4gICAgICAgICAgICAvLyBpdCdzIGdldHRpbmcgcGlja2VkIGJ5IHRoZSBGb3JtRGF0YSBmaWVsZCBmaWxlbmFtZS5cbiAgICAgICAgICAgIGZpbGVuYW1lID0gbWV0aG9kID09PSAncG9zdCcgfHwgbWV0aG9kID09PSAncHV0JyA/ICcnIDogZmlsZW5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICB2YXIgdXJsID0gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICB2YXIgY3JlYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsLCBjb250ZW50VHlwZTogY29udGVudFR5cGUgfSk7XG5cbiAgICAgICAgcmV0dXJuIGh0dHBbbWV0aG9kXShwYXJhbXMsIGNyZWF0ZU9wdGlvbnMpO1xuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICAvKipcbiAgICAgICAgKiBDcmVhdGVzIGEgZmlsZSBpbiB0aGUgQXNzZXQgQVBJLiBUaGUgc2VydmVyIHJldHVybnMgYW4gZXJyb3IgKHN0YXR1cyBjb2RlIGA0MDlgLCBjb25mbGljdCkgaWYgdGhlIGZpbGUgYWxyZWFkeSBleGlzdHMsIHNvXG4gICAgICAgICogY2hlY2sgZmlyc3Qgd2l0aCBhIGBsaXN0KClgIG9yIGEgYGdldCgpYC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIGFhID0gbmV3IEYuc2VydmljZS5Bc3NldCh7XG4gICAgICAgICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gICAgICAgICogICAgICAgICAgdXNlcklkOiAnJ1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgLy8gY3JlYXRlIGEgbmV3IGFzc2V0IHVzaW5nIGVuY29kZWQgdGV4dFxuICAgICAgICAqICAgICAgIGFhLmNyZWF0ZSgndGVzdC50eHQnLCB7XG4gICAgICAgICogICAgICAgICAgIGVuY29kaW5nOiAnQkFTRV82NCcsXG4gICAgICAgICogICAgICAgICAgIGRhdGE6ICdWR2hwY3lCcGN5QmhJSFJsYzNRZ1ptbHNaUzQ9JyxcbiAgICAgICAgKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICAgICAgICAqICAgICAgIH0sIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAgICAgICAgKiAgICAgICAvLyB0aGlzIHNhbXBsZSBjb2RlIGdvZXMgd2l0aCBhbiBodG1sIGZvcm0gdGhhdCBsb29rcyBsaWtlIHRoaXM6XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAvLyA8Zm9ybSBpZD1cInVwbG9hZC1maWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlXCIgdHlwZT1cImZpbGVcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVuYW1lXCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cIm15RmlsZS50eHRcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlVwbG9hZCBteUZpbGU8L2J1dHRvbj5cbiAgICAgICAgKiAgICAgICAvLyA8L2Zvcm0+XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAkKCcjdXBsb2FkLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgKiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGZpbGVuYW1lID0gJCgnI2ZpbGVuYW1lJykudmFsKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgaW5wdXRDb250cm9sID0gJCgnI2ZpbGUnKVswXTtcbiAgICAgICAgKiAgICAgICAgICBkYXRhLmFwcGVuZCgnZmlsZScsIGlucHV0Q29udHJvbC5maWxlc1swXSwgZmlsZW5hbWUpO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgICAgYWEuY3JlYXRlKGZpbGVuYW1lLCBkYXRhLCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSB0byBjcmVhdGUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSS4gUmVxdWlyZWQgaWYgdGhlIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLCBvdGhlcndpc2UgaWdub3JlZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5lbmNvZGluZ2AgRWl0aGVyIGBIRVhgIG9yIGBCQVNFXzY0YC4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZGF0YWAgVGhlIGVuY29kZWQgZGF0YSBmb3IgdGhlIGZpbGUuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmNvbnRlbnRUeXBlYCBUaGUgbWltZSB0eXBlIG9mIHRoZSBmaWxlLiBPcHRpb25hbC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgY3JlYXRlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHVwbG9hZCgncG9zdCcsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgYSBmaWxlIGZyb20gdGhlIEFzc2V0IEFQSSwgZmV0Y2hpbmcgdGhlIGFzc2V0IGNvbnRlbnQuIChUbyBnZXQgYSBsaXN0XG4gICAgICAgICogb2YgdGhlIGFzc2V0cyBpbiBhIHNjb3BlLCB1c2UgYGxpc3QoKWAuKVxuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIHJldHJpZXZlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGdldFNlcnZpY2VPcHRpb25zID0gX3BpY2soc2VydmljZU9wdGlvbnMsIFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJywgJ3VzZXJJZCddKTtcbiAgICAgICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIGdldFNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciB1cmwgPSBidWlsZFVybChmaWxlbmFtZSwgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoe30sIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIGxpc3Qgb2YgdGhlIGFzc2V0cyBpbiBhIHNjb3BlLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIGFhLmxpc3QoeyBmdWxsVXJsOiB0cnVlIH0pLnRoZW4oZnVuY3Rpb24oZmlsZUxpc3Qpe1xuICAgICAgICAqICAgICAgICAgICBjb25zb2xlLmxvZygnYXJyYXkgb2YgZmlsZXMgPSAnLCBmaWxlTGlzdCk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLnNjb3BlYCAoT3B0aW9uYWwpIFRoZSBzY29wZSAoYHVzZXJgLCBgZ3JvdXBgLCBgcHJvamVjdGApLlxuICAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gYG9wdGlvbnMuZnVsbFVybGAgKE9wdGlvbmFsKSBEZXRlcm1pbmVzIGlmIHRoZSBsaXN0IG9mIGFzc2V0cyBpbiBhIHNjb3BlIGluY2x1ZGVzIHRoZSBjb21wbGV0ZSBVUkwgZm9yIGVhY2ggYXNzZXQgKGB0cnVlYCksIG9yIG9ubHkgdGhlIGZpbGUgbmFtZXMgb2YgdGhlIGFzc2V0cyAoYGZhbHNlYCkuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgbGlzdDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIHVybCA9IGJ1aWxkVXJsKCcnLCB1cmxPcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHVybE9wdGlvbnMsIHsgdXJsOiB1cmwgfSk7XG4gICAgICAgICAgICB2YXIgZnVsbFVybCA9IGdldE9wdGlvbnMuZnVsbFVybDtcblxuICAgICAgICAgICAgaWYgKCFmdWxsVXJsKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaHR0cC5nZXQoe30sIGdldE9wdGlvbnMpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKGZpbGVzKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBmdWxsUGF0aEZpbGVzID0gJC5tYXAoZmlsZXMsIGZ1bmN0aW9uIChmaWxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gYnVpbGRVcmwoZmlsZSwgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShmdWxsUGF0aEZpbGVzLCBtZSk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZmFpbChkdGQucmVqZWN0KTtcblxuICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmVwbGFjZXMgYW4gZXhpc3RpbmcgZmlsZSBpbiB0aGUgQXNzZXQgQVBJLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIHJlcGxhY2UgYW4gYXNzZXQgdXNpbmcgZW5jb2RlZCB0ZXh0XG4gICAgICAgICogICAgICAgYWEucmVwbGFjZSgndGVzdC50eHQnLCB7XG4gICAgICAgICogICAgICAgICAgIGVuY29kaW5nOiAnQkFTRV82NCcsXG4gICAgICAgICogICAgICAgICAgIGRhdGE6ICdWR2hwY3lCcGN5QmhJSE5sWTI5dVpDQjBaWE4wSUdacGJHVXUnLFxuICAgICAgICAqICAgICAgICAgICBjb250ZW50VHlwZTogJ3RleHQvcGxhaW4nXG4gICAgICAgICogICAgICAgfSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgLy8gYWx0ZXJuYXRpdmVseSwgcmVwbGFjZSBhbiBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAgICAgICAgKiAgICAgICAvLyB0aGlzIHNhbXBsZSBjb2RlIGdvZXMgd2l0aCBhbiBodG1sIGZvcm0gdGhhdCBsb29rcyBsaWtlIHRoaXM6XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAvLyA8Zm9ybSBpZD1cInJlcGxhY2UtZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwiZmlsZVwiIHR5cGU9XCJmaWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJyZXBsYWNlLWZpbGVuYW1lXCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cIm15RmlsZS50eHRcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlJlcGxhY2UgbXlGaWxlPC9idXR0b24+XG4gICAgICAgICogICAgICAgLy8gPC9mb3JtPlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgJCgnI3JlcGxhY2UtZmlsZScpLm9uKCdzdWJtaXQnLCBmdW5jdGlvbiAoZSkge1xuICAgICAgICAqICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgZmlsZW5hbWUgPSAkKCcjcmVwbGFjZS1maWxlbmFtZScpLnZhbCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBkYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGlucHV0Q29udHJvbCA9ICQoJyNmaWxlJylbMF07XG4gICAgICAgICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgIGFhLnJlcGxhY2UoZmlsZW5hbWUsIGRhdGEsIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSBiZWluZyByZXBsYWNlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgKE9wdGlvbmFsKSBCb2R5IHBhcmFtZXRlcnMgdG8gc2VuZCB0byB0aGUgQXNzZXQgQVBJLiBSZXF1aXJlZCBpZiB0aGUgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAsIG90aGVyd2lzZSBpZ25vcmVkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmVuY29kaW5nYCBFaXRoZXIgYEhFWGAgb3IgYEJBU0VfNjRgLiBSZXF1aXJlZCBpZiBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5kYXRhYCBUaGUgZW5jb2RlZCBkYXRhIGZvciB0aGUgZmlsZS4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuY29udGVudFR5cGVgIFRoZSBtaW1lIHR5cGUgb2YgdGhlIGZpbGUuIE9wdGlvbmFsLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICByZXBsYWNlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHVwbG9hZCgncHV0JywgZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogRGVsZXRlcyBhIGZpbGUgZnJvbSB0aGUgQXNzZXQgQVBJLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIGFhLmRlbGV0ZShzYW1wbGVGaWxlTmFtZSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gZGVsZXRlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBkZWxldGU6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHVwbG9hZCgnZGVsZXRlJywgZmlsZW5hbWUsIHt9LCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICBhc3NldFVybDogZnVuY3Rpb24gKGZpbGVuYW1lLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgdXJsT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICByZXR1cm4gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICpcbiAqICMjIEF1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhlIEF1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlIHByb3ZpZGVzIGEgbWV0aG9kIGZvciBsb2dnaW5nIGluLCB3aGljaCBjcmVhdGVzIGFuZCByZXR1cm5zIGEgdXNlciBhY2Nlc3MgdG9rZW4uXG4gKlxuICogVXNlciBhY2Nlc3MgdG9rZW5zIGFyZSByZXF1aXJlZCBmb3IgZWFjaCBjYWxsIHRvIEVwaWNlbnRlci4gKFNlZSBbUHJvamVjdCBBY2Nlc3NdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykgZm9yIG1vcmUgaW5mb3JtYXRpb24uKVxuICpcbiAqIElmIHlvdSBuZWVkIGFkZGl0aW9uYWwgZnVuY3Rpb25hbGl0eSAtLSBzdWNoIGFzIHRyYWNraW5nIHNlc3Npb24gaW5mb3JtYXRpb24sIGVhc2lseSByZXRyaWV2aW5nIHRoZSB1c2VyIHRva2VuLCBvciBnZXR0aW5nIHRoZSBncm91cHMgdG8gd2hpY2ggYW4gZW5kIHVzZXIgYmVsb25ncyAtLSBjb25zaWRlciB1c2luZyB0aGUgW0F1dGhvcml6YXRpb24gTWFuYWdlcl0oLi4vYXV0aC1tYW5hZ2VyLykgaW5zdGVhZC5cbiAqXG4gKiAgICAgIHZhciBhdXRoID0gbmV3IEYuc2VydmljZS5BdXRoKCk7XG4gKiAgICAgIGF1dGgubG9naW4oeyB1c2VyTmFtZTogJ2pzbWl0aEBhY21lc2ltdWxhdGlvbnMuY29tJyxcbiAqICAgICAgICAgICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCcgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVtYWlsIG9yIHVzZXJuYW1lIHRvIHVzZSBmb3IgbG9nZ2luZyBpbi4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdXNlck5hbWU6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBQYXNzd29yZCBmb3Igc3BlY2lmaWVkIGB1c2VyTmFtZWAuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHBhc3N3b3JkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQgZm9yIHRoaXMgYHVzZXJOYW1lYC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciB0aGUgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIFJlcXVpcmVkIGlmIHRoZSBgdXNlck5hbWVgIGlzIGZvciBhbiBbZW5kIHVzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGFjY291bnQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgnYXV0aGVudGljYXRpb24nKVxuICAgIH0pO1xuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2dzIHVzZXIgaW4sIHJldHVybmluZyB0aGUgdXNlciBhY2Nlc3MgdG9rZW4uXG4gICAgICAgICAqXG4gICAgICAgICAqIElmIG5vIGB1c2VyTmFtZWAgb3IgYHBhc3N3b3JkYCB3ZXJlIHByb3ZpZGVkIGluIHRoZSBpbml0aWFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucywgdGhleSBhcmUgcmVxdWlyZWQgaW4gdGhlIGBvcHRpb25zYCBoZXJlLiBJZiBubyBgYWNjb3VudGAgd2FzIHByb3ZpZGVkIGluIHRoZSBpbml0aWFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBhbmQgdGhlIGB1c2VyTmFtZWAgaXMgZm9yIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgdGhlIGBhY2NvdW50YCBpcyByZXF1aXJlZCBhcyB3ZWxsLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGF1dGgubG9naW4oe1xuICAgICAgICAgKiAgICAgICAgICB1c2VyTmFtZTogJ2pzbWl0aCcsXG4gICAgICAgICAqICAgICAgICAgIHBhc3N3b3JkOiAncGFzc3cwcmQnLFxuICAgICAgICAgKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycgfSlcbiAgICAgICAgICogICAgICAudGhlbihmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgICAgICogICAgICAgICAgY29uc29sZS5sb2coXCJ1c2VyIGFjY2VzcyB0b2tlbiBpczogXCIsIHRva2VuLmFjY2Vzc190b2tlbik7XG4gICAgICAgICAqICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvZ2luOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgeyBzdWNjZXNzOiAkLm5vb3AgfSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaWYgKCFodHRwT3B0aW9ucy51c2VyTmFtZSB8fCAhaHR0cE9wdGlvbnMucGFzc3dvcmQpIHtcbiAgICAgICAgICAgICAgICB2YXIgcmVzcCA9IHsgc3RhdHVzOiA0MDEsIHN0YXR1c01lc3NhZ2U6ICdObyB1c2VybmFtZSBvciBwYXNzd29yZCBzcGVjaWZpZWQuJyB9O1xuICAgICAgICAgICAgICAgIGlmIChvcHRpb25zLmVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuZXJyb3IuY2FsbCh0aGlzLCByZXNwKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlamVjdChyZXNwKS5wcm9taXNlKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBwb3N0UGFyYW1zID0ge1xuICAgICAgICAgICAgICAgIHVzZXJOYW1lOiBodHRwT3B0aW9ucy51c2VyTmFtZSxcbiAgICAgICAgICAgICAgICBwYXNzd29yZDogaHR0cE9wdGlvbnMucGFzc3dvcmQsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgaWYgKGh0dHBPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgICAgICAgICAvL3Bhc3MgaW4gbnVsbCBmb3IgYWNjb3VudCB1bmRlciBvcHRpb25zIGlmIHlvdSBkb24ndCB3YW50IGl0IHRvIGJlIHNlbnRcbiAgICAgICAgICAgICAgICBwb3N0UGFyYW1zLmFjY291bnQgPSBodHRwT3B0aW9ucy5hY2NvdW50O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBvc3RQYXJhbXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvLyAocmVwbGFjZSB3aXRoIC8qICovIGNvbW1lbnQgYmxvY2ssIHRvIG1ha2UgdmlzaWJsZSBpbiBkb2NzLCBvbmNlIHRoaXMgaXMgbW9yZSB0aGFuIGEgbm9vcClcbiAgICAgICAgLy9cbiAgICAgICAgLy8gTG9ncyB1c2VyIG91dCBmcm9tIHNwZWNpZmllZCBhY2NvdW50cy5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gRXBpY2VudGVyIGxvZ291dCBpcyBub3QgaW1wbGVtZW50ZWQgeWV0LCBzbyBmb3Igbm93IHRoaXMgaXMgYSBkdW1teSBwcm9taXNlIHRoYXQgZ2V0cyBhdXRvbWF0aWNhbGx5IHJlc29sdmVkLlxuICAgICAgICAvL1xuICAgICAgICAvLyAqKkV4YW1wbGUqKlxuICAgICAgICAvL1xuICAgICAgICAvLyAgICAgIGF1dGgubG9nb3V0KCk7XG4gICAgICAgIC8vXG4gICAgICAgIC8vICoqUGFyYW1ldGVycyoqXG4gICAgICAgIC8vIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgLy9cbiAgICAgICAgbG9nb3V0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIGR0ZC5yZXNvbHZlKCk7XG4gICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxuLyoqXG4gKiAjIyBDaGFubmVsIFNlcnZpY2VcbiAqXG4gKiBUaGUgRXBpY2VudGVyIHBsYXRmb3JtIHByb3ZpZGVzIGEgcHVzaCBjaGFubmVsLCB3aGljaCBhbGxvd3MgeW91IHRvIHB1Ymxpc2ggYW5kIHN1YnNjcmliZSB0byBtZXNzYWdlcyB3aXRoaW4gYSBbcHJvamVjdF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3Byb2plY3RzKSwgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSwgb3IgW211bHRpcGxheWVyIHdvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLiBUaGVyZSBhcmUgdHdvIG1haW4gdXNlIGNhc2VzIGZvciB0aGUgY2hhbm5lbDogZXZlbnQgbm90aWZpY2F0aW9ucyBhbmQgY2hhdCBtZXNzYWdlcy5cbiAqXG4gKiBUaGUgQ2hhbm5lbCBTZXJ2aWNlIGlzIGEgYnVpbGRpbmcgYmxvY2sgZm9yIHRoaXMgZnVuY3Rpb25hbGl0eS4gSXQgY3JlYXRlcyBhIHB1Ymxpc2gtc3Vic2NyaWJlIG9iamVjdCwgYWxsb3dpbmcgeW91IHRvIHB1Ymxpc2ggbWVzc2FnZXMsIHN1YnNjcmliZSB0byBtZXNzYWdlcywgb3IgdW5zdWJzY3JpYmUgZnJvbSBtZXNzYWdlcyBmb3IgYSBnaXZlbiAndG9waWMnIG9uIGEgYCQuY29tZXRkYCB0cmFuc3BvcnQgaW5zdGFuY2UuXG4gKlxuICogVHlwaWNhbGx5LCB5b3UgdXNlIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pIHRvIGNyZWF0ZSBvciByZXRyaWV2ZSBjaGFubmVscywgdGhlbiB1c2UgdGhlIENoYW5uZWwgU2VydmljZSBgc3Vic2NyaWJlKClgIGFuZCBgcHVibGlzaCgpYCBtZXRob2RzIHRvIGxpc3RlbiB0byBvciB1cGRhdGUgZGF0YS4gKEZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQgb24gRXBpY2VudGVyJ3MgcHVzaCBjaGFubmVsLCBzZWUgdGhlIGludHJvZHVjdG9yeSBub3RlcyBvbiB0aGUgW1B1c2ggQ2hhbm5lbCBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLykgcGFnZS4pXG4gKlxuICogWW91J2xsIG5lZWQgdG8gaW5jbHVkZSB0aGUgYGVwaWNlbnRlci1tdWx0aXBsYXllci1kZXBlbmRlbmNpZXMuanNgIGxpYnJhcnkgaW4gYWRkaXRpb24gdG8gdGhlIGBlcGljZW50ZXIuanNgIGxpYnJhcnkgaW4geW91ciBwcm9qZWN0IHRvIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlLiBTZWUgW0luY2x1ZGluZyBFcGljZW50ZXIuanNdKC4uLy4uLyNpbmNsdWRlKS5cbiAqXG4gKiBUbyB1c2UgdGhlIENoYW5uZWwgU2VydmljZSwgaW5zdGFudGlhdGUgaXQsIHRoZW4gbWFrZSBjYWxscyB0byBhbnkgb2YgdGhlIG1ldGhvZHMgeW91IG5lZWQuXG4gKlxuICogICAgICAgIHZhciBjcyA9IG5ldyBGLnNlcnZpY2UuQ2hhbm5lbCgpO1xuICogICAgICAgIGNzLnB1Ymxpc2goJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vdmFyaWFibGVzJywgeyBwcmljZTogNTAgfSk7XG4gKlxuICogVGhlIHBhcmFtZXRlcnMgZm9yIGluc3RhbnRpYXRpbmcgYSBDaGFubmVsIFNlcnZpY2UgaW5jbHVkZTpcbiAqXG4gKiAqIGBvcHRpb25zYCBUaGUgb3B0aW9ucyBvYmplY3QgdG8gY29uZmlndXJlIHRoZSBDaGFubmVsIFNlcnZpY2UuXG4gKiAqIGBvcHRpb25zLmJhc2VgIFRoZSBiYXNlIHRvcGljLiBUaGlzIGlzIGFkZGVkIGFzIGEgcHJlZml4IHRvIGFsbCBmdXJ0aGVyIHRvcGljcyB5b3UgcHVibGlzaCBvciBzdWJzY3JpYmUgdG8gd2hpbGUgd29ya2luZyB3aXRoIHRoaXMgQ2hhbm5lbCBTZXJ2aWNlLlxuICogKiBgb3B0aW9ucy50b3BpY1Jlc29sdmVyYCBBIGZ1bmN0aW9uIHRoYXQgcHJvY2Vzc2VzIGFsbCAndG9waWNzJyBwYXNzZWQgaW50byB0aGUgYHB1Ymxpc2hgIGFuZCBgc3Vic2NyaWJlYCBtZXRob2RzLiBUaGlzIGlzIHVzZWZ1bCBpZiB5b3Ugd2FudCB0byBpbXBsZW1lbnQgeW91ciBvd24gc2VyaWFsaXplIGZ1bmN0aW9ucyBmb3IgY29udmVydGluZyBjdXN0b20gb2JqZWN0cyB0byB0b3BpYyBuYW1lcy4gUmV0dXJucyBhIFN0cmluZy4gQnkgZGVmYXVsdCwgaXQganVzdCBlY2hvZXMgdGhlIHRvcGljLlxuICogKiBgb3B0aW9ucy50cmFuc3BvcnRgIFRoZSBpbnN0YW5jZSBvZiBgJC5jb21ldGRgIHRvIGhvb2sgb250by4gU2VlIGh0dHA6Ly9kb2NzLmNvbWV0ZC5vcmcvcmVmZXJlbmNlL2phdmFzY3JpcHQuaHRtbCBmb3IgYWRkaXRpb25hbCBiYWNrZ3JvdW5kIG9uIGNvbWV0ZC5cbiAqL1xudmFyIENoYW5uZWwgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGJhc2UgdG9waWMuIFRoaXMgaXMgYWRkZWQgYXMgYSBwcmVmaXggdG8gYWxsIGZ1cnRoZXIgdG9waWNzIHlvdSBwdWJsaXNoIG9yIHN1YnNjcmliZSB0byB3aGlsZSB3b3JraW5nIHdpdGggdGhpcyBDaGFubmVsIFNlcnZpY2UuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBiYXNlOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQSBmdW5jdGlvbiB0aGF0IHByb2Nlc3NlcyBhbGwgJ3RvcGljcycgcGFzc2VkIGludG8gdGhlIGBwdWJsaXNoYCBhbmQgYHN1YnNjcmliZWAgbWV0aG9kcy4gVGhpcyBpcyB1c2VmdWwgaWYgeW91IHdhbnQgdG8gaW1wbGVtZW50IHlvdXIgb3duIHNlcmlhbGl6ZSBmdW5jdGlvbnMgZm9yIGNvbnZlcnRpbmcgY3VzdG9tIG9iamVjdHMgdG8gdG9waWMgbmFtZXMuIEJ5IGRlZmF1bHQsIGl0IGp1c3QgZWNob2VzIHRoZSB0b3BpYy5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICpcbiAgICAgICAgICogKiBgdG9waWNgIFRvcGljIHRvIHBhcnNlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICogKlN0cmluZyo6IFRoaXMgZnVuY3Rpb24gc2hvdWxkIHJldHVybiBhIHN0cmluZyB0b3BpYy5cbiAgICAgICAgICpcbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgdG9waWNSZXNvbHZlcjogZnVuY3Rpb24gKHRvcGljKSB7XG4gICAgICAgICAgICByZXR1cm4gdG9waWM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBpbnN0YW5jZSBvZiBgJC5jb21ldGRgIHRvIGhvb2sgb250by5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDogbnVsbFxuICAgIH07XG4gICAgdGhpcy5jaGFubmVsT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgb3B0aW9ucyk7XG59O1xuXG52YXIgbWFrZU5hbWUgPSBmdW5jdGlvbiAoY2hhbm5lbE5hbWUsIHRvcGljKSB7XG4gICAgLy9SZXBsYWNlIHRyYWlsaW5nL2RvdWJsZSBzbGFzaGVzXG4gICAgdmFyIG5ld05hbWUgPSAoY2hhbm5lbE5hbWUgPyAoY2hhbm5lbE5hbWUgKyAnLycgKyB0b3BpYykgOiB0b3BpYykucmVwbGFjZSgvXFwvXFwvL2csICcvJykucmVwbGFjZSgvXFwvJC8sJycpO1xuICAgIHJldHVybiBuZXdOYW1lO1xufTtcblxuXG5DaGFubmVsLnByb3RvdHlwZSA9ICQuZXh0ZW5kKENoYW5uZWwucHJvdG90eXBlLCB7XG5cbiAgICAvLyBmdXR1cmUgZnVuY3Rpb25hbGl0eTpcbiAgICAvLyAgICAgIC8vIFNldCB0aGUgY29udGV4dCBmb3IgdGhlIGNhbGxiYWNrXG4gICAgLy8gICAgICBjcy5zdWJzY3JpYmUoJ3J1bicsIGZ1bmN0aW9uICgpIHsgdGhpcy5pbm5lckhUTUwgPSAnVHJpZ2dlcmVkJ30sIGRvY3VtZW50LmJvZHkpO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIENvbnRyb2wgdGhlIG9yZGVyIG9mIG9wZXJhdGlvbnMgYnkgc2V0dGluZyB0aGUgYHByaW9yaXR5YFxuICAgICAvLyAgICAgIGNzLnN1YnNjcmliZSgncnVuJywgY2IsIHRoaXMsIHtwcmlvcml0eTogOX0pO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIE9ubHkgZXhlY3V0ZSB0aGUgY2FsbGJhY2ssIGBjYmAsIGlmIHRoZSB2YWx1ZSBvZiB0aGUgYHByaWNlYCB2YXJpYWJsZSBpcyA1MFxuICAgICAvLyAgICAgIGNzLnN1YnNjcmliZSgncnVuL3ZhcmlhYmxlcy9wcmljZScsIGNiLCB0aGlzLCB7cHJpb3JpdHk6IDMwLCB2YWx1ZTogNTB9KTtcbiAgICAgLy9cbiAgICAgLy8gICAgICAvLyBPbmx5IGV4ZWN1dGUgdGhlIGNhbGxiYWNrLCBgY2JgLCBpZiB0aGUgdmFsdWUgb2YgdGhlIGBwcmljZWAgdmFyaWFibGUgaXMgZ3JlYXRlciB0aGFuIDUwXG4gICAgIC8vICAgICAgc3Vic2NyaWJlKCdydW4vdmFyaWFibGVzL3ByaWNlJywgY2IsIHRoaXMsIHtwcmlvcml0eTogMzAsIHZhbHVlOiAnPjUwJ30pO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIE9ubHkgZXhlY3V0ZSB0aGUgY2FsbGJhY2ssIGBjYmAsIGlmIHRoZSB2YWx1ZSBvZiB0aGUgYHByaWNlYCB2YXJpYWJsZSBpcyBldmVuXG4gICAgIC8vICAgICAgc3Vic2NyaWJlKCdydW4vdmFyaWFibGVzL3ByaWNlJywgY2IsIHRoaXMsIHtwcmlvcml0eTogMzAsIHZhbHVlOiBmdW5jdGlvbiAodmFsKSB7cmV0dXJuIHZhbCAlIDIgPT09IDB9fSk7XG5cblxuICAgIC8qKlxuICAgICAqIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGEgdG9waWMuXG4gICAgICpcbiAgICAgKiBUaGUgdG9waWMgc2hvdWxkIGluY2x1ZGUgdGhlIGZ1bGwgcGF0aCBvZiB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMpLCBwcm9qZWN0IGlkLCBhbmQgZ3JvdXAgbmFtZS4gKEluIG1vc3QgY2FzZXMsIGl0IGlzIHNpbXBsZXIgdG8gdXNlIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pIGluc3RlYWQsIGluIHdoaWNoIGNhc2UgdGhpcyBpcyBjb25maWd1cmVkIGZvciB5b3UuKVxuICAgICAqXG4gICAgICogICoqRXhhbXBsZXMqKlxuICAgICAqXG4gICAgICogICAgICB2YXIgY2IgPSBmdW5jdGlvbih2YWwpIHsgY29uc29sZS5sb2codmFsLmRhdGEpOyB9O1xuICAgICAqXG4gICAgICogICAgICAvLyBTdWJzY3JpYmUgdG8gY2hhbmdlcyBvbiBhIHRvcC1sZXZlbCAncnVuJyB0b3BpY1xuICAgICAqICAgICAgY3Muc3Vic2NyaWJlKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuJywgY2IpO1xuICAgICAqXG4gICAgICogICAgICAvLyBTdWJzY3JpYmUgdG8gY2hhbmdlcyBvbiBjaGlsZHJlbiBvZiB0aGUgJ3J1bicgdG9waWMuIE5vdGUgdGhpcyB3aWxsIGFsc28gYmUgdHJpZ2dlcmVkIGZvciBjaGFuZ2VzIHRvIHJ1bi54Lnkuei5cbiAgICAgKiAgICAgIGNzLnN1YnNjcmliZSgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi8qJywgY2IpO1xuICAgICAqXG4gICAgICogICAgICAvLyBTdWJzY3JpYmUgdG8gY2hhbmdlcyBvbiBib3RoIHRoZSB0b3AtbGV2ZWwgJ3J1bicgdG9waWMgYW5kIGl0cyBjaGlsZHJlblxuICAgICAqICAgICAgY3Muc3Vic2NyaWJlKFsnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bicsXG4gICAgICogICAgICAgICAgJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vKiddLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGEgcGFydGljdWxhciB2YXJpYWJsZVxuICAgICAqICAgICAgc3Vic2NyaWJlKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuL3ZhcmlhYmxlcy9wcmljZScsIGNiKTtcbiAgICAgKlxuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqU3RyaW5nKiBSZXR1cm5zIGEgdG9rZW4geW91IGNhbiBsYXRlciB1c2UgdG8gdW5zdWJzY3JpYmUuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xBcnJheX0gICBgdG9waWNgICAgIExpc3Qgb2YgdG9waWNzIHRvIGxpc3RlbiBmb3IgY2hhbmdlcyBvbi5cbiAgICAgKiBAcGFyYW0gIHtGdW5jdGlvbn0gYGNhbGxiYWNrYCBDYWxsYmFjayBmdW5jdGlvbiB0byBleGVjdXRlLiBDYWxsYmFjayBpcyBjYWxsZWQgd2l0aCBzaWduYXR1cmUgYChldnQsIHBheWxvYWQsIG1ldGFkYXRhKWAuXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSAgIGBjb250ZXh0YCAgQ29udGV4dCBpbiB3aGljaCB0aGUgYGNhbGxiYWNrYCBpcyBleGVjdXRlZC5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9ICAgYG9wdGlvbnNgICAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqIEBwYXJhbSAge051bWJlcn0gICBgb3B0aW9ucy5wcmlvcml0eWAgIFVzZWQgdG8gY29udHJvbCBvcmRlciBvZiBvcGVyYXRpb25zLiBEZWZhdWx0cyB0byAwLiBDYW4gYmUgYW55ICt2ZSBvciAtdmUgbnVtYmVyLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xOdW1iZXJ8RnVuY3Rpb259ICAgYG9wdGlvbnMudmFsdWVgIFRoZSBgY2FsbGJhY2tgIGlzIG9ubHkgdHJpZ2dlcmVkIGlmIHRoaXMgY29uZGl0aW9uIG1hdGNoZXMuIFNlZSBleGFtcGxlcyBmb3IgZGV0YWlscy5cbiAgICAgKlxuICAgICAqL1xuICAgIHN1YnNjcmliZTogZnVuY3Rpb24gKHRvcGljLCBjYWxsYmFjaywgY29udGV4dCwgb3B0aW9ucykge1xuXG4gICAgICAgIHZhciB0b3BpY3MgPSBbXS5jb25jYXQodG9waWMpO1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICB2YXIgc3Vic2NyaXB0aW9uSWRzID0gW107XG4gICAgICAgIHZhciBvcHRzID0gbWUuY2hhbm5lbE9wdGlvbnM7XG5cbiAgICAgICAgb3B0cy50cmFuc3BvcnQuYmF0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgJC5lYWNoKHRvcGljcywgZnVuY3Rpb24gKGluZGV4LCB0b3BpYykge1xuICAgICAgICAgICAgICAgIHRvcGljID0gbWFrZU5hbWUob3B0cy5iYXNlLCBvcHRzLnRvcGljUmVzb2x2ZXIodG9waWMpKTtcbiAgICAgICAgICAgICAgICBzdWJzY3JpcHRpb25JZHMucHVzaChvcHRzLnRyYW5zcG9ydC5zdWJzY3JpYmUodG9waWMsIGNhbGxiYWNrKSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiAoc3Vic2NyaXB0aW9uSWRzWzFdID8gc3Vic2NyaXB0aW9uSWRzIDogc3Vic2NyaXB0aW9uSWRzWzBdKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUHVibGlzaCBkYXRhIHRvIGEgdG9waWMuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGVzKipcbiAgICAgKlxuICAgICAqICAgICAgLy8gU2VuZCBkYXRhIHRvIGFsbCBzdWJzY3JpYmVycyBvZiB0aGUgJ3J1bicgdG9waWNcbiAgICAgKiAgICAgIGNzLnB1Ymxpc2goJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4nLCB7IGNvbXBsZXRlZDogZmFsc2UgfSk7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFNlbmQgZGF0YSB0byBhbGwgc3Vic2NyaWJlcnMgb2YgdGhlICdydW4vdmFyaWFibGVzJyB0b3BpY1xuICAgICAqICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi92YXJpYWJsZXMnLCB7IHByaWNlOiA1MCB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGB0b3BpY2AgVG9waWMgdG8gcHVibGlzaCB0by5cbiAgICAgKiBAcGFyYW0gIHsqfSBgZGF0YWAgIERhdGEgdG8gcHVibGlzaCB0byB0b3BpYy5cbiAgICAgKlxuICAgICAqL1xuICAgIHB1Ymxpc2g6IGZ1bmN0aW9uICh0b3BpYywgZGF0YSkge1xuICAgICAgICB2YXIgdG9waWNzID0gW10uY29uY2F0KHRvcGljKTtcbiAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgdmFyIHJldHVybk9ianMgPSBbXTtcbiAgICAgICAgdmFyIG9wdHMgPSBtZS5jaGFubmVsT3B0aW9ucztcblxuXG4gICAgICAgIG9wdHMudHJhbnNwb3J0LmJhdGNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICQuZWFjaCh0b3BpY3MsIGZ1bmN0aW9uIChpbmRleCwgdG9waWMpIHtcbiAgICAgICAgICAgICAgICB0b3BpYyA9IG1ha2VOYW1lKG9wdHMuYmFzZSwgb3B0cy50b3BpY1Jlc29sdmVyKHRvcGljKSk7XG4gICAgICAgICAgICAgICAgaWYgKHRvcGljLmNoYXJBdCh0b3BpYy5sZW5ndGggLSAxKSA9PT0gJyonKSB7XG4gICAgICAgICAgICAgICAgICAgIHRvcGljID0gdG9waWMucmVwbGFjZSgvXFwqKyQvLCAnJyk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignWW91IGNhbiBjYW5ub3QgcHVibGlzaCB0byBjaGFubmVscyB3aXRoIHdpbGRjYXJkcy4gUHVibGlzaGluZyB0byAnLCB0b3BpYywgJ2luc3RlYWQnKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuT2Jqcy5wdXNoKG9wdHMudHJhbnNwb3J0LnB1Ymxpc2godG9waWMsIGRhdGEpKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIChyZXR1cm5PYmpzWzFdID8gcmV0dXJuT2JqcyA6IHJldHVybk9ianNbMF0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBVbnN1YnNjcmliZSBmcm9tIGNoYW5nZXMgdG8gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIGNzLnVuc3Vic2NyaWJlKCdzYW1wbGVUb2tlbicpO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGB0b2tlbmAgVGhlIHRva2VuIGZvciB0b3BpYyBpcyByZXR1cm5lZCB3aGVuIHlvdSBpbml0aWFsbHkgc3Vic2NyaWJlLiBQYXNzIGl0IGhlcmUgdG8gdW5zdWJzY3JpYmUgZnJvbSB0aGF0IHRvcGljLlxuICAgICAqL1xuICAgIHVuc3Vic2NyaWJlOiBmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgICAgdGhpcy5jaGFubmVsT3B0aW9ucy50cmFuc3BvcnQudW5zdWJzY3JpYmUodG9rZW4pO1xuICAgICAgICByZXR1cm4gdG9rZW47XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0YXJ0IGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqXG4gICAgICogU3VwcG9ydGVkIGV2ZW50cyBhcmU6IGBjb25uZWN0YCwgYGRpc2Nvbm5lY3RgLCBgc3Vic2NyaWJlYCwgYHVuc3Vic2NyaWJlYCwgYHB1Ymxpc2hgLCBgZXJyb3JgLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29uLy5cbiAgICAgKi9cbiAgICBvbjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub24uYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RvcCBsaXN0ZW5pbmcgZm9yIGV2ZW50cyBvbiB0aGlzIGluc3RhbmNlLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKi9cbiAgICBvZmY6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLm9mZi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUcmlnZ2VyIGV2ZW50cyBhbmQgZXhlY3V0ZSBoYW5kbGVycy4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKi9cbiAgICB0cmlnZ2VyOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBDaGFubmVsO1xuIiwiLyoqXG4gKiBAY2xhc3MgQ29uZmlndXJhdGlvblNlcnZpY2VcbiAqXG4gKiBBbGwgc2VydmljZXMgdGFrZSBpbiBhIGNvbmZpZ3VyYXRpb24gc2V0dGluZ3Mgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGVtc2VsdmVzLiBBIEpTIGhhc2gge30gaXMgYSB2YWxpZCBjb25maWd1cmF0aW9uIG9iamVjdCwgYnV0IG9wdGlvbmFsbHkgeW91IGNhbiB1c2UgdGhlIGNvbmZpZ3VyYXRpb24gc2VydmljZSB0byB0b2dnbGUgY29uZmlncyBiYXNlZCBvbiB0aGUgZW52aXJvbm1lbnRcbiAqXG4gKiBAZXhhbXBsZVxuICogICAgIHZhciBjcyA9IHJlcXVpcmUoJ2NvbmZpZ3VyYXRpb24tc2VydmljZScpKHtcbiAqICAgICAgICAgIGRldjogeyAvL2Vudmlyb25tZW50XG4gICAgICAgICAgICAgICAgcG9ydDogMzAwMCxcbiAgICAgICAgICAgICAgICBob3N0OiAnbG9jYWxob3N0JyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBwcm9kOiB7XG4gICAgICAgICAgICAgICAgcG9ydDogODA4MCxcbiAgICAgICAgICAgICAgICBob3N0OiAnYXBpLmZvcmlvLmNvbScsXG4gICAgICAgICAgICAgICAgbG9nTGV2ZWw6ICdub25lJ1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGxvZ0xldmVsOiAnREVCVUcnIC8vZ2xvYmFsXG4gKiAgICAgfSk7XG4gKlxuICogICAgICBjcy5nZXQoJ2xvZ0xldmVsJyk7IC8vcmV0dXJucyAnREVCVUcnXG4gKlxuICogICAgICBjcy5zZXRFbnYoJ2RldicpO1xuICogICAgICBjcy5nZXQoJ2xvZ0xldmVsJyk7IC8vcmV0dXJucyAnREVCVUcnXG4gKlxuICogICAgICBjcy5zZXRFbnYoJ3Byb2QnKTtcbiAqICAgICAgY3MuZ2V0KCdsb2dMZXZlbCcpOyAvL3JldHVybnMgJ25vbmUnXG4gKlxuICovXG5cbid1c2Ugc3RyaWN0JztcbnZhciB1cmxTZXJ2aWNlID0gcmVxdWlyZSgnLi91cmwtY29uZmlnLXNlcnZpY2UnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgLy9UT0RPOiBFbnZpcm9ubWVudHNcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIGxvZ0xldmVsOiAnTk9ORSdcbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICBzZXJ2aWNlT3B0aW9ucy5zZXJ2ZXIgPSB1cmxTZXJ2aWNlKHNlcnZpY2VPcHRpb25zLnNlcnZlcik7XG5cbiAgICByZXR1cm4ge1xuXG4gICAgICAgIGRhdGE6IHNlcnZpY2VPcHRpb25zLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgdGhlIGVudmlyb25tZW50IGtleSB0byBnZXQgY29uZmlndXJhdGlvbiBvcHRpb25zIGZyb21cbiAgICAgICAgICogQHBhcmFtIHsgc3RyaW5nfSBlbnZcbiAgICAgICAgICovXG4gICAgICAgIHNldEVudjogZnVuY3Rpb24gKGVudikge1xuXG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBjb25maWd1cmF0aW9uLlxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfSBwcm9wZXJ0eSBvcHRpb25hbFxuICAgICAgICAgKiBAcmV0dXJuIHsqfSAgICAgICAgICBWYWx1ZSBvZiBwcm9wZXJ0eSBpZiBzcGVjaWZpZWQsIHRoZSBlbnRpcmUgY29uZmlnIG9iamVjdCBvdGhlcndpc2VcbiAgICAgICAgICovXG4gICAgICAgIGdldDogZnVuY3Rpb24gKHByb3BlcnR5KSB7XG4gICAgICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnNbcHJvcGVydHldO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgY29uZmlndXJhdGlvbi5cbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xPYmplY3R9IGtleSBpZiBhIGtleSBpcyBwcm92aWRlZCwgc2V0IGEga2V5IHRvIHRoYXQgdmFsdWUuIE90aGVyd2lzZSBtZXJnZSBvYmplY3Qgd2l0aCBjdXJyZW50IGNvbmZpZ1xuICAgICAgICAgKiBAcGFyYW0gIHsqfSB2YWx1ZSAgdmFsdWUgZm9yIHByb3ZpZGVkIGtleVxuICAgICAgICAgKi9cbiAgICAgICAgc2V0OiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnNba2V5XSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfTtcbn07XG5cbiIsIi8qKlxuICogIyMgRGF0YSBBUEkgU2VydmljZVxuICpcbiAqIFRoZSBEYXRhIEFQSSBTZXJ2aWNlIGFsbG93cyB5b3UgdG8gY3JlYXRlLCBhY2Nlc3MsIGFuZCBtYW5pcHVsYXRlIGRhdGEgcmVsYXRlZCB0byBhbnkgb2YgeW91ciBwcm9qZWN0cy4gRGF0YSBhcmUgb3JnYW5pemVkIGluIGNvbGxlY3Rpb25zLiBFYWNoIGNvbGxlY3Rpb24gY29udGFpbnMgYSBkb2N1bWVudDsgZWFjaCBlbGVtZW50IG9mIHRoaXMgdG9wLWxldmVsIGRvY3VtZW50IGlzIGEgSlNPTiBvYmplY3QuIChTZWUgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBvbiB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pLilcbiAqXG4gKiBBbGwgQVBJIGNhbGxzIHRha2UgaW4gYW4gXCJvcHRpb25zXCIgb2JqZWN0IGFzIHRoZSBsYXN0IHBhcmFtZXRlci4gVGhlIG9wdGlvbnMgY2FuIGJlIHVzZWQgdG8gZXh0ZW5kL292ZXJyaWRlIHRoZSBEYXRhIEFQSSBTZXJ2aWNlIGRlZmF1bHRzLiBJbiBwYXJ0aWN1bGFyLCB0aGVyZSBhcmUgdGhyZWUgcmVxdWlyZWQgcGFyYW1ldGVycyB3aGVuIHlvdSBpbnN0YW50aWF0ZSB0aGUgRGF0YSBTZXJ2aWNlOlxuICpcbiAqICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gKiAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4gKiAqIGByb290YDogVGhlIHRoZSBuYW1lIG9mIHRoZSBjb2xsZWN0aW9uLiBJZiB5b3UgaGF2ZSBtdWx0aXBsZSBjb2xsZWN0aW9ucyB3aXRoaW4gZWFjaCBvZiB5b3VyIHByb2plY3RzLCB5b3UgY2FuIGFsc28gcGFzcyB0aGUgY29sbGVjdGlvbiBuYW1lIGFzIGFuIG9wdGlvbiBmb3IgZWFjaCBjYWxsLlxuICpcbiAqICAgICAgIHZhciBkcyA9IG5ldyBGLnNlcnZpY2UuRGF0YSh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgcm9vdDogJ3N1cnZleS1yZXNwb25zZXMnLFxuICogICAgICAgICAgc2VydmVyOiB7IGhvc3Q6ICdhcGkuZm9yaW8uY29tJyB9XG4gKiAgICAgICB9KTtcbiAqICAgICAgIGRzLnNhdmVBcygndXNlcjEnLFxuICogICAgICAgICAgeyAncXVlc3Rpb24xJzogMiwgJ3F1ZXN0aW9uMic6IDEwLFxuICogICAgICAgICAgJ3F1ZXN0aW9uMyc6IGZhbHNlLCAncXVlc3Rpb240JzogJ3NvbWV0aW1lcycgfSApO1xuICogICAgICAgZHMuc2F2ZUFzKCd1c2VyMicsXG4gKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAzLCAncXVlc3Rpb24yJzogOCxcbiAqICAgICAgICAgICdxdWVzdGlvbjMnOiB0cnVlLCAncXVlc3Rpb240JzogJ2Fsd2F5cycgfSApO1xuICogICAgICAgZHMucXVlcnkoJycseyAncXVlc3Rpb24yJzogeyAnJGd0JzogOX0gfSk7XG4gKlxuICogTm90ZSB0aGF0IGluIGFkZGl0aW9uIHRvIHRoZSBgYWNjb3VudGAsIGBwcm9qZWN0YCwgYW5kIGByb290YCwgdGhlIERhdGEgU2VydmljZSBwYXJhbWV0ZXJzIG9wdGlvbmFsbHkgaW5jbHVkZSBhIGBzZXJ2ZXJgIG9iamVjdCwgd2hvc2UgYGhvc3RgIGZpZWxkIGNvbnRhaW5zIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBOYW1lIG9mIGNvbGxlY3Rpb24uIERlZmF1bHRzIHRvIGAvYCwgdGhhdCBpcywgdGhlIHJvb3QgbGV2ZWwgb2YgeW91ciBwcm9qZWN0IGF0IGBmb3Jpby5jb20vYXBwL3lvdXItYWNjb3VudC1pZC95b3VyLXByb2plY3QtaWQvYC4gUmVxdWlyZWQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICByb290OiAnLycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBvcGVyYXRpb25zIHRoYXQgcmVxdWlyZSBhdXRoZW50aWNhdGlvbiwgcGFzcyBpbiB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gKGRlZmF1bHRzIHRvIGVtcHR5IHN0cmluZykuIElmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluIHRvIEVwaWNlbnRlciwgdGhlIHVzZXIgYWNjZXNzIHRva2VuIGlzIGFscmVhZHkgc2V0IGluIGEgY29va2llIGFuZCBhdXRvbWF0aWNhbGx5IGxvYWRlZCBmcm9tIHRoZXJlLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICAgICAqIEBzZWUgW0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXSguLi9hdXRoLWFwaS1zZXJ2aWNlLykgZm9yIGdldHRpbmcgdG9rZW5zLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdG9rZW46IHVuZGVmaW5lZCxcblxuICAgICAgICAvL09wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXJcbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG4gICAgdGhpcy5zZXNzaW9uTWFuYWdlciA9IG5ldyBTZXNzaW9uTWFuYWdlcigpO1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyhkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBnZXRVUkwgPSBmdW5jdGlvbiAoa2V5LCByb290KSB7XG4gICAgICAgIGlmICghcm9vdCkge1xuICAgICAgICAgICAgcm9vdCA9IHNlcnZpY2VPcHRpb25zLnJvb3Q7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVybCA9IHVybENvbmZpZy5nZXRBUElQYXRoKCdkYXRhJykgKyBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKHJvb3QpO1xuICAgICAgICBpZiAoa2V5KSB7XG4gICAgICAgICAgICB1cmwrPSBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKGtleSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IGdldFVSTFxuICAgIH0pO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNlYXJjaCBmb3IgZGF0YSB3aXRoaW4gYSBjb2xsZWN0aW9uLlxuICAgICAgICAgKlxuICAgICAgICAgKiBTZWFyY2hpbmcgdXNpbmcgY29tcGFyaXNvbiBvciBsb2dpY2FsIG9wZXJhdG9ycyAoYXMgb3Bwb3NlZCB0byBleGFjdCBtYXRjaGVzKSByZXF1aXJlcyBNb25nb0RCIHN5bnRheC4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLyNzZWFyY2hpbmcpIGZvciBhZGRpdGlvbmFsIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRhdGEgYXNzb2NpYXRlZCB3aXRoIGRvY3VtZW50ICd1c2VyMSdcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgndXNlcjEnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBleGFjdCBtYXRjaGluZzpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvbiB3aGVyZSAncXVlc3Rpb24yJyBpcyA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IDl9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBjb21wYXJpc29uIG9wZXJhdG9yczpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjInIGlzIGdyZWF0ZXIgdGhhbiA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIGxvZ2ljYWwgb3BlcmF0b3JzOlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRvY3VtZW50cyBpbiBjb2xsZWN0aW9uXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgJ3F1ZXN0aW9uMicgaXMgbGVzcyB0aGFuIDEwLCBhbmQgJ3F1ZXN0aW9uMycgaXMgZmFsc2VcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgnJywgeyAnJGFuZCc6IFsgeyAncXVlc3Rpb24yJzogeyAnJGx0JzoxMH0gfSwgeyAncXVlc3Rpb24zJzogZmFsc2UgfV0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gcmVndWxhciBleHByZXNzc2lvbnM6IHVzZSBhbnkgUGVybC1jb21wYXRpYmxlIHJlZ3VsYXIgZXhwcmVzc2lvbnNcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjUnIGNvbnRhaW5zIHRoZSBzdHJpbmcgJy4qZGF5J1xuICAgICAgICAgKiAgICAgIGRzLnF1ZXJ5KCcnLCB7ICdxdWVzdGlvbjUnOiB7ICckcmVnZXgnOiAnLipkYXknIH0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBga2V5YCBUaGUgbmFtZSBvZiB0aGUgZG9jdW1lbnQgdG8gc2VhcmNoLiBQYXNzIHRoZSBlbXB0eSBzdHJpbmcgKCcnKSB0byBzZWFyY2ggdGhlIGVudGlyZSBjb2xsZWN0aW9uLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHF1ZXJ5YCBUaGUgcXVlcnkgb2JqZWN0LiBGb3IgZXhhY3QgbWF0Y2hpbmcsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCBmaWVsZCB2YWx1ZSB0byBtYXRjaC4gRm9yIG1hdGNoaW5nIGJhc2VkIG9uIGNvbXBhcmlzb24sIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCB0aGUgY29tcGFyaXNvbiBleHByZXNzaW9uLiBGb3IgbWF0Y2hpbmcgYmFzZWQgb24gbG9naWNhbCBvcGVyYXRvcnMsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIGFuIGV4cHJlc3Npb24gdXNpbmcgTW9uZ29EQiBzeW50YXguIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8jc2VhcmNoaW5nKSBmb3IgYWRkaXRpb25hbCBleGFtcGxlcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKlxuICAgICAgICAgKi9cbiAgICAgICAgcXVlcnk6IGZ1bmN0aW9uIChrZXksIHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgcTogcXVlcnkgfSwgb3V0cHV0TW9kaWZpZXIpO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGRhdGEgdG8gYW4gYW5vbnltb3VzIGRvY3VtZW50IHdpdGhpbiB0aGUgY29sbGVjdGlvbi5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmUoJ3F1ZXN0aW9uMScsICd5ZXMnKTtcbiAgICAgICAgICogICAgICBkcy5zYXZlKHtxdWVzdGlvbjE6J3llcycsIHF1ZXN0aW9uMjogMzIgfSk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZSh7IG5hbWU6J0pvaG4nLCBjbGFzc05hbWU6ICdDUzEwMScgfSwgeyByb290OiAnc3R1ZGVudHMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xPYmplY3R9IGBrZXlgIElmIGBrZXlgIGlzIGEgc3RyaW5nLCBpdCBpcyB0aGUgaWQgb2YgdGhlIGVsZW1lbnQgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJZiBga2V5YCBpcyBhbiBvYmplY3QsIHRoZSBvYmplY3QgaXMgdGhlIGRhdGEgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJbiBib3RoIGNhc2VzLCB0aGUgaWQgZm9yIHRoZSBkb2N1bWVudCBpcyBnZW5lcmF0ZWQgYXV0b21hdGljYWxseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGB2YWx1ZWAgKE9wdGlvbmFsKSBUaGUgZGF0YSB0byBzYXZlLiBJZiBga2V5YCBpcyBhIHN0cmluZywgdGhpcyBpcyB0aGUgdmFsdWUgdG8gc2F2ZS4gSWYgYGtleWAgaXMgYW4gb2JqZWN0LCB0aGUgdmFsdWUocykgdG8gc2F2ZSBhcmUgYWxyZWFkeSBwYXJ0IG9mIGBrZXlgIGFuZCB0aGlzIGFyZ3VtZW50IGlzIG5vdCByZXF1aXJlZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZTogZnVuY3Rpb24gKGtleSwgdmFsdWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBhdHRycztcbiAgICAgICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0ga2V5O1xuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSB2YWx1ZTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoJycsIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KGF0dHJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgZGF0YSB0byBhIG5hbWVkIGRvY3VtZW50IG9yIGVsZW1lbnQgd2l0aGluIHRoZSBjb2xsZWN0aW9uLiBUaGUgYHJvb3RgIG9mIHRoZSBjb2xsZWN0aW9uIG11c3QgYmUgc3BlY2lmaWVkIHNlcGFyYXRlbHkgaW4gY29uZmlndXJhdGlvbiBvcHRpb25zLCBlaXRoZXIgYXMgcGFydCBvZiB0aGUgY2FsbCBvciBhcyBwYXJ0IG9mIHRoZSBpbml0aWFsaXphdGlvbiBvZiBkcy5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmVBcygndXNlcjEnLFxuICAgICAgICAgKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAyLCAncXVlc3Rpb24yJzogMTAsXG4gICAgICAgICAqICAgICAgICAgICAncXVlc3Rpb24zJzogZmFsc2UsICdxdWVzdGlvbjQnOiAnc29tZXRpbWVzJyB9ICk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZUFzKCdzdHVkZW50MScsXG4gICAgICAgICAqICAgICAgICAgIHsgZmlyc3ROYW1lOiAnam9obicsIGxhc3ROYW1lOiAnc21pdGgnIH0sXG4gICAgICAgICAqICAgICAgICAgIHsgcm9vdDogJ3N0dWRlbnRzJyB9KTtcbiAgICAgICAgICogICAgICBkcy5zYXZlQXMoJ21nbXQxMDAvZ3JvdXBCJyxcbiAgICAgICAgICogICAgICAgICAgeyBzY2VuYXJpb1llYXI6ICcyMDE1JyB9LFxuICAgICAgICAgKiAgICAgICAgICB7IHJvb3Q6ICdteWNsYXNzZXMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYGtleWAgSWQgb2YgdGhlIGRvY3VtZW50LlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbHVlYCAoT3B0aW9uYWwpIFRoZSBkYXRhIHRvIHNhdmUsIGluIGtleTp2YWx1ZSBwYWlycy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZUFzOiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wdXQodmFsdWUsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGRhdGEgZm9yIGEgc3BlY2lmaWMgZG9jdW1lbnQgb3IgZmllbGQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgZHMubG9hZCgndXNlcjEnKTtcbiAgICAgICAgICogICAgICBkcy5sb2FkKCd1c2VyMS9xdWVzdGlvbjMnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYGtleWAgVGhlIGlkIG9mIHRoZSBkYXRhIHRvIHJldHVybi4gQ2FuIGJlIHRoZSBpZCBvZiBhIGRvY3VtZW50LCBvciBhIHBhdGggdG8gZGF0YSB3aXRoaW4gdGhhdCBkb2N1bWVudC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uIChrZXksIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMudXJsID0gZ2V0VVJMKGtleSwgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQob3V0cHV0TW9kaWZpZXIsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBkYXRhIGZyb20gY29sbGVjdGlvbi4gT25seSBkb2N1bWVudHMgKHRvcC1sZXZlbCBlbGVtZW50cyBpbiBlYWNoIGNvbGxlY3Rpb24pIGNhbiBiZSBkZWxldGVkLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgZHMucmVtb3ZlKCd1c2VyMScpO1xuICAgICAgICAgKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xBcnJheX0gYGtleXNgIFRoZSBpZCBvZiB0aGUgZG9jdW1lbnQgdG8gcmVtb3ZlIGZyb20gdGhpcyBjb2xsZWN0aW9uLCBvciBhbiBhcnJheSBvZiBzdWNoIGlkcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgcmVtb3ZlOiBmdW5jdGlvbiAoa2V5cywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBwYXJhbXM7XG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KGtleXMpKSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBpZDoga2V5cyB9O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSAnJztcbiAgICAgICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoa2V5cywgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUocGFyYW1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFcGljZW50ZXIgZG9lc24ndCBhbGxvdyBudWtpbmcgY29sbGVjdGlvbnNcbiAgICAgICAgLy8gICAgIC8qKlxuICAgICAgICAvLyAgICAgICogUmVtb3ZlcyBjb2xsZWN0aW9uIGJlaW5nIHJlZmVyZW5jZWRcbiAgICAgICAgLy8gICAgICAqIEByZXR1cm4gbnVsbFxuICAgICAgICAvLyAgICAgICovXG4gICAgICAgIC8vICAgICBkZXN0cm95OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvLyAgICAgICAgIHJldHVybiB0aGlzLnJlbW92ZSgnJywgb3B0aW9ucyk7XG4gICAgICAgIC8vICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKlxuICogIyMgSW50cm9zcGVjdGlvbiBBUEkgU2VydmljZVxuICpcbiAqIFVzZWQgaW4gY29uanVuY3Rpb24gd2l0aCB0aGUgW1J1biBBUEkgU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykgdG8gYWNjZXNzIE5hdGl2ZSBETVMgMyBJbnRyb3NwZWN0aW9uIGNhbGxzXG4gKlxuICogICAgIHZhciBybSA9IG5ldyBGLm1hbmFnZXIuUnVuTWFuYWdlcih7XG4gKiAgICAgICAgICAgcnVuOiB7XG4gKiAgICAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgICAgICAgICAgbW9kZWw6ICdzdXBwbHktY2hhaW4tbW9kZWwuamwnXG4gKiAgICAgICAgICAgfVxuICogICAgICB9KTtcbiAqICAgICBybS5nZXRSdW4oKVxuICogICAgICAgLnRoZW4oZnVuY3Rpb24oKSB7XG4gKiAgICAgICAgICB2YXIgaXMgPSBybS5ydW4uaW50cm9zcGVjdGlvbigpO1xuICogICAgICAgIH0pO1xuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICBzZXJ2ZXI6IHtcbiAgICAgICAgICAgIHZlcnNpb25QYXRoOiAndjMvJ1xuICAgICAgICB9XG4gICAgfTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgdXJsQ29uZmlnLmFjY291bnRQYXRoID0gc2VydmljZU9wdGlvbnMuYWNjb3VudDtcbiAgICB9XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgdXJsQ29uZmlnLnByb2plY3RQYXRoID0gc2VydmljZU9wdGlvbnMucHJvamVjdDtcbiAgICB9XG5cbiAgICB1cmxDb25maWcuZmlsdGVyID0gJzsnO1xuXG4gICAgdmFyIGh0dHBPcHRpb25zID0ge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdtb2RlbCcpICsgJ3B1Ymxpc2gnXG4gICAgfTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IHRoZSBhdmFpbGFibGUgRnVuY3Rpb25zIGFuZCBWYXJpYWJsZXNcbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICB2cy5nZXQoKVxuICAgICAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbihkYXRhKSB7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyBkYXRhIGNvbnRhaW5zIGFuIG9iamVjdCB3aXRoIGF2YWlsYWJsZSBmdW5jdGlvbnMgKHVzZWQgd2l0aCBvcGVyYXRpb25zIEFQSSkgYW5kIGF2YWlsYWJsZSB2YXJpYWJsZXMgKHVzZWQgd2l0aCB2YXJpYWJsZXMgQVBJKVxuICAgICAgICAgKiAgICAgICAgICAgICAgY29uc29sZS5sb2coZGF0YS5mdW5jdGlvbnMpO1xuICAgICAgICAgKiAgICAgICAgICAgICAgY29uc29sZS5sb2coZGF0YS52YXJpYWJsZXMpO1xuICAgICAgICAgKiAgICAgICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBgcnVuSWRgICAgKE9wdGlvbmFsKSBPdmVycmlkZXMgdGhlIHJ1biBpZCB1c2VkIHdoZW4gdGhlIHNlcnZpY2Ugd2FzIGNyZWF0ZWRcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGdldDogZnVuY3Rpb24gKHJ1bklkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIHBhcmFtcyA9IHtcbiAgICAgICAgICAgICAgICBydW5JZDogcnVuSWQgfHwgaHR0cE9wdGlvbnMuZmlsdGVyLFxuICAgICAgICAgICAgICAgIGNvbW1hbmRXcmFwcGVyOiB7IGNvbW1hbmQ6IHsgaW50cm9zcGVjdDoge30gfSB9LFxuICAgICAgICAgICAgICAgIHJlYW5pbWF0ZTogZmFsc2VcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICpcbiAqICMjIE1lbWJlciBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBNZW1iZXIgQVBJIEFkYXB0ZXIgcHJvdmlkZXMgbWV0aG9kcyB0byBsb29rIHVwIGluZm9ybWF0aW9uIGFib3V0IGVuZCB1c2VycyBmb3IgeW91ciBwcm9qZWN0IGFuZCBob3cgdGhleSBhcmUgZGl2aWRlZCBhY3Jvc3MgZ3JvdXBzLiBJdCBpcyBiYXNlZCBvbiBxdWVyeSBjYXBhYmlsaXRpZXMgb2YgdGhlIHVuZGVybHlpbmcgUkVTVGZ1bCBbTWVtYmVyIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL3VzZXJfbWFuYWdlbWVudC9tZW1iZXIvKS5cbiAqXG4gKiBUaGlzIGlzIG9ubHkgbmVlZGVkIGZvciBBdXRoZW50aWNhdGVkIHByb2plY3RzLCB0aGF0IGlzLCB0ZWFtIHByb2plY3RzIHdpdGggW2VuZCB1c2VycyBhbmQgZ3JvdXBzXSguLi8uLi8uLi9ncm91cHNfYW5kX2VuZF91c2Vycy8pLiBGb3IgZXhhbXBsZSwgaWYgc29tZSBvZiB5b3VyIGVuZCB1c2VycyBhcmUgZmFjaWxpdGF0b3JzLCBvciBpZiB5b3VyIGVuZCB1c2VycyBzaG91bGQgYmUgdHJlYXRlZCBkaWZmZXJlbnRseSBiYXNlZCBvbiB3aGljaCBncm91cCB0aGV5IGFyZSBpbiwgdXNlIHRoZSBNZW1iZXIgQVBJIHRvIGZpbmQgdGhhdCBpbmZvcm1hdGlvbi5cbiAqXG4gKiAgICAgIHZhciBtYSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAqICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcih7IHVzZXJJZDogJ2I2YjMxM2EzLWFiODQtNDc5Yy1iYWVhLTIwNmY2YmZmMzM3JyB9KTtcbiAqICAgICAgbWEuZ2V0R3JvdXBEZXRhaWxzKHsgZ3JvdXBJZDogJzAwYjUzMzA4LTk4MzMtNDdmMi1iMjFlLTEyNzhjMDdkNTNiOCcgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBhcGlFbmRwb2ludCA9ICdtZW1iZXIvbG9jYWwnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBFcGljZW50ZXIgdXNlciBpZC4gRGVmYXVsdHMgdG8gYSBibGFuayBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1c2VySWQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRXBpY2VudGVyIGdyb3VwIGlkLiBEZWZhdWx0cyB0byBhIGJsYW5rIHN0cmluZy4gTm90ZSB0aGF0IHRoaXMgaXMgdGhlIGdyb3VwICppZCosIG5vdCB0aGUgZ3JvdXAgKm5hbWUqLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZ3JvdXBJZDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMsIHNlcnZpY2VPcHRpb25zKTtcblxuICAgIHZhciBnZXRGaW5hbFBhcmFtcyA9IGZ1bmN0aW9uIChwYXJhbXMpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBwYXJhbXMgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwgc2VydmljZU9wdGlvbnMsIHBhcmFtcyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zO1xuICAgIH07XG5cbiAgICB2YXIgcGF0Y2hVc2VyQWN0aXZlRmllbGQgPSBmdW5jdGlvbiAocGFyYW1zLCBhY3RpdmUsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHtcbiAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcGFyYW1zLmdyb3VwSWQgKyAnLycgKyBwYXJhbXMudXNlcklkXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBodHRwLnBhdGNoKHsgYWN0aXZlOiBhY3RpdmUgfSwgaHR0cE9wdGlvbnMpO1xuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgYWxsIG9mIHRoZSBncm91cCBtZW1iZXJzaGlwcyBmb3Igb25lIGVuZCB1c2VyLiBUaGUgbWVtYmVyc2hpcCBkZXRhaWxzIGFyZSByZXR1cm5lZCBpbiBhbiBhcnJheSwgd2l0aCBvbmUgZWxlbWVudCAoZ3JvdXAgcmVjb3JkKSBmb3IgZWFjaCBncm91cCB0byB3aGljaCB0aGUgZW5kIHVzZXIgYmVsb25ncy5cbiAgICAgICAgKlxuICAgICAgICAqIEluIHRoZSBtZW1iZXJzaGlwIGFycmF5LCBlYWNoIGdyb3VwIHJlY29yZCBpbmNsdWRlcyB0aGUgZ3JvdXAgaWQsIHByb2plY3QgaWQsIGFjY291bnQgKHRlYW0pIGlkLCBhbmQgYW4gYXJyYXkgb2YgbWVtYmVycy4gSG93ZXZlciwgb25seSB0aGUgdXNlciB3aG9zZSB1c2VySWQgaXMgaW5jbHVkZWQgaW4gdGhlIGNhbGwgaXMgbGlzdGVkIGluIHRoZSBtZW1iZXJzIGFycmF5IChyZWdhcmRsZXNzIG9mIHdoZXRoZXIgdGhlcmUgYXJlIG90aGVyIG1lbWJlcnMgaW4gdGhpcyBncm91cCkuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLmdldEdyb3Vwc0ZvclVzZXIoJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKG1lbWJlcnNoaXBzKXtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaTxtZW1iZXJzaGlwcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAqICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKG1lbWJlcnNoaXBzW2ldLmdyb3VwSWQpO1xuICAgICAgICAqICAgICAgICAgICAgICAgfVxuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIG1hLmdldEdyb3Vwc0ZvclVzZXIoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ3xvYmplY3R9IGBwYXJhbXNgIFRoZSB1c2VyIGlkIGZvciB0aGUgZW5kIHVzZXIuIEFsdGVybmF0aXZlbHksIGFuIG9iamVjdCB3aXRoIGZpZWxkIGB1c2VySWRgIGFuZCB2YWx1ZSB0aGUgdXNlciBpZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG5cbiAgICAgICAgZ2V0R3JvdXBzRm9yVXNlcjogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgaXNTdHJpbmcgPSB0eXBlb2YgcGFyYW1zID09PSAnc3RyaW5nJztcbiAgICAgICAgICAgIHZhciBvYmpQYXJhbXMgPSBnZXRGaW5hbFBhcmFtcyhwYXJhbXMpO1xuICAgICAgICAgICAgaWYgKCFpc1N0cmluZyAmJiAhb2JqUGFyYW1zLnVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gdXNlcklkIHNwZWNpZmllZC4nKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGdldFBhcm1zID0gaXNTdHJpbmcgPyB7IHVzZXJJZDogcGFyYW1zIH0gOiBfcGljayhvYmpQYXJhbXMsICd1c2VySWQnKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChnZXRQYXJtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgb25lIGdyb3VwLCBpbmNsdWRpbmcgYW4gYXJyYXkgb2YgYWxsIGl0cyBtZW1iZXJzLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBtYSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAgICAgICAgKiAgICAgICBtYS5nZXRHcm91cERldGFpbHMoJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKGdyb3VwKXtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaTxncm91cC5tZW1iZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coZ3JvdXAubWVtYmVyc1tpXS51c2VyTmFtZSk7XG4gICAgICAgICogICAgICAgICAgICAgICB9XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBEZXRhaWxzKHsgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdH0gYHBhcmFtc2AgVGhlIGdyb3VwIGlkLiBBbHRlcm5hdGl2ZWx5LCBhbiBvYmplY3Qgd2l0aCBmaWVsZCBgZ3JvdXBJZGAgYW5kIHZhbHVlIHRoZSBncm91cCBpZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGdldEdyb3VwRGV0YWlsczogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICB2YXIgaXNTdHJpbmcgPSB0eXBlb2YgcGFyYW1zID09PSAnc3RyaW5nJztcbiAgICAgICAgICAgIHZhciBvYmpQYXJhbXMgPSBnZXRGaW5hbFBhcmFtcyhwYXJhbXMpO1xuICAgICAgICAgICAgaWYgKCFpc1N0cmluZyAmJiAhb2JqUGFyYW1zLmdyb3VwSWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGdyb3VwSWQgc3BlY2lmaWVkLicpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZ3JvdXBJZCA9IGlzU3RyaW5nID8gcGFyYW1zIDogb2JqUGFyYW1zLmdyb3VwSWQ7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBncm91cElkIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldCh7fSwgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFNldCBhIHBhcnRpY3VsYXIgZW5kIHVzZXIgYXMgYGFjdGl2ZWAuIEFjdGl2ZSBlbmQgdXNlcnMgY2FuIGJlIGFzc2lnbmVkIHRvIFt3b3JsZHNdKC4uL3dvcmxkLW1hbmFnZXIvKSBpbiBtdWx0aXBsYXllciBnYW1lcyBkdXJpbmcgYXV0b21hdGljIGFzc2lnbm1lbnQuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLm1ha2VVc2VyQWN0aXZlKHsgdXNlcklkOiAnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwSWQ6ICc4MDI1N2EyNS1hYTEwLTQ5NTktOTY4Yi1mZDA1MzkwMWY3MmYnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgVGhlIGVuZCB1c2VyIGFuZCBncm91cCBpbmZvcm1hdGlvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy51c2VySWRgIFRoZSBpZCBvZiB0aGUgZW5kIHVzZXIgdG8gbWFrZSBhY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZ3JvdXBJZGAgVGhlIGlkIG9mIHRoZSBncm91cCB0byB3aGljaCB0aGlzIGVuZCB1c2VyIGJlbG9uZ3MsIGFuZCBpbiB3aGljaCB0aGUgZW5kIHVzZXIgc2hvdWxkIGJlY29tZSBhY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBtYWtlVXNlckFjdGl2ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHBhdGNoVXNlckFjdGl2ZUZpZWxkKHBhcmFtcywgdHJ1ZSwgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogU2V0IGEgcGFydGljdWxhciBlbmQgdXNlciBhcyBgaW5hY3RpdmVgLiBJbmFjdGl2ZSBlbmQgdXNlcnMgYXJlIG5vdCBhc3NpZ25lZCB0byBbd29ybGRzXSguLi93b3JsZC1tYW5hZ2VyLykgaW4gbXVsdGlwbGF5ZXIgZ2FtZXMgZHVyaW5nIGF1dG9tYXRpYyBhc3NpZ25tZW50LlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBtYSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAgICAgICAgKiAgICAgICBtYS5tYWtlVXNlckluYWN0aXZlKHsgdXNlcklkOiAnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwSWQ6ICc4MDI1N2EyNS1hYTEwLTQ5NTktOTY4Yi1mZDA1MzkwMWY3MmYnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgVGhlIGVuZCB1c2VyIGFuZCBncm91cCBpbmZvcm1hdGlvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy51c2VySWRgIFRoZSBpZCBvZiB0aGUgZW5kIHVzZXIgdG8gbWFrZSBpbmFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5ncm91cElkYCBUaGUgaWQgb2YgdGhlIGdyb3VwIHRvIHdoaWNoIHRoaXMgZW5kIHVzZXIgYmVsb25ncywgYW5kIGluIHdoaWNoIHRoZSBlbmQgdXNlciBzaG91bGQgYmVjb21lIGluYWN0aXZlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgbWFrZVVzZXJJbmFjdGl2ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHBhdGNoVXNlckFjdGl2ZUZpZWxkKHBhcmFtcywgZmFsc2UsIG9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKlxuICogIyMgUnVuIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhlIFJ1biBBUEkgU2VydmljZSBhbGxvd3MgeW91IHRvIHBlcmZvcm0gY29tbW9uIHRhc2tzIGFyb3VuZCBjcmVhdGluZyBhbmQgdXBkYXRpbmcgcnVucywgdmFyaWFibGVzLCBhbmQgZGF0YS5cbiAqXG4gKiBXaGVuIGJ1aWxkaW5nIGludGVyZmFjZXMgdG8gc2hvdyBydW4gb25lIGF0IGEgdGltZSAoYXMgZm9yIHN0YW5kYXJkIGVuZCB1c2VycyksIHR5cGljYWxseSB5b3UgZmlyc3QgaW5zdGFudGlhdGUgYSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyLykgYW5kIHRoZW4gYWNjZXNzIHRoZSBSdW4gU2VydmljZSB0aGF0IGlzIGF1dG9tYXRpY2FsbHkgcGFydCBvZiB0aGUgbWFuYWdlciwgcmF0aGVyIHRoYW4gaW5zdGFudGlhdGluZyB0aGUgUnVuIFNlcnZpY2UgZGlyZWN0bHkuIFRoaXMgaXMgYmVjYXVzZSB0aGUgUnVuIE1hbmFnZXIgZ2l2ZXMgeW91IGNvbnRyb2wgb3ZlciBydW4gY3JlYXRpb24gZGVwZW5kaW5nIG9uIHJ1biBzdGF0ZXMuXG4gKlxuICogSG93ZXZlciwgbWFueSBvZiB0aGUgRXBpY2VudGVyIHNhbXBsZSBwcm9qZWN0cyB1c2UgYSBSdW4gU2VydmljZSwgYmVjYXVzZSBnZW5lcmFsbHkgdGhlIHNhbXBsZSBwcm9qZWN0cyBhcmUgcGxheWVkIGluIG9uZSBlbmQgdXNlciBzZXNzaW9uIGFuZCBkb24ndCBjYXJlIGFib3V0IHJ1biBzdGF0ZXMgb3IgW3J1biBzdHJhdGVnaWVzXSguLi8uLi9zdHJhdGVneS8pLiBUaGUgUnVuIEFQSSBTZXJ2aWNlIGlzIGFsc28gdXNlZnVsIGZvciBidWlsZGluZyBhbiBpbnRlcmZhY2UgZm9yIGEgZmFjaWxpdGF0b3IsIGJlY2F1c2UgaXQgbWFrZXMgaXQgZWFzeSB0byBsaXN0IGRhdGEgYWNyb3NzIG11bHRpcGxlIHJ1bnMgKHVzaW5nIHRoZSBgZmlsdGVyKClgIGFuZCBgcXVlcnkoKWAgbWV0aG9kcykuXG4gKlxuICogVG8gdXNlIHRoZSBSdW4gQVBJIFNlcnZpY2UsIGluc3RhbnRpYXRlIGl0IGJ5IHBhc3NpbmcgaW46XG4gKlxuICogKiBgYWNjb3VudGA6IEVwaWNlbnRlciBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBmb3IgdGVhbSBwcm9qZWN0cywgKipVc2VyIElEKiogZm9yIHBlcnNvbmFsIHByb2plY3RzKS5cbiAqICogYHByb2plY3RgOiBFcGljZW50ZXIgcHJvamVjdCBpZC5cbiAqXG4gKiBGb3IgZXhhbXBsZSxcbiAqXG4gKiAgICAgICB2YXIgcnMgPSBuZXcgRi5zZXJ2aWNlLlJ1bih7XG4gKiAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgfSk7XG4gKiAgICAgIHJzLmNyZWF0ZSgnc3VwcGx5X2NoYWluX2dhbWUucHknKS50aGVuKGZ1bmN0aW9uKHJ1bikge1xuICogICAgICAgICAgICAgcnMuZG8oJ3NvbWVPcGVyYXRpb24nKTtcbiAqICAgICAgfSk7XG4gKlxuICpcbiAqIEFkZGl0aW9uYWxseSwgYWxsIEFQSSBjYWxscyB0YWtlIGluIGFuIFwib3B0aW9uc1wiIG9iamVjdCBhcyB0aGUgbGFzdCBwYXJhbWV0ZXIuIFRoZSBvcHRpb25zIGNhbiBiZSB1c2VkIHRvIGV4dGVuZC9vdmVycmlkZSB0aGUgUnVuIEFQSSBTZXJ2aWNlIGRlZmF1bHRzIGxpc3RlZCBiZWxvdy5cbiAqXG4gKiBOb3RlIHRoYXQgaW4gYWRkaXRpb24gdG8gdGhlIGBhY2NvdW50YCwgYHByb2plY3RgLCBhbmQgYG1vZGVsYCwgdGhlIFJ1biBTZXJ2aWNlIHBhcmFtZXRlcnMgb3B0aW9uYWxseSBpbmNsdWRlIGEgYHNlcnZlcmAgb2JqZWN0LCB3aG9zZSBgaG9zdGAgZmllbGQgY29udGFpbnMgdGhlIFVSSSBvZiB0aGUgRm9yaW8gc2VydmVyLiBUaGlzIGlzIGF1dG9tYXRpY2FsbHkgc2V0LCBidXQgeW91IGNhbiBwYXNzIGl0IGV4cGxpY2l0bHkgaWYgZGVzaXJlZC4gSXQgaXMgbW9zdCBjb21tb25seSB1c2VkIGZvciBjbGFyaXR5IHdoZW4geW91IGFyZSBbaG9zdGluZyBhbiBFcGljZW50ZXIgcHJvamVjdCBvbiB5b3VyIG93biBzZXJ2ZXJdKC4uLy4uLy4uL2hvd190by9zZWxmX2hvc3RpbmcvKS5cbiAqXG4gKiAgICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuICogICAgICAgICAgIHJ1bjoge1xuICogICAgICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5X2NoYWluX2dhbWUucHknLFxuICogICAgICAgICAgICAgICBzZXJ2ZXI6IHsgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH1cbiAqICAgICAgICAgICB9XG4gKiAgICAgICB9KTtcbiAqICAgICAgIHJtLmdldFJ1bigpXG4gKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24ocnVuKSB7XG4gKiAgICAgICAgICAgICAgIC8vIHRoZSBSdW5NYW5hZ2VyLnJ1biBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFJ1biBTZXJ2aWNlLFxuICogICAgICAgICAgICAgICAvLyBzbyBhbnkgUnVuIFNlcnZpY2UgbWV0aG9kIGlzIHZhbGlkIGhlcmVcbiAqICAgICAgICAgICAgICAgdmFyIHJzID0gcm0ucnVuO1xuICogICAgICAgICAgICAgICBycy5kbygnc29tZU9wZXJhdGlvbicpO1xuICogICAgICAgfSlcbiAqXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBydXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcnVuLXV0aWwnKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBWYXJpYWJsZXNTZXJ2aWNlID0gcmVxdWlyZSgnLi92YXJpYWJsZXMtYXBpLXNlcnZpY2UnKTtcbnZhciBJbnRyb3NwZWN0aW9uU2VydmljZSA9IHJlcXVpcmUoJy4vaW50cm9zcGVjdGlvbi1hcGktc2VydmljZScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRva2VuOiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENyaXRlcmlhIGJ5IHdoaWNoIHRvIGZpbHRlciBydW5zLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBmaWx0ZXI6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZW5pZW5jZSBhbGlhcyBmb3IgZmlsdGVyLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgaWQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGbGFnIGRldGVybWluZXMgaWYgYFgtQXV0b1Jlc3RvcmU6IHRydWVgIGhlYWRlciBpcyBzZW50IHRvIEVwaWNlbnRlci4gRGVmYXVsdHMgdG8gYHRydWVgLlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn1cbiAgICAgICAgICovXG4gICAgICAgIGF1dG9SZXN0b3JlOiB0cnVlLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBjb21wbGV0ZXMgc3VjY2Vzc2Z1bGx5LiBEZWZhdWx0cyB0byBgJC5ub29wYC5cbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgc3VjY2VzczogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBmYWlscy4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIGVycm9yOiAkLm5vb3AsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG5cbiAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgdXJsQ29uZmlnLmFjY291bnRQYXRoID0gc2VydmljZU9wdGlvbnMuYWNjb3VudDtcbiAgICB9XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgdXJsQ29uZmlnLnByb2plY3RQYXRoID0gc2VydmljZU9wdGlvbnMucHJvamVjdDtcbiAgICB9XG5cbiAgICB1cmxDb25maWcuZmlsdGVyID0gJzsnO1xuICAgIHVybENvbmZpZy5nZXRGaWx0ZXJVUkwgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJyk7XG4gICAgICAgIHZhciBmaWx0ZXIgPSBxdXRpbC50b01hdHJpeEZvcm1hdChzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpO1xuXG4gICAgICAgIGlmIChmaWx0ZXIpIHtcbiAgICAgICAgICAgIHVybCArPSBmaWx0ZXIgKyAnLyc7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGZpbHRlciA9IHNlcnZpY2VPcHRpb25zLmZpbHRlcjtcbiAgICAgICAgLy8gVGhlIHNlbWljb2xvbiBzZXBhcmF0ZWQgZmlsdGVyIGlzIHVzZWQgd2hlbiBmaWx0ZXIgaXMgYW4gb2JqZWN0XG4gICAgICAgIHZhciBpc0ZpbHRlclJ1bklkID0gZmlsdGVyICYmICQudHlwZShmaWx0ZXIpID09PSAnc3RyaW5nJztcbiAgICAgICAgaWYgKHNlcnZpY2VPcHRpb25zLmF1dG9SZXN0b3JlICYmIGlzRmlsdGVyUnVuSWQpIHtcbiAgICAgICAgICAgIC8vIEJ5IGRlZmF1bHQgYXV0b3JlcGxheSB0aGUgcnVuIGJ5IHNlbmRpbmcgdGhpcyBoZWFkZXIgdG8gZXBpY2VudGVyXG4gICAgICAgICAgICAvLyBodHRwczovL2ZvcmlvLmNvbS9lcGljZW50ZXIvZG9jcy9wdWJsaWMvcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNyZXRyaWV2aW5nXG4gICAgICAgICAgICB2YXIgYXV0b3Jlc3RvcmVPcHRzID0ge1xuICAgICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICAgICAgJ1gtQXV0b1Jlc3RvcmUnOiB0cnVlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCBhdXRvcmVzdG9yZU9wdHMsIG9wdGlvbnMpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG9wdGlvbnM7XG4gICAgfTtcblxuICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0RmlsdGVyVVJMXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG4gICAgaHR0cC5zcGxpdEdldCA9IHJ1dGlsLnNwbGl0R2V0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgc2V0RmlsdGVyT3JUaHJvd0Vycm9yID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMuaWQpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IG9wdGlvbnMuaWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmZpbHRlcjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBmaWx0ZXIgc3BlY2lmaWVkIHRvIGFwcGx5IG9wZXJhdGlvbnMgYWdhaW5zdCcpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBc3luY0FQSSA9IHtcbiAgICAgICAgdXJsQ29uZmlnOiB1cmxDb25maWcsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENyZWF0ZSBhIG5ldyBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqIE5PVEU6IFR5cGljYWxseSB0aGlzIGlzIG5vdCB1c2VkISBVc2UgYFJ1bk1hbmFnZXIuZ2V0UnVuKClgIHdpdGggYSBgc3RyYXRlZ3lgIG9mIGBhbHdheXMtbmV3YCwgb3IgdXNlIGBSdW5NYW5hZ2VyLnJlc2V0KClgLiBTZWUgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGZvciBtb3JlIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHJzLmNyZWF0ZSgnaGVsbG9fd29ybGQuamwnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYHBhcmFtc2AgSWYgYSBzdHJpbmcsIHRoZSBuYW1lIG9mIHRoZSBwcmltYXJ5IFttb2RlbCBmaWxlXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4gVGhpcyBpcyB0aGUgb25lIGZpbGUgaW4gdGhlIHByb2plY3QgdGhhdCBleHBsaWNpdGx5IGV4cG9zZXMgdmFyaWFibGVzIGFuZCBtZXRob2RzLCBhbmQgaXQgbXVzdCBiZSBzdG9yZWQgaW4gdGhlIE1vZGVsIGZvbGRlciBvZiB5b3VyIEVwaWNlbnRlciBwcm9qZWN0LiBJZiBhbiBvYmplY3QsIG1heSBpbmNsdWRlIGBtb2RlbGAsIGBzY29wZWAsIGFuZCBgZmlsZXNgLiAoU2VlIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bl9tYW5hZ2VyLykgZm9yIG1vcmUgaW5mb3JtYXRpb24gb24gYHNjb3BlYCBhbmQgYGZpbGVzYC4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICpcbiAgICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJykgfSk7XG4gICAgICAgICAgICB2YXIgcnVuQXBpUGFyYW1zID0gWydtb2RlbCcsICdzY29wZScsICdmaWxlcyddO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgLy8gdGhpcyBpcyBqdXN0IHRoZSBtb2RlbCBuYW1lXG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBtb2RlbDogcGFyYW1zIH07XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIHdoaXRlbGlzdCB0aGUgZmllbGRzIHRoYXQgd2UgYWN0dWFsbHkgY2FuIHNlbmQgdG8gdGhlIGFwaVxuICAgICAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgcnVuQXBpUGFyYW1zKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBjcmVhdGVPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgICAgICBjcmVhdGVPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSByZXNwb25zZS5pZDsgLy9hbGwgZnV0dXJlIGNoYWluZWQgY2FsbHMgdG8gb3BlcmF0ZSBvbiB0aGlzIGlkXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHJ1bnMsIGJhc2VkIG9uIGNvbmRpdGlvbnMgc3BlY2lmaWVkIGluIHRoZSBgcXNgIG9iamVjdC5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGVsZW1lbnRzIG9mIHRoZSBgcXNgIG9iamVjdCBhcmUgQU5EZWQgdG9nZXRoZXIgd2l0aGluIGEgc2luZ2xlIGNhbGwgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyByZXR1cm5zIHJ1bnMgd2l0aCBzYXZlZCA9IHRydWUgYW5kIHZhcmlhYmxlcy5wcmljZSA+IDEsXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgdmFyaWFibGVzLnByaWNlIGhhcyBiZWVuIHBlcnNpc3RlZCAocmVjb3JkZWQpXG4gICAgICAgICAqICAgICAgLy8gaW4gdGhlIG1vZGVsLlxuICAgICAgICAgKiAgICAgcnMucXVlcnkoe1xuICAgICAgICAgKiAgICAgICAgICAnc2F2ZWQnOiAndHJ1ZScsXG4gICAgICAgICAqICAgICAgICAgICcucHJpY2UnOiAnPjEnXG4gICAgICAgICAqICAgICAgIH0sXG4gICAgICAgICAqICAgICAgIHtcbiAgICAgICAgICogICAgICAgICAgc3RhcnRyZWNvcmQ6IDIsXG4gICAgICAgICAqICAgICAgICAgIGVuZHJlY29yZDogNVxuICAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBxc2AgUXVlcnkgb2JqZWN0LiBFYWNoIGtleSBjYW4gYmUgYSBwcm9wZXJ0eSBvZiB0aGUgcnVuIG9yIHRoZSBuYW1lIG9mIHZhcmlhYmxlIHRoYXQgaGFzIGJlZW4gc2F2ZWQgaW4gdGhlIHJ1biAocHJlZmFjZWQgYnkgYHZhcmlhYmxlcy5gKS4gRWFjaCB2YWx1ZSBjYW4gYmUgYSBsaXRlcmFsIHZhbHVlLCBvciBhIGNvbXBhcmlzb24gb3BlcmF0b3IgYW5kIHZhbHVlLiAoU2VlIFttb3JlIG9uIGZpbHRlcmluZ10oLi4vLi4vLi4vcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNmaWx0ZXJzKSBhbGxvd2VkIGluIHRoZSB1bmRlcmx5aW5nIFJ1biBBUEkuKSBRdWVyeWluZyBmb3IgdmFyaWFibGVzIGlzIGF2YWlsYWJsZSBmb3IgcnVucyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBhbmQgZm9yIHJ1bnMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgaWYgdGhlIHZhcmlhYmxlcyBhcmUgcGVyc2lzdGVkIChlLmcuIHRoYXQgaGF2ZSBiZWVuIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHF1ZXJ5OiBmdW5jdGlvbiAocXMsIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBxczsgLy9zaG91bGRuJ3QgYmUgYWJsZSB0byBvdmVyLXJpZGVcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucyA9IHVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlcihodHRwT3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJldHVybnMgcGFydGljdWxhciBydW5zLCBiYXNlZCBvbiBjb25kaXRpb25zIHNwZWNpZmllZCBpbiB0aGUgYHFzYCBvYmplY3QuXG4gICAgICAgICAqXG4gICAgICAgICAqIFNpbWlsYXIgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBmaWx0ZXJgIEZpbHRlciBvYmplY3QuIEVhY2gga2V5IGNhbiBiZSBhIHByb3BlcnR5IG9mIHRoZSBydW4gb3IgdGhlIG5hbWUgb2YgdmFyaWFibGUgdGhhdCBoYXMgYmVlbiBzYXZlZCBpbiB0aGUgcnVuIChwcmVmYWNlZCBieSBgdmFyaWFibGVzLmApLiBFYWNoIHZhbHVlIGNhbiBiZSBhIGxpdGVyYWwgdmFsdWUsIG9yIGEgY29tcGFyaXNvbiBvcGVyYXRvciBhbmQgdmFsdWUuIChTZWUgW21vcmUgb24gZmlsdGVyaW5nXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkvI2ZpbHRlcnMpIGFsbG93ZWQgaW4gdGhlIHVuZGVybHlpbmcgUnVuIEFQSS4pIEZpbHRlcmluZyBmb3IgdmFyaWFibGVzIGlzIGF2YWlsYWJsZSBmb3IgcnVucyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBhbmQgZm9yIHJ1bnMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgaWYgdGhlIHZhcmlhYmxlcyBhcmUgcGVyc2lzdGVkIChlLmcuIHRoYXQgaGF2ZSBiZWVuIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogZnVuY3Rpb24gKGZpbHRlciwgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qoc2VydmljZU9wdGlvbnMuZmlsdGVyKSkge1xuICAgICAgICAgICAgICAgICQuZXh0ZW5kKHNlcnZpY2VPcHRpb25zLmZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gZmlsdGVyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBkYXRhIGZvciBhIHNwZWNpZmljIHJ1bi4gVGhpcyBpbmNsdWRlcyBzdGFuZGFyZCBydW4gZGF0YSBzdWNoIGFzIHRoZSBhY2NvdW50LCBtb2RlbCwgcHJvamVjdCwgYW5kIGNyZWF0ZWQgYW5kIGxhc3QgbW9kaWZpZWQgZGF0ZXMuIFRvIHJlcXVlc3Qgc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLCBwYXNzIHRoZW0gYXMgcGFydCBvZiB0aGUgYGZpbHRlcnNgIHBhcmFtZXRlci5cbiAgICAgICAgICpcbiAgICAgICAgICogTm90ZSB0aGF0IGlmIHRoZSBydW4gaXMgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSksIGFueSBtb2RlbCB2YXJpYWJsZXMgYXJlIGF2YWlsYWJsZTsgaWYgdGhlIHJ1biBpcyBbaW4gdGhlIGRhdGFiYXNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tZGIpLCBvbmx5IG1vZGVsIHZhcmlhYmxlcyB0aGF0IGhhdmUgYmVlbiBwZXJzaXN0ZWQgJm1kYXNoOyB0aGF0IGlzLCBgcmVjb3JkYGVkIGluIHlvdXIgSnVsaWEgbW9kZWwgJm1kYXNoOyBhcmUgYXZhaWxhYmxlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgcnMubG9hZCgnYmI1ODk2NzctZDQ3Ni00OTcxLWE2OGUtMGM1OGQxOTFlNDUwJywgeyBpbmNsdWRlOiBbJy5wcmljZScsICcuc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGBydW5JRGAgVGhlIHJ1biBpZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBmaWx0ZXJzYCAoT3B0aW9uYWwpIE9iamVjdCBjb250YWluaW5nIGZpbHRlcnMgYW5kIG9wZXJhdGlvbiBtb2RpZmllcnMuIFVzZSBrZXkgYGluY2x1ZGVgIHRvIGxpc3QgbW9kZWwgdmFyaWFibGVzIHRoYXQgeW91IHdhbnQgdG8gaW5jbHVkZSBpbiB0aGUgcmVzcG9uc2UuIE90aGVyIGF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAocnVuSUQsIGZpbHRlcnMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmIChydW5JRCkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHJ1bklEOyAvL3Nob3VsZG4ndCBiZSBhYmxlIHRvIG92ZXItcmlkZVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cblxuICAgICAgICAvKipcbiAgICAgICAgICogU2F2ZSBhdHRyaWJ1dGVzIChkYXRhLCBtb2RlbCB2YXJpYWJsZXMpIG9mIHRoZSBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgLy8gYWRkICdjb21wbGV0ZWQnIGZpZWxkIHRvIHJ1biByZWNvcmRcbiAgICAgICAgICogICAgIHJzLnNhdmUoeyBjb21wbGV0ZWQ6IHRydWUgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAvLyB1cGRhdGUgJ3NhdmVkJyBmaWVsZCBvZiBydW4gcmVjb3JkLCBhbmQgdXBkYXRlIHZhbHVlcyBvZiBtb2RlbCB2YXJpYWJsZXMgZm9yIHRoaXMgcnVuXG4gICAgICAgICAqICAgICBycy5zYXZlKHsgc2F2ZWQ6IHRydWUsIHZhcmlhYmxlczogeyBhOiAyMywgYjogMjMgfSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBhdHRyaWJ1dGVzYCBUaGUgcnVuIGRhdGEgYW5kIHZhcmlhYmxlcyB0byBzYXZlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYGF0dHJpYnV0ZXMudmFyaWFibGVzYCBNb2RlbCB2YXJpYWJsZXMgbXVzdCBiZSBpbmNsdWRlZCBpbiBhIGB2YXJpYWJsZXNgIGZpZWxkIHdpdGhpbiB0aGUgYGF0dHJpYnV0ZXNgIG9iamVjdC4gKE90aGVyd2lzZSB0aGV5IGFyZSB0cmVhdGVkIGFzIHJ1biBkYXRhIGFuZCBhZGRlZCB0byB0aGUgcnVuIHJlY29yZCBkaXJlY3RseS4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uIChhdHRyaWJ1dGVzLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgc2V0RmlsdGVyT3JUaHJvd0Vycm9yKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKGF0dHJpYnV0ZXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBhIG1ldGhvZCBmcm9tIHRoZSBtb2RlbC5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2QgbWF5IG5lZWQgdG8gYmUgZXhwb3NlZCAoZS5nLiBgZXhwb3J0YCBmb3IgYSBKdWxpYSBtb2RlbCkgaW4gdGhlIG1vZGVsIGZpbGUgaW4gb3JkZXIgdG8gYmUgY2FsbGVkIHRocm91Z2ggdGhlIEFQSS4gU2VlIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pKS5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGBwYXJhbXNgIGFyZ3VtZW50IGlzIG5vcm1hbGx5IGFuIGFycmF5IG9mIGFyZ3VtZW50cyB0byB0aGUgYG9wZXJhdGlvbmAuIEluIHRoZSBzcGVjaWFsIGNhc2Ugd2hlcmUgYG9wZXJhdGlvbmAgb25seSB0YWtlcyBvbmUgYXJndW1lbnQsIHlvdSBhcmUgbm90IHJlcXVpcmVkIHRvIHB1dCB0aGF0IGFyZ3VtZW50IGludG8gYW4gYXJyYXkuXG4gICAgICAgICAqXG4gICAgICAgICAqIE5vdGUgdGhhdCB5b3UgY2FuIGNvbWJpbmUgdGhlIGBvcGVyYXRpb25gIGFuZCBgcGFyYW1zYCBhcmd1bWVudHMgaW50byBhIHNpbmdsZSBvYmplY3QgaWYgeW91IHByZWZlciwgYXMgaW4gdGhlIGxhc3QgZXhhbXBsZS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlcyoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwic29sdmVcIiB0YWtlcyBubyBhcmd1bWVudHNcbiAgICAgICAgICogICAgIHJzLmRvKCdzb2x2ZScpO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImVjaG9cIiB0YWtlcyBvbmUgYXJndW1lbnQsIGEgc3RyaW5nXG4gICAgICAgICAqICAgICBycy5kbygnZWNobycsIFsnaGVsbG8nXSk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwiZWNob1wiIHRha2VzIG9uZSBhcmd1bWVudCwgYSBzdHJpbmdcbiAgICAgICAgICogICAgIHJzLmRvKCdlY2hvJywgJ2hlbGxvJyk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwic3VtQXJyYXlcIiB0YWtlcyBvbmUgYXJndW1lbnQsIGFuIGFycmF5XG4gICAgICAgICAqICAgICBycy5kbygnc3VtQXJyYXknLCBbWzQsMiwxXV0pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImFkZFwiIHRha2VzIHR3byBhcmd1bWVudHMsIGJvdGggaW50ZWdlcnNcbiAgICAgICAgICogICAgIHJzLmRvKHsgbmFtZTonYWRkJywgcGFyYW1zOlsyLDRdIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYG9wZXJhdGlvbmAgTmFtZSBvZiBtZXRob2QuXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGBwYXJhbXNgIChPcHRpb25hbCkgQW55IHBhcmFtZXRlcnMgdGhlIG9wZXJhdGlvbiB0YWtlcywgcGFzc2VkIGFzIGFuIGFycmF5LiBJbiB0aGUgc3BlY2lhbCBjYXNlIHdoZXJlIGBvcGVyYXRpb25gIG9ubHkgdGFrZXMgb25lIGFyZ3VtZW50LCB5b3UgYXJlIG5vdCByZXF1aXJlZCB0byBwdXQgdGhhdCBhcmd1bWVudCBpbnRvIGFuIGFycmF5LCBhbmQgY2FuIGp1c3QgcGFzcyBpdCBkaXJlY3RseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgZG86IGZ1bmN0aW9uIChvcGVyYXRpb24sIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coJ2RvJywgb3BlcmF0aW9uLCBwYXJhbXMpO1xuICAgICAgICAgICAgdmFyIG9wc0FyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnM7XG4gICAgICAgICAgICBpZiAob3B0aW9ucykge1xuICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMgPSBvcHRpb25zO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHBhcmFtcykpIHtcbiAgICAgICAgICAgICAgICAgICAgb3BzQXJncyA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zID0gcGFyYW1zO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9uLCBvcHNBcmdzKTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgcG9zdE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBzZXRGaWx0ZXJPclRocm93RXJyb3IoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcHJtcyA9IChyZXN1bHQuYXJnc1swXS5sZW5ndGggJiYgKHJlc3VsdC5hcmdzWzBdICE9PSBudWxsICYmIHJlc3VsdC5hcmdzWzBdICE9PSB1bmRlZmluZWQpKSA/IHJlc3VsdC5hcmdzWzBdIDogW107XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHsgYXJndW1lbnRzOiBwcm1zIH0sICQuZXh0ZW5kKHRydWUsIHt9LCBodHRwT3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ29wZXJhdGlvbnMvJyArIHJlc3VsdC5vcHNbMF0gKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBzZXZlcmFsIG1ldGhvZHMgZnJvbSB0aGUgbW9kZWwsIHNlcXVlbnRpYWxseS5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2RzIG1heSBuZWVkIHRvIGJlIGV4cG9zZWQgKGUuZy4gYGV4cG9ydGAgZm9yIGEgSnVsaWEgbW9kZWwpIGluIHRoZSBtb2RlbCBmaWxlIGluIG9yZGVyIHRvIGJlIGNhbGxlZCB0aHJvdWdoIHRoZSBBUEkuIFNlZSBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKSkuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJpbml0aWFsaXplXCIgYW5kIFwic29sdmVcIiBkbyBub3QgdGFrZSBhbnkgYXJndW1lbnRzXG4gICAgICAgICAqICAgICBycy5zZXJpYWwoWydpbml0aWFsaXplJywgJ3NvbHZlJ10pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJpbml0XCIgYW5kIFwicmVzZXRcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMuc2VyaWFsKFsgIHsgbmFtZTogJ2luaXQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgeyBuYW1lOiAncmVzZXQnLCBwYXJhbXM6IFsyLDNdIH1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJpbml0XCIgdGFrZXMgdHdvIGFyZ3VtZW50cyxcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJydW5tb2RlbFwiIHRha2VzIG5vbmVcbiAgICAgICAgICogICAgIHJzLnNlcmlhbChbICB7IG5hbWU6ICdpbml0JywgcGFyYW1zOiBbMSwyXSB9LFxuICAgICAgICAgKiAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3J1bm1vZGVsJywgcGFyYW1zOiBbXSB9XSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGBvcGVyYXRpb25zYCBJZiBub25lIG9mIHRoZSBtZXRob2RzIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiB0aGUgbWV0aG9kIG5hbWVzIChzdHJpbmdzKS4gSWYgYW55IG9mIHRoZSBtZXRob2RzIGRvIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiBvYmplY3RzLCBlYWNoIG9mIHdoaWNoIGNvbnRhaW5zIGEgbWV0aG9kIG5hbWUgYW5kIGl0cyBvd24gKHBvc3NpYmx5IGVtcHR5KSBhcnJheSBvZiBwYXJhbWV0ZXJzLlxuICAgICAgICAgKiBAcGFyYW0geyp9IGBwYXJhbXNgIFBhcmFtZXRlcnMgdG8gcGFzcyB0byBvcGVyYXRpb25zLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBzZXJpYWw6IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBvcFBhcmFtcyA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHMgPSBvcFBhcmFtcy5vcHM7XG4gICAgICAgICAgICB2YXIgYXJncyA9IG9wUGFyYW1zLmFyZ3M7XG4gICAgICAgICAgICB2YXIgbWUgPSB0aGlzO1xuXG4gICAgICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZG9TaW5nbGVPcCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB2YXIgb3AgPSBvcHMuc2hpZnQoKTtcbiAgICAgICAgICAgICAgICB2YXIgYXJnID0gYXJncy5zaGlmdCgpO1xuXG4gICAgICAgICAgICAgICAgbWUuZG8ob3AsIGFyZywge1xuICAgICAgICAgICAgICAgICAgICBzdWNjZXNzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAob3BzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvU2luZ2xlT3AoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zLnN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICRkLnJlamVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuZXJyb3IuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgZG9TaW5nbGVPcCgpO1xuXG4gICAgICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsIHNldmVyYWwgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbCwgZXhlY3V0aW5nIHRoZW0gaW4gcGFyYWxsZWwuXG4gICAgICAgICAqXG4gICAgICAgICAqIERlcGVuZGluZyBvbiB0aGUgbGFuZ3VhZ2UgaW4gd2hpY2ggeW91IGhhdmUgd3JpdHRlbiB5b3VyIG1vZGVsLCB0aGUgbWV0aG9kcyBtYXkgbmVlZCB0byBiZSBleHBvc2VkIChlLmcuIGBleHBvcnRgIGZvciBhIEp1bGlhIG1vZGVsKSBpbiB0aGUgbW9kZWwgZmlsZSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdGhyb3VnaCB0aGUgQVBJLiBTZWUgW1dyaXRpbmcgeW91ciBNb2RlbF0oLi4vLi4vLi4vd3JpdGluZ195b3VyX21vZGVsLykpLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJzb2x2ZVwiIGFuZCBcInJlc2V0XCIgZG8gbm90IHRha2UgYW55IGFyZ3VtZW50c1xuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoWydzb2x2ZScsICdyZXNldCddKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiYWRkXCIgYW5kIFwic3VidHJhY3RcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoWyB7IG5hbWU6ICdhZGQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3N1YnRyYWN0JywgcGFyYW1zOlsyLDNdIH1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiYWRkXCIgYW5kIFwic3VidHJhY3RcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoeyBhZGQ6IFsxLDJdLCBzdWJ0cmFjdDogWzIsNF0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fSBgb3BlcmF0aW9uc2AgSWYgbm9uZSBvZiB0aGUgbWV0aG9kcyB0YWtlIHBhcmFtZXRlcnMsIHBhc3MgYW4gYXJyYXkgb2YgdGhlIG1ldGhvZCBuYW1lcyAoYXMgc3RyaW5ncykuIElmIGFueSBvZiB0aGUgbWV0aG9kcyBkbyB0YWtlIHBhcmFtZXRlcnMsIHlvdSBoYXZlIHR3byBvcHRpb25zLiBZb3UgY2FuIHBhc3MgYW4gYXJyYXkgb2Ygb2JqZWN0cywgZWFjaCBvZiB3aGljaCBjb250YWlucyBhIG1ldGhvZCBuYW1lIGFuZCBpdHMgb3duIChwb3NzaWJseSBlbXB0eSkgYXJyYXkgb2YgcGFyYW1ldGVycy4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBwYXNzIGEgc2luZ2xlIG9iamVjdCB3aXRoIHRoZSBtZXRob2QgbmFtZSBhbmQgYSAocG9zc2libHkgZW1wdHkpIGFycmF5IG9mIHBhcmFtZXRlcnMuXG4gICAgICAgICAqIEBwYXJhbSB7Kn0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBwYXNzIHRvIG9wZXJhdGlvbnMuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHBhcmFsbGVsOiBmdW5jdGlvbiAob3BlcmF0aW9ucywgcGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG5cbiAgICAgICAgICAgIHZhciBvcFBhcmFtcyA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHMgPSBvcFBhcmFtcy5vcHM7XG4gICAgICAgICAgICB2YXIgYXJncyA9IG9wUGFyYW1zLmFyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcXVldWUgID0gW107XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaTwgb3BzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgcXVldWUucHVzaChcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kbyhvcHNbaV0sIGFyZ3NbaV0pXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgICQud2hlbi5hcHBseSh0aGlzLCBxdWV1ZSlcbiAgICAgICAgICAgICAgICAuZG9uZShmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlc29sdmUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuc3VjY2Vzcy5hcHBseSh0aGlzLmFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZmFpbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlamVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucy5lcnJvci5hcHBseSh0aGlzLmFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY1N5bmNBUEkgPSB7XG4gICAgICAgIGdldEN1cnJlbnRDb25maWc6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucztcbiAgICAgICAgfSxcbiAgICAgICAgLyoqXG4gICAgICAgICAgKiBSZXR1cm5zIGEgVmFyaWFibGVzIFNlcnZpY2UgaW5zdGFuY2UuIFVzZSB0aGUgdmFyaWFibGVzIGluc3RhbmNlIHRvIGxvYWQsIHNhdmUsIGFuZCBxdWVyeSBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLiBTZWUgdGhlIFtWYXJpYWJsZSBBUEkgU2VydmljZV0oLi4vdmFyaWFibGVzLWFwaS1zZXJ2aWNlLykgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG4gICAgICAgICAgKlxuICAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAgICAgIHZhciB2cyA9IHJzLnZhcmlhYmxlcygpO1xuICAgICAgICAgICogICAgICB2cy5zYXZlKHsgc2FtcGxlX2ludDogNCB9KTtcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBjb25maWdgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAgKi9cbiAgICAgICAgdmFyaWFibGVzOiBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICAgICAgICB2YXIgdnMgPSBuZXcgVmFyaWFibGVzU2VydmljZSgkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIGNvbmZpZywge1xuICAgICAgICAgICAgICAgIHJ1blNlcnZpY2U6IHRoaXNcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgIHJldHVybiB2cztcbiAgICAgICAgfSxcblxuICAgICAgICBpbnRyb3NwZWN0aW9uOiBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICAgICAgICB2YXIgaW50cm9zcGVjdGlvbiA9IG5ldyBJbnRyb3NwZWN0aW9uU2VydmljZSgkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIGNvbmZpZykpO1xuICAgICAgICAgICAgcmV0dXJuIGludHJvc3BlY3Rpb247XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQXN5bmNBUEkpO1xuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY1N5bmNBUEkpO1xufTtcbiIsIid1c2Ugc3RyaWN0Jztcbi8qKlxuICogIyMgU3RhdGUgQVBJIEFkYXB0ZXJcbiAqXG4gKiBUaGUgU3RhdGUgQVBJIEFkYXB0ZXIgYWxsb3dzIHlvdSB0byByZXBsYXkgb3IgY2xvbmUgcnVucy4gSXQgYnJpbmdzIGV4aXN0aW5nLCBwZXJzaXN0ZWQgcnVuIGRhdGEgZnJvbSB0aGUgZGF0YWJhc2UgYmFjayBpbnRvIG1lbW9yeSwgdXNpbmcgdGhlIHNhbWUgcnVuIGlkIChgcmVwbGF5YCkgb3IgYSBuZXcgcnVuIGlkIChgY2xvbmVgKS4gUnVucyBtdXN0IGJlIGluIG1lbW9yeSBpbiBvcmRlciBmb3IgeW91IHRvIHVwZGF0ZSB2YXJpYWJsZXMgb3IgY2FsbCBvcGVyYXRpb25zIG9uIHRoZW0uXG4gKlxuICogU3BlY2lmaWNhbGx5LCB0aGUgU3RhdGUgQVBJIEFkYXB0ZXIgd29ya3MgYnkgXCJyZS1ydW5uaW5nXCIgdGhlIHJ1biAodXNlciBpbnRlcmFjdGlvbnMpIGZyb20gdGhlIGNyZWF0aW9uIG9mIHRoZSBydW4gdXAgdG8gdGhlIHRpbWUgaXQgd2FzIGxhc3QgcGVyc2lzdGVkIGluIHRoZSBkYXRhYmFzZS4gVGhpcyBwcm9jZXNzIHVzZXMgdGhlIGN1cnJlbnQgdmVyc2lvbiBvZiB0aGUgcnVuJ3MgbW9kZWwuIFRoZXJlZm9yZSwgaWYgdGhlIG1vZGVsIGhhcyBjaGFuZ2VkIHNpbmNlIHRoZSBvcmlnaW5hbCBydW4gd2FzIGNyZWF0ZWQsIHRoZSByZXRyaWV2ZWQgcnVuIHdpbGwgdXNlIHRoZSBuZXcgbW9kZWwg4oCUIGFuZCBtYXkgZW5kIHVwIGhhdmluZyBkaWZmZXJlbnQgdmFsdWVzIG9yIGJlaGF2aW9yIGFzIGEgcmVzdWx0LiBVc2Ugd2l0aCBjYXJlIVxuICpcbiAqIFRvIHVzZSB0aGUgU3RhdGUgQVBJIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGNhbGwgaXRzIG1ldGhvZHM6XG4gKlxuICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gKiAgICAgIHNhLnJlcGxheSh7cnVuSWQ6ICcxODQyYmI1Yy04M2FkLTRiYTgtYTk1NS1iZDEzY2MyZmRiNGYnfSk7XG4gKlxuICogVGhlIGNvbnN0cnVjdG9yIHRha2VzIGFuIG9wdGlvbmFsIGBvcHRpb25zYCBwYXJhbWV0ZXIgaW4gd2hpY2ggeW91IGNhbiBzcGVjaWZ5IHRoZSBgYWNjb3VudGAgYW5kIGBwcm9qZWN0YCBpZiB0aGV5IGFyZSBub3QgYWxyZWFkeSBhdmFpbGFibGUgaW4gdGhlIGN1cnJlbnQgY29udGV4dC5cbiAqXG4gKi9cblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG52YXIgYXBpRW5kcG9pbnQgPSAnbW9kZWwvc3RhdGUnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcblxuICAgIH07XG5cbiAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuICAgIHZhciBwYXJzZVJ1bklkT3JFcnJvciA9IGZ1bmN0aW9uIChwYXJhbXMpIHtcbiAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdChwYXJhbXMpICYmIHBhcmFtcy5ydW5JZCkge1xuICAgICAgICAgICAgcmV0dXJuIHBhcmFtcy5ydW5JZDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHBhc3MgaW4gYSBydW4gaWQnKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICAvKipcbiAgICAgICAgKiBSZXBsYXkgYSBydW4uIEFmdGVyIHRoaXMgY2FsbCwgdGhlIHJ1biwgd2l0aCBpdHMgb3JpZ2luYWwgcnVuIGlkLCBpcyBub3cgYXZhaWxhYmxlIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLiAoSXQgY29udGludWVzIHRvIGJlIHBlcnNpc3RlZCBpbnRvIHRoZSBFcGljZW50ZXIgZGF0YWJhc2UgYXQgcmVndWxhciBpbnRlcnZhbHMuKVxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciBzYSA9IG5ldyBGLnNlcnZpY2UuU3RhdGUoKTtcbiAgICAgICAgKiAgICAgIHNhLnJlcGxheSh7cnVuSWQ6ICcxODQyYmI1Yy04M2FkLTRiYTgtYTk1NS1iZDEzY2MyZmRiNGYnLCBzdG9wQmVmb3JlOiAnY2FsY3VsYXRlU2NvcmUnfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgUGFyYW1ldGVycyBvYmplY3QuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMucnVuSWRgIFRoZSBpZCBvZiB0aGUgcnVuIHRvIGJyaW5nIGJhY2sgdG8gbWVtb3J5LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnN0b3BCZWZvcmVgIChPcHRpb25hbCkgVGhlIHJ1biBpcyBhZHZhbmNlZCBvbmx5IHVwIHRvIHRoZSBmaXJzdCBvY2N1cnJlbmNlIG9mIHRoaXMgbWV0aG9kLlxuICAgICAgICAqIEBwYXJhbSB7YXJyYXl9IGBwYXJhbXMuZXhjbHVkZWAgKE9wdGlvbmFsKSBBcnJheSBvZiBtZXRob2RzIHRvIGV4Y2x1ZGUgd2hlbiBhZHZhbmNpbmcgdGhlIHJ1bi5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIHJlcGxheTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHJ1bklkID0gcGFyc2VSdW5JZE9yRXJyb3IocGFyYW1zKTtcblxuICAgICAgICAgICAgdmFyIHJlcGxheU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBydW5JZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBwYXJhbXMgPSAkLmV4dGVuZCh0cnVlLCB7IGFjdGlvbjogJ3JlcGxheScgfSwgX3BpY2socGFyYW1zLCBbJ3N0b3BCZWZvcmUnLCAnZXhjbHVkZSddKSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCByZXBsYXlPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBDbG9uZSBhIGdpdmVuIHJ1biBhbmQgcmV0dXJuIGEgbmV3IHJ1biBpbiB0aGUgc2FtZSBzdGF0ZSBhcyB0aGUgZ2l2ZW4gcnVuLlxuICAgICAgICAqXG4gICAgICAgICogVGhlIG5ldyBydW4gaWQgaXMgbm93IGF2YWlsYWJsZSBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KS4gVGhlIG5ldyBydW4gaW5jbHVkZXMgYSBjb3B5IG9mIGFsbCBvZiB0aGUgZGF0YSBmcm9tIHRoZSBvcmlnaW5hbCBydW4sIEVYQ0VQVDpcbiAgICAgICAgKlxuICAgICAgICAqICogVGhlIGBzYXZlZGAgZmllbGQgaW4gdGhlIG5ldyBydW4gcmVjb3JkIGlzIG5vdCBjb3BpZWQgZnJvbSB0aGUgb3JpZ2luYWwgcnVuIHJlY29yZC4gSXQgZGVmYXVsdHMgdG8gYGZhbHNlYC5cbiAgICAgICAgKiAqIFRoZSBgaW5pdGlhbGl6ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyBub3QgY29waWVkIGZyb20gdGhlIG9yaWdpbmFsIHJ1biByZWNvcmQuIEl0IGRlZmF1bHRzIHRvIGBmYWxzZWAgYnV0IG1heSBjaGFuZ2UgdG8gYHRydWVgIGFzIHRoZSBuZXcgcnVuIGlzIGFkdmFuY2VkLiBGb3IgZXhhbXBsZSwgaWYgdGhlcmUgaGFzIGJlZW4gYSBjYWxsIHRvIHRoZSBgc3RlcGAgZnVuY3Rpb24gKGZvciBWZW5zaW0gbW9kZWxzKSwgdGhlIGBpbml0aWFsaXplZGAgZmllbGQgaXMgc2V0IHRvIGB0cnVlYC5cbiAgICAgICAgKiAqIFRoZSBgY3JlYXRlZGAgZmllbGQgaW4gdGhlIG5ldyBydW4gcmVjb3JkIGlzIHRoZSBkYXRlIGFuZCB0aW1lIGF0IHdoaWNoIHRoZSBjbG9uZSB3YXMgY3JlYXRlZCAobm90IHRoZSB0aW1lIHRoYXQgdGhlIG9yaWdpbmFsIHJ1biB3YXMgY3JlYXRlZC4pXG4gICAgICAgICpcbiAgICAgICAgKiBUaGUgb3JpZ2luYWwgcnVuIHJlbWFpbnMgb25seSBbaW4gdGhlIGRhdGFiYXNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tZGIpLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciBzYSA9IG5ldyBGLnNlcnZpY2UuU3RhdGUoKTtcbiAgICAgICAgKiAgICAgIHNhLmNsb25lKHtydW5JZDogJzE4NDJiYjVjLTgzYWQtNGJhOC1hOTU1LWJkMTNjYzJmZGI0ZicsIHN0b3BCZWZvcmU6ICdjYWxjdWxhdGVTY29yZScsIGV4Y2x1ZGU6IFsnaW50ZXJpbUNhbGN1bGF0aW9uJ10gfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgUGFyYW1ldGVycyBvYmplY3QuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMucnVuSWRgIFRoZSBpZCBvZiB0aGUgcnVuIHRvIGNsb25lIGZyb20gbWVtb3J5LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnN0b3BCZWZvcmVgIChPcHRpb25hbCkgVGhlIG5ld2x5IGNsb25lZCBydW4gaXMgYWR2YW5jZWQgb25seSB1cCB0byB0aGUgZmlyc3Qgb2NjdXJyZW5jZSBvZiB0aGlzIG1ldGhvZC5cbiAgICAgICAgKiBAcGFyYW0ge2FycmF5fSBgcGFyYW1zLmV4Y2x1ZGVgIChPcHRpb25hbCkgQXJyYXkgb2YgbWV0aG9kcyB0byBleGNsdWRlIHdoZW4gYWR2YW5jaW5nIHRoZSBuZXdseSBjbG9uZWQgcnVuLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgY2xvbmU6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBydW5JZCA9IHBhcnNlUnVuSWRPckVycm9yKHBhcmFtcyk7XG5cbiAgICAgICAgICAgIHZhciByZXBsYXlPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcnVuSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gJC5leHRlbmQodHJ1ZSwgeyBhY3Rpb246ICdjbG9uZScgfSwgX3BpY2socGFyYW1zLCBbJ3N0b3BCZWZvcmUnLCAnZXhjbHVkZSddKSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCByZXBsYXlPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGVwaVZlcnNpb24gPSByZXF1aXJlKCcuLi9hcGktdmVyc2lvbi5qc29uJyk7XG5cbi8vVE9ETzogdXJsdXRpbHMgdG8gZ2V0IGhvc3QsIHNpbmNlIG5vIHdpbmRvdyBvbiBub2RlXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgaG9zdDogd2luZG93LmxvY2F0aW9uLmhvc3QsXG4gICAgcGF0aG5hbWU6IHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZVxufTtcblxudmFyIFVybENvbmZpZ1NlcnZpY2UgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIG9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgZnVuY3Rpb24gaXNMb2NhbGhvc3QoKSB7XG4gICAgICAgIHZhciBob3N0ID0gb3B0aW9ucy5ob3N0O1xuICAgICAgICB2YXIgcGF0aCA9IG9wdGlvbnMucGF0aG5hbWU7XG4gICAgICAgIC8vIFNvcnQgb2YgaGFyZGNvZGUgdGhlIGZhY3QgdGhhdCBlcGljZW50ZXIgYXBwbGljYXRpb24gc3BhY2UgaXMgcHJlZml4ZWQgYnkgL2FwcC9cbiAgICAgICAgcmV0dXJuICghaG9zdCB8fCBwYXRoLmluZGV4T2YoJy9hcHAvJykgIT09IDApO1xuICAgIH1cblxuICAgIHZhciBBUElfUFJPVE9DT0wgPSAnaHR0cHMnO1xuICAgIHZhciBIT1NUX0FQSV9NQVBQSU5HID0ge1xuICAgICAgICAnZm9yaW8uY29tJzogJ2FwaS5mb3Jpby5jb20nLFxuICAgICAgICAnZm9yaW9kZXYuY29tJzogJ2FwaS5lcGljZW50ZXIuZm9yaW9kZXYuY29tJ1xuICAgIH07XG5cbiAgICB2YXIgcHVibGljRXhwb3J0cyA9IHtcbiAgICAgICAgcHJvdG9jb2w6IEFQSV9QUk9UT0NPTCxcblxuICAgICAgICBhcGk6ICcnLFxuXG4gICAgICAgIGhvc3Q6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgaG9zdCA9IG9wdGlvbnMuaG9zdDtcbiAgICAgICAgICAgIGlmIChpc0xvY2FsaG9zdCgpKSB7XG4gICAgICAgICAgICAgICAgaG9zdCA9ICdmb3Jpby5jb20nO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIChIT1NUX0FQSV9NQVBQSU5HW2hvc3RdKSA/IEhPU1RfQVBJX01BUFBJTkdbaG9zdF0gOiAnYXBpLicgKyBob3N0O1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIGFwcFBhdGg6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IG9wdGlvbnMucGF0aG5hbWUuc3BsaXQoJ1xcLycpO1xuXG4gICAgICAgICAgICByZXR1cm4gcGF0aCAmJiBwYXRoWzFdIHx8ICcnO1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIGFjY291bnRQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFjY250ID0gJyc7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IG9wdGlvbnMucGF0aG5hbWUuc3BsaXQoJ1xcLycpO1xuICAgICAgICAgICAgaWYgKHBhdGggJiYgcGF0aFsxXSA9PT0gJ2FwcCcpIHtcbiAgICAgICAgICAgICAgICBhY2NudCA9IHBhdGhbMl07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gYWNjbnQ7XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgcHJvamVjdFBhdGg6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgcHJqID0gJyc7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IG9wdGlvbnMucGF0aG5hbWUuc3BsaXQoJ1xcLycpO1xuICAgICAgICAgICAgaWYgKHBhdGggJiYgcGF0aFsxXSA9PT0gJ2FwcCcpIHtcbiAgICAgICAgICAgICAgICBwcmogPSBwYXRoWzNdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHByajtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICB2ZXJzaW9uUGF0aDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciB2ZXJzaW9uID0gZXBpVmVyc2lvbi52ZXJzaW9uID8gZXBpVmVyc2lvbi52ZXJzaW9uICsgJy8nIDogJyc7XG4gICAgICAgICAgICByZXR1cm4gdmVyc2lvbjtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBpc0xvY2FsaG9zdDogaXNMb2NhbGhvc3QsXG5cbiAgICAgICAgZ2V0QVBJUGF0aDogZnVuY3Rpb24gKGFwaSkge1xuICAgICAgICAgICAgdmFyIFBST0pFQ1RfQVBJUyA9IFsncnVuJywgJ2RhdGEnLCAnZmlsZSddO1xuXG4gICAgICAgICAgICB2YXIgYXBpUGF0aCA9IHRoaXMucHJvdG9jb2wgKyAnOi8vJyArIHRoaXMuaG9zdCArICcvJyArIHRoaXMudmVyc2lvblBhdGggKyBhcGkgKyAnLyc7XG5cbiAgICAgICAgICAgIGlmICgkLmluQXJyYXkoYXBpLCBQUk9KRUNUX0FQSVMpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIGFwaVBhdGggKz0gdGhpcy5hY2NvdW50UGF0aCArICcvJyArIHRoaXMucHJvamVjdFBhdGggICsgJy8nO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGFwaVBhdGg7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLy8gVGhpcyBkYXRhIGlzIHNldCBieSBhbiBleHRlcm5hbCBzY3JpcHQgKHN0YXJ0LWxvYWQuanMpXG4gICAgdmFyIGVudkNvbmYgPSB7XG4gICAgICAgIHByb3RvY29sOiBVcmxDb25maWdTZXJ2aWNlLnByb3RvY29sLFxuICAgICAgICBob3N0OiBVcmxDb25maWdTZXJ2aWNlLmhvc3RcbiAgICB9O1xuXG4gICAgJC5leHRlbmQocHVibGljRXhwb3J0cywgZW52Q29uZiwgY29uZmlnKTtcbiAgICByZXR1cm4gcHVibGljRXhwb3J0cztcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gVXJsQ29uZmlnU2VydmljZTtcbiIsIid1c2Ugc3RyaWN0Jztcbi8qKlxuKiAjIyBVc2VyIEFQSSBBZGFwdGVyXG4qXG4qIFRoZSBVc2VyIEFQSSBBZGFwdGVyIGFsbG93cyB5b3UgdG8gcmV0cmlldmUgZGV0YWlscyBhYm91dCBlbmQgdXNlcnMgaW4geW91ciB0ZWFtIChhY2NvdW50KS4gSXQgaXMgYmFzZWQgb24gdGhlIHF1ZXJ5aW5nIGNhcGFiaWxpdGllcyBvZiB0aGUgdW5kZXJseWluZyBSRVNUZnVsIFtVc2VyIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL3VzZXJfbWFuYWdlbWVudC91c2VyLykuXG4qXG4qIFRvIHVzZSB0aGUgVXNlciBBUEkgQWRhcHRlciwgaW5zdGFudGlhdGUgaXQgYW5kIHRoZW4gY2FsbCBpdHMgbWV0aG9kcy5cbipcbiogICAgICAgdmFyIHVhID0gbmV3IEYuc2VydmljZS5Vc2VyKHtcbiogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiogICAgICAgfSk7XG4qICAgICAgIHVhLmdldEJ5SWQoJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycpO1xuKiAgICAgICB1YS5nZXQoeyB1c2VyTmFtZTogJ2pzbWl0aCcgfSk7XG4qICAgICAgIHVhLmdldCh7IGlkOiBbJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycsXG4qICAgICAgICAgICAgICAgICAgICc0ZWE3NTYzMS00YzhkLTQ4NzItOWQ4MC1iNDYwMDE0NjQ3OGUnXSB9KTtcbipcbiogVGhlIGNvbnN0cnVjdG9yIHRha2VzIGFuIG9wdGlvbmFsIGBvcHRpb25zYCBwYXJhbWV0ZXIgaW4gd2hpY2ggeW91IGNhbiBzcGVjaWZ5IHRoZSBgYWNjb3VudGAgYW5kIGB0b2tlbmAgaWYgdGhleSBhcmUgbm90IGFscmVhZHkgYXZhaWxhYmxlIGluIHRoZSBjdXJyZW50IGNvbnRleHQuXG4qL1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcbnZhciBxdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2Nlc3MgdG9rZW4gdG8gdXNlIHdoZW4gc2VhcmNoaW5nIGZvciBlbmQgdXNlcnMuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRva2VuOiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG5cbiAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgcGFydGljdWxhciBlbmQgdXNlcnMgaW4geW91ciB0ZWFtLCBiYXNlZCBvbiB1c2VyIG5hbWUgb3IgdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXQoeyB1c2VyTmFtZTogJ2pzbWl0aCcgfSk7XG4gICAgICAgICogICAgICAgdWEuZ2V0KHsgaWQ6IFsnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAnNGVhNzU2MzEtNGM4ZC00ODcyLTlkODAtYjQ2MDAxNDY0NzhlJ10gfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgZmlsdGVyYCBPYmplY3Qgd2l0aCBmaWVsZCBgdXNlck5hbWVgIGFuZCB2YWx1ZSBvZiB0aGUgdXNlcm5hbWUuIEFsdGVybmF0aXZlbHksIG9iamVjdCB3aXRoIGZpZWxkIGBpZGAgYW5kIHZhbHVlIG9mIGFuIGFycmF5IG9mIHVzZXIgaWRzLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChmaWx0ZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICAgICAgZmlsdGVyID0gZmlsdGVyIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnNcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciB0b1FGaWx0ZXIgPSBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJlcyA9IHt9O1xuXG4gICAgICAgICAgICAgICAgLy8gQVBJIG9ubHkgc3VwcG9ydHMgZmlsdGVyaW5nIGJ5IHVzZXJuYW1lIGZvciBub3dcbiAgICAgICAgICAgICAgICBpZiAoZmlsdGVyLnVzZXJOYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlcy5xID0gZmlsdGVyLnVzZXJOYW1lO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgdG9JZEZpbHRlcnMgPSBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZCA9ICQuaXNBcnJheShpZCkgPyBpZCA6IFtpZF07XG4gICAgICAgICAgICAgICAgcmV0dXJuICdpZD0nICsgaWQuam9pbignJmlkPScpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIGdldEZpbHRlcnMgPSBbXG4gICAgICAgICAgICAgICAgJ2FjY291bnQ9JyArIGdldE9wdGlvbnMuYWNjb3VudCxcbiAgICAgICAgICAgICAgICB0b0lkRmlsdGVycyhmaWx0ZXIuaWQpLFxuICAgICAgICAgICAgICAgIHF1dGlsLnRvUXVlcnlGb3JtYXQodG9RRmlsdGVyKGZpbHRlcikpXG4gICAgICAgICAgICBdLmpvaW4oJyYnKTtcblxuICAgICAgICAgICAgLy8gc3BlY2lhbCBjYXNlIGZvciBxdWVyaWVzIHdpdGggbGFyZ2UgbnVtYmVyIG9mIGlkc1xuICAgICAgICAgICAgLy8gbWFrZSBpdCBhcyBhIHBvc3Qgd2l0aCBHRVQgc2VtYW50aWNzXG4gICAgICAgICAgICB2YXIgdGhyZXNob2xkID0gMzA7XG4gICAgICAgICAgICBpZiAoZmlsdGVyLmlkICYmICQuaXNBcnJheShmaWx0ZXIuaWQpICYmIGZpbHRlci5pZC5sZW5ndGggPj0gdGhyZXNob2xkKSB7XG4gICAgICAgICAgICAgICAgZ2V0T3B0aW9ucy51cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpICsgJz9fbWV0aG9kPUdFVCc7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdCh7IGlkOiBmaWx0ZXIuaWQgfSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChnZXRGaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXRyaWV2ZSBkZXRhaWxzIGFib3V0IGEgc2luZ2xlIGVuZCB1c2VyIGluIHlvdXIgdGVhbSwgYmFzZWQgb24gdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXRCeUlkKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSB1c2VyIGlkIGZvciB0aGUgZW5kIHVzZXIgaW4geW91ciB0ZWFtLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXRCeUlkOiBmdW5jdGlvbiAodXNlcklkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcHVibGljQVBJLmdldCh7IGlkOiB1c2VySWQgfSwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG5cblxuXG5cbiIsIi8qKlxuICpcbiAqICMjIFZhcmlhYmxlcyBBUEkgU2VydmljZVxuICpcbiAqIFVzZWQgaW4gY29uanVuY3Rpb24gd2l0aCB0aGUgW1J1biBBUEkgU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykgdG8gcmVhZCwgd3JpdGUsIGFuZCBzZWFyY2ggZm9yIHNwZWNpZmljIG1vZGVsIHZhcmlhYmxlcy5cbiAqXG4gKiAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiAqICAgICAgICAgICBydW46IHtcbiAqICAgICAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgICAgICBtb2RlbDogJ3N1cHBseS1jaGFpbi1tb2RlbC5qbCdcbiAqICAgICAgICAgICB9XG4gKiAgICAgIH0pO1xuICogICAgIHJtLmdldFJ1bigpXG4gKiAgICAgICAudGhlbihmdW5jdGlvbigpIHtcbiAqICAgICAgICAgIHZhciB2cyA9IHJtLnJ1bi52YXJpYWJsZXMoKTtcbiAqICAgICAgICAgIHZzLnNhdmUoe3NhbXBsZV9pbnQ6IDR9KTtcbiAqICAgICAgICB9KTtcbiAqXG4gKi9cblxuXG4gJ3VzZSBzdHJpY3QnO1xuXG4gdmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xuIHZhciBydXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcnVuLXV0aWwnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHJ1bnMgb2JqZWN0IHRvIHdoaWNoIHRoZSB2YXJpYWJsZSBmaWx0ZXJzIGFwcGx5LiBEZWZhdWx0cyB0byBudWxsLlxuICAgICAgICAgKiBAdHlwZSB7cnVuU2VydmljZX1cbiAgICAgICAgICovXG4gICAgICAgIHJ1blNlcnZpY2U6IG51bGxcbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciBnZXRVUkwgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucy5ydW5TZXJ2aWNlLnVybENvbmZpZy5nZXRGaWx0ZXJVUkwoKSArICd2YXJpYWJsZXMvJztcbiAgICB9O1xuXG4gICAgdmFyIGFkZEF1dG9SZXN0b3JlSGVhZGVyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zLnJ1blNlcnZpY2UudXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKG9wdGlvbnMpO1xuICAgIH07XG5cbiAgICB2YXIgaHR0cE9wdGlvbnMgPSB7XG4gICAgICAgIHVybDogZ2V0VVJMXG4gICAgfTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG4gICAgaHR0cC5zcGxpdEdldCA9IHJ1dGlsLnNwbGl0R2V0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgdmFsdWVzIGZvciBhIHZhcmlhYmxlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHZzLmxvYWQoJ3NhbXBsZV9pbnQnKVxuICAgICAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbih2YWwpe1xuICAgICAgICAgKiAgICAgICAgICAgICAgLy8gdmFsIGNvbnRhaW5zIHRoZSB2YWx1ZSBvZiBzYW1wbGVfaW50XG4gICAgICAgICAqICAgICAgICAgIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYHZhcmlhYmxlYCBOYW1lIG9mIHZhcmlhYmxlIHRvIGxvYWQuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uICh2YXJpYWJsZSwgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucyA9IGFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChvdXRwdXRNb2RpZmllciwgJC5leHRlbmQoe30sIGh0dHBPcHRpb25zLCB7XG4gICAgICAgICAgICAgICAgdXJsOiBnZXRVUkwoKSArIHZhcmlhYmxlICsgJy8nXG4gICAgICAgICAgICB9KSk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJldHVybnMgcGFydGljdWxhciB2YXJpYWJsZXMsIGJhc2VkIG9uIGNvbmRpdGlvbnMgc3BlY2lmaWVkIGluIHRoZSBgcXVlcnlgIG9iamVjdC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICB2cy5xdWVyeShbJ3ByaWNlJywgJ3NhbGVzJ10pXG4gICAgICAgICAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHZhbCkge1xuICAgICAgICAgKiAgICAgICAgICAgICAgLy8gdmFsIGlzIGFuIG9iamVjdCB3aXRoIHRoZSB2YWx1ZXMgb2YgdGhlIHJlcXVlc3RlZCB2YXJpYWJsZXM6IHZhbC5wcmljZSwgdmFsLnNhbGVzXG4gICAgICAgICAqICAgICAgICAgIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHZzLnF1ZXJ5KHsgaW5jbHVkZTpbJ3ByaWNlJywgJ3NhbGVzJ10gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fEFycmF5fSBgcXVlcnlgIFRoZSBuYW1lcyBvZiB0aGUgdmFyaWFibGVzIHJlcXVlc3RlZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKlxuICAgICAgICAgKi9cbiAgICAgICAgcXVlcnk6IGZ1bmN0aW9uIChxdWVyeSwgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIC8vUXVlcnkgYW5kIG91dHB1dE1vZGlmaWVyIGFyZSBib3RoIHF1ZXJ5c3RyaW5ncyBpbiB0aGUgdXJsOyBvbmx5IGNhbGxpbmcgdGhlbSBvdXQgc2VwYXJhdGVseSBoZXJlIHRvIGJlIGNvbnNpc3RlbnQgd2l0aCB0aGUgb3RoZXIgY2FsbHNcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucyA9IGFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcblxuICAgICAgICAgICAgaWYgKCQuaXNBcnJheShxdWVyeSkpIHtcbiAgICAgICAgICAgICAgICBxdWVyeSA9IHsgaW5jbHVkZTogcXVlcnkgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgICQuZXh0ZW5kKHF1ZXJ5LCBvdXRwdXRNb2RpZmllcik7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5zcGxpdEdldChxdWVyeSwgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIHZhbHVlcyB0byBtb2RlbCB2YXJpYWJsZXMuIE92ZXJ3cml0ZXMgZXhpc3RpbmcgdmFsdWVzLiBOb3RlIHRoYXQgeW91IGNhbiBvbmx5IHVwZGF0ZSBtb2RlbCB2YXJpYWJsZXMgaWYgdGhlIHJ1biBpcyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KS4gKEFuIGFsdGVybmF0ZSB3YXkgdG8gdXBkYXRlIG1vZGVsIHZhcmlhYmxlcyBpcyB0byBjYWxsIGEgbWV0aG9kIGZyb20gdGhlIG1vZGVsIGFuZCBtYWtlIHN1cmUgdGhhdCB0aGUgbWV0aG9kIHBlcnNpc3RzIHRoZSB2YXJpYWJsZXMuIFNlZSBgZG9gLCBgc2VyaWFsYCwgYW5kIGBwYXJhbGxlbGAgaW4gdGhlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pIGZvciBjYWxsaW5nIG1ldGhvZHMgZnJvbSB0aGUgbW9kZWwuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHZzLnNhdmUoJ3ByaWNlJywgNCk7XG4gICAgICAgICAqICAgICAgdnMuc2F2ZSh7IHByaWNlOiA0LCBxdWFudGl0eTogNSwgcHJvZHVjdHM6IFsyLDMsNF0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fFN0cmluZ30gYHZhcmlhYmxlYCBBbiBvYmplY3QgY29tcG9zZWQgb2YgdGhlIG1vZGVsIHZhcmlhYmxlcyBhbmQgdGhlIHZhbHVlcyB0byBzYXZlLiBBbHRlcm5hdGl2ZWx5LCBhIHN0cmluZyB3aXRoIHRoZSBuYW1lIG9mIHRoZSB2YXJpYWJsZS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGB2YWxgIChPcHRpb25hbCkgSWYgcGFzc2luZyBhIHN0cmluZyBmb3IgYHZhcmlhYmxlYCwgdXNlIHRoaXMgYXJndW1lbnQgZm9yIHRoZSB2YWx1ZSB0byBzYXZlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBzYXZlOiBmdW5jdGlvbiAodmFyaWFibGUsIHZhbCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGF0dHJzO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiB2YXJpYWJsZSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgICAgICBhdHRycyA9IHZhcmlhYmxlO1xuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSB2YWw7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIChhdHRycyA9IHt9KVt2YXJpYWJsZV0gPSB2YWw7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wYXRjaC5jYWxsKHRoaXMsIGF0dHJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBOb3QgQXZhaWxhYmxlIHVudGlsIHVuZGVybHlpbmcgQVBJIHN1cHBvcnRzIFBVVC4gT3RoZXJ3aXNlIHNhdmUgd291bGQgYmUgUFVUIGFuZCBtZXJnZSB3b3VsZCBiZSBQQVRDSFxuICAgICAgICAvLyAqXG4gICAgICAgIC8vICAqIFNhdmUgdmFsdWVzIHRvIHRoZSBhcGkuIE1lcmdlcyBhcnJheXMsIGJ1dCBvdGhlcndpc2Ugc2FtZSBhcyBzYXZlXG4gICAgICAgIC8vICAqIEBwYXJhbSB7T2JqZWN0fFN0cmluZ30gdmFyaWFibGUgT2JqZWN0IHdpdGggYXR0cmlidXRlcywgb3Igc3RyaW5nIGtleVxuICAgICAgICAvLyAgKiBAcGFyYW0ge09iamVjdH0gdmFsIE9wdGlvbmFsIGlmIHByZXYgcGFyYW1ldGVyIHdhcyBhIHN0cmluZywgc2V0IHZhbHVlIGhlcmVcbiAgICAgICAgLy8gICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnNcbiAgICAgICAgLy8gICpcbiAgICAgICAgLy8gICogQGV4YW1wbGVcbiAgICAgICAgLy8gICogICAgIHZzLm1lcmdlKHsgcHJpY2U6IDQsIHF1YW50aXR5OiA1LCBwcm9kdWN0czogWzIsMyw0XSB9KVxuICAgICAgICAvLyAgKiAgICAgdnMubWVyZ2UoJ3ByaWNlJywgNCk7XG5cbiAgICAgICAgLy8gbWVyZ2U6IGZ1bmN0aW9uICh2YXJpYWJsZSwgdmFsLCBvcHRpb25zKSB7XG4gICAgICAgIC8vICAgICB2YXIgYXR0cnM7XG4gICAgICAgIC8vICAgICBpZiAodHlwZW9mIHZhcmlhYmxlID09PSAnb2JqZWN0Jykge1xuICAgICAgICAvLyAgICAgICBhdHRycyA9IHZhcmlhYmxlO1xuICAgICAgICAvLyAgICAgICBvcHRpb25zID0gdmFsO1xuICAgICAgICAvLyAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gICAgICAgKGF0dHJzID0ge30pW3ZhcmlhYmxlXSA9IHZhbDtcbiAgICAgICAgLy8gICAgIH1cbiAgICAgICAgLy8gICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgLy8gICAgIHJldHVybiBodHRwLnBhdGNoLmNhbGwodGhpcywgYXR0cnMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgLy8gfVxuICAgIH07XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqICMjIFdvcmxkIEFQSSBBZGFwdGVyXG4gKlxuICogQSBbcnVuXSguLi8uLi8uLi9nbG9zc2FyeS8jcnVuKSBpcyBhIGNvbGxlY3Rpb24gb2YgZW5kIHVzZXIgaW50ZXJhY3Rpb25zIHdpdGggYSBwcm9qZWN0IGFuZCBpdHMgbW9kZWwgLS0gaW5jbHVkaW5nIHNldHRpbmcgdmFyaWFibGVzLCBtYWtpbmcgZGVjaXNpb25zLCBhbmQgY2FsbGluZyBvcGVyYXRpb25zLiBGb3IgYnVpbGRpbmcgbXVsdGlwbGF5ZXIgc2ltdWxhdGlvbnMgeW91IHR5cGljYWxseSB3YW50IG11bHRpcGxlIGVuZCB1c2VycyB0byBzaGFyZSB0aGUgc2FtZSBzZXQgb2YgaW50ZXJhY3Rpb25zLCBhbmQgd29yayB3aXRoaW4gYSBjb21tb24gc3RhdGUuIEVwaWNlbnRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSBcIndvcmxkc1wiIHRvIGhhbmRsZSBzdWNoIGNhc2VzLiBPbmx5IFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9nbG9zc2FyeS8jdGVhbSkgY2FuIGJlIG11bHRpcGxheWVyLlxuICpcbiAqIFRoZSBXb3JsZCBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgbWFuaXB1bGF0ZSBtdWx0aXBsYXllciB3b3JsZHMgd2l0aGluIHlvdXIgRXBpY2VudGVyIHByb2plY3QuIFlvdSBjYW4gdXNlIHRoaXMgdG8gYWRkIGFuZCByZW1vdmUgZW5kIHVzZXJzIGZyb20gdGhlIHdvcmxkLCBhbmQgdG8gY3JlYXRlLCBhY2Nlc3MsIGFuZCByZW1vdmUgdGhlaXIgcnVucy4gQmVjYXVzZSBvZiB0aGlzLCB0eXBpY2FsbHkgdGhlIFdvcmxkIEFkYXB0ZXIgaXMgdXNlZCBmb3IgZmFjaWxpdGF0b3IgcGFnZXMgaW4geW91ciBwcm9qZWN0LiAoVGhlIHJlbGF0ZWQgW1dvcmxkIE1hbmFnZXJdKC4uL3dvcmxkLW1hbmFnZXIvKSBwcm92aWRlcyBhbiBlYXN5IHdheSB0byBhY2Nlc3MgcnVucyBhbmQgd29ybGRzIGZvciBwYXJ0aWN1bGFyIGVuZCB1c2Vycywgc28gaXMgdHlwaWNhbGx5IHVzZWQgaW4gcGFnZXMgdGhhdCBlbmQgdXNlcnMgd2lsbCBpbnRlcmFjdCB3aXRoLilcbiAqXG4gKiBBcyB3aXRoIGFsbCB0aGUgb3RoZXIgW0FQSSBBZGFwdGVyc10oLi4vLi4vKSwgYWxsIG1ldGhvZHMgdGFrZSBpbiBhbiBcIm9wdGlvbnNcIiBvYmplY3QgYXMgdGhlIGxhc3QgcGFyYW1ldGVyLiBUaGUgb3B0aW9ucyBjYW4gYmUgdXNlZCB0byBleHRlbmQvb3ZlcnJpZGUgdGhlIFdvcmxkIEFQSSBTZXJ2aWNlIGRlZmF1bHRzLlxuICpcbiAqIFRvIHVzZSB0aGUgV29ybGQgQWRhcHRlciwgaW5zdGFudGlhdGUgaXQgYW5kIHRoZW4gYWNjZXNzIHRoZSBtZXRob2RzIHByb3ZpZGVkLiBJbnN0YW50aWF0aW5nIHJlcXVpcmVzIHRoZSBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBpbiB0aGUgRXBpY2VudGVyIHVzZXIgaW50ZXJmYWNlKSwgcHJvamVjdCBpZCAoKipQcm9qZWN0IElEKiopLCBhbmQgZ3JvdXAgKCoqR3JvdXAgTmFtZSoqKS5cbiAqXG4gKiAgICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAqICAgICAgIHdhLmNyZWF0ZSgpXG4gKiAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICogICAgICAgICAgICAgIC8vIGNhbGwgbWV0aG9kcywgZS5nLiB3YS5hZGRVc2VycygpXG4gKiAgICAgICAgICB9KTtcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbi8vIHZhciBxdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG5cbnZhciBhcGlCYXNlID0gJ211bHRpcGxheWVyLyc7XG52YXIgYXNzaWdubWVudEVuZHBvaW50ID0gYXBpQmFzZSArICdhc3NpZ24nO1xudmFyIGFwaUVuZHBvaW50ID0gYXBpQmFzZSArICd3b3JsZCc7XG52YXIgcHJvamVjdEVuZHBvaW50ID0gYXBpQmFzZSArICdwcm9qZWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRm9yIHByb2plY3RzIHRoYXQgcmVxdWlyZSBhdXRoZW50aWNhdGlvbiwgcGFzcyBpbiB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gKGRlZmF1bHRzIHRvIGVtcHR5IHN0cmluZykuIElmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluIHRvIEVwaWNlbnRlciwgdGhlIHVzZXIgYWNjZXNzIHRva2VuIGlzIGFscmVhZHkgc2V0IGluIGEgY29va2llIGFuZCBhdXRvbWF0aWNhbGx5IGxvYWRlZCBmcm9tIHRoZXJlLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICAgICAqIEBzZWUgW0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXSguLi9hdXRoLWFwaS1zZXJ2aWNlLykgZm9yIGdldHRpbmcgdG9rZW5zLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICB0b2tlbjogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcHJvamVjdCBpZC4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBncm91cCBuYW1lLiBEZWZhdWx0cyB0byB1bmRlZmluZWQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBncm91cDogdW5kZWZpbmVkLFxuXG4gICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBtb2RlbCBmaWxlIHRvIHVzZSB0byBjcmVhdGUgcnVucyBpbiB0aGlzIHdvcmxkLiBEZWZhdWx0cyB0byB1bmRlZmluZWQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBtb2RlbDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDcml0ZXJpYSBieSB3aGljaCB0byBmaWx0ZXIgd29ybGQuIEN1cnJlbnRseSBvbmx5IHN1cHBvcnRzIHdvcmxkLWlkcyBhcyBmaWx0ZXJzLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZmlsdGVyOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVuaWVuY2UgYWxpYXMgZm9yIGZpbHRlclxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgaWQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge30sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENhbGxlZCB3aGVuIHRoZSBjYWxsIGNvbXBsZXRlcyBzdWNjZXNzZnVsbHkuIERlZmF1bHRzIHRvIGAkLm5vb3BgLlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICBzdWNjZXNzOiAkLm5vb3AsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENhbGxlZCB3aGVuIHRoZSBjYWxsIGZhaWxzLiBEZWZhdWx0cyB0byBgJC5ub29wYC5cbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgZXJyb3I6ICQubm9vcFxuICAgIH07XG5cbiAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMucHJvamVjdCA9IHVybENvbmZpZy5wcm9qZWN0UGF0aDtcbiAgICB9XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBzZXRJZEZpbHRlck9yVGhyb3dFcnJvciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGlmIChvcHRpb25zLmlkKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmlkO1xuICAgICAgICB9XG4gICAgICAgIGlmIChvcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gb3B0aW9ucy5maWx0ZXI7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gd29ybGQgaWQgc3BlY2lmaWVkIHRvIGFwcGx5IG9wZXJhdGlvbnMgYWdhaW5zdC4gVGhpcyBjb3VsZCBoYXBwZW4gaWYgdGhlIHVzZXIgaXMgbm90IGFzc2lnbmVkIHRvIGEgd29ybGQgYW5kIGlzIHRyeWluZyB0byB3b3JrIHdpdGggcnVucyBmcm9tIHRoYXQgd29ybGQuJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICBpZiAoIW9wdGlvbnMubW9kZWwpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gbW9kZWwgc3BlY2lmaWVkIHRvIGdldCB0aGUgY3VycmVudCBydW4nKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIENyZWF0ZXMgYSBuZXcgV29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBVc2luZyB0aGlzIG1ldGhvZCBpcyByYXJlLiBJdCBpcyBtb3JlIGNvbW1vbiB0byBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkgd2hpbGUgeW91IGBhdXRvQXNzaWduKClgIGVuZCB1c2VycyB0byB3b3JsZHMuIChJbiB0aGlzIGNhc2UsIGNvbmZpZ3VyYXRpb24gZGF0YSBmb3IgdGhlIHdvcmxkLCBzdWNoIGFzIHRoZSByb2xlcywgYXJlIHJlYWQgZnJvbSB0aGUgcHJvamVjdC1sZXZlbCB3b3JsZCBjb25maWd1cmF0aW9uIGluZm9ybWF0aW9uLCBmb3IgZXhhbXBsZSBieSBgZ2V0UHJvamVjdFNldHRpbmdzKClgLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSh7XG4gICAgICAgICogICAgICAgICAgIHJvbGVzOiBbJ1ZQIE1hcmtldGluZycsICdWUCBTYWxlcycsICdWUCBFbmdpbmVlcmluZyddXG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBjcmVhdGUgdGhlIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmdyb3VwYCAoT3B0aW9uYWwpIFRoZSAqKkdyb3VwIE5hbWUqKiB0byBjcmVhdGUgdGhpcyB3b3JsZCB1bmRlci4gT25seSBlbmQgdXNlcnMgaW4gdGhpcyBncm91cCBhcmUgZWxpZ2libGUgdG8gam9pbiB0aGUgd29ybGQuIE9wdGlvbmFsIGhlcmU7IHJlcXVpcmVkIHdoZW4gaW5zdGFudGlhdGluZyB0aGUgc2VydmljZSAoYG5ldyBGLnNlcnZpY2UuV29ybGQoKWApLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zLnJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbXVzdCoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIHJvbGVzIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMub3B0aW9uYWxSb2xlc2AgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gYHBhcmFtcy5taW5Vc2Vyc2AgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgfSk7XG4gICAgICAgICAgICB2YXIgd29ybGRBcGlQYXJhbXMgPSBbJ3Njb3BlJywgJ2ZpbGVzJywgJ3JvbGVzJywgJ29wdGlvbmFsUm9sZXMnLCAnbWluVXNlcnMnLCAnZ3JvdXAnLCAnbmFtZSddO1xuICAgICAgICAgICAgdmFyIHZhbGlkUGFyYW1zID0gX3BpY2soc2VydmljZU9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pO1xuICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIHdvcmxkQXBpUGFyYW1zKTtcblxuICAgICAgICAgICAgLy8gYWNjb3VudCBhbmQgcHJvamVjdCBnbyBpbiB0aGUgYm9keSwgbm90IGluIHRoZSB1cmxcbiAgICAgICAgICAgIHBhcmFtcyA9ICQuZXh0ZW5kKHt9LCB2YWxpZFBhcmFtcywgcGFyYW1zKTtcblxuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBjcmVhdGVPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgICAgICBjcmVhdGVPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSByZXNwb25zZS5pZDsgLy9hbGwgZnV0dXJlIGNoYWluZWQgY2FsbHMgdG8gb3BlcmF0ZSBvbiB0aGlzIGlkXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBVcGRhdGVzIGEgV29ybGQsIGZvciBleGFtcGxlIHRvIHJlcGxhY2UgdGhlIHJvbGVzIGluIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgeW91IGNvbXBsZXRlIHdvcmxkIGNvbmZpZ3VyYXRpb24gYXQgdGhlIHByb2plY3QgbGV2ZWwsIHJhdGhlciB0aGFuIGF0IHRoZSB3b3JsZCBsZXZlbC4gRm9yIGV4YW1wbGUsIGVhY2ggd29ybGQgaW4geW91ciBwcm9qZWN0IHByb2JhYmx5IGhhcyB0aGUgc2FtZSByb2xlcyBmb3IgZW5kIHVzZXJzLiBBbmQgeW91ciBwcm9qZWN0IGlzIHByb2JhYmx5IGVpdGhlciBjb25maWd1cmVkIHNvIHRoYXQgYWxsIGVuZCB1c2VycyBzaGFyZSB0aGUgc2FtZSB3b3JsZCAoYW5kIHJ1biksIG9yIHNtYWxsZXIgc2V0cyBvZiBlbmQgdXNlcnMgc2hhcmUgd29ybGRzIOKAlCBidXQgbm90IGJvdGguIEhvd2V2ZXIsIHRoaXMgbWV0aG9kIGlzIGF2YWlsYWJsZSBpZiB5b3UgbmVlZCB0byB1cGRhdGUgdGhlIGNvbmZpZ3VyYXRpb24gb2YgYSBwYXJ0aWN1bGFyIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnVwZGF0ZSh7IHJvbGVzOiBbJ1ZQIE1hcmtldGluZycsICdWUCBTYWxlcycsICdWUCBFbmdpbmVlcmluZyddIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBQYXJhbWV0ZXJzIHRvIHVwZGF0ZSB0aGUgd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMubmFtZWAgQSBzdHJpbmcgaWRlbnRpZmllciBmb3IgdGhlIGxpbmtlZCBlbmQgdXNlcnMsIGZvciBleGFtcGxlLCBcIm5hbWVcIjogXCJPdXIgVGVhbVwiLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zLnJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbXVzdCoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIHJvbGVzIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMub3B0aW9uYWxSb2xlc2AgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gYHBhcmFtcy5taW5Vc2Vyc2AgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHdoaXRlbGlzdCA9IFsncm9sZXMnLCAnb3B0aW9uYWxSb2xlcycsICdtaW5Vc2VycyddO1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIHVwZGF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gX3BpY2socGFyYW1zIHx8IHt9LCB3aGl0ZWxpc3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wYXRjaChwYXJhbXMsIHVwZGF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgYW4gZXhpc3Rpbmcgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBUaGlzIGZ1bmN0aW9uIG9wdGlvbmFsbHkgdGFrZXMgb25lIGFyZ3VtZW50LiBJZiB0aGUgYXJndW1lbnQgaXMgYSBzdHJpbmcsIGl0IGlzIHRoZSBpZCBvZiB0aGUgd29ybGQgdG8gZGVsZXRlLiBJZiB0aGUgYXJndW1lbnQgaXMgYW4gb2JqZWN0LCBpdCBpcyB0aGUgb3ZlcnJpZGUgZm9yIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmRlbGV0ZSgpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBkZWxldGUsIG9yIG9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSAob3B0aW9ucyAmJiAodHlwZW9mIG9wdGlvbnMgPT09ICdzdHJpbmcnKSkgPyB7IGZpbHRlcjogb3B0aW9ucyB9IDoge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRlbGV0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGRlbGV0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBjdXJyZW50IGluc3RhbmNlIG9mIHRoZSBXb3JsZCBBUEkgQWRhcHRlciAoaW5jbHVkaW5nIGFsbCBzdWJzZXF1ZW50IGZ1bmN0aW9uIGNhbGxzLCB1bnRpbCB0aGUgY29uZmlndXJhdGlvbiBpcyB1cGRhdGVkIGFnYWluKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoey4uLn0pLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogJzEyMycgfSkuYWRkVXNlcih7IHVzZXJJZDogJzEyMycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgY29uZmlnYCBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgdG8gdXNlIGluIHVwZGF0aW5nIGV4aXN0aW5nIGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZUNvbmZpZzogZnVuY3Rpb24gKGNvbmZpZykge1xuICAgICAgICAgICAgJC5leHRlbmQoc2VydmljZU9wdGlvbnMsIGNvbmZpZyk7XG5cbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIExpc3RzIGFsbCB3b3JsZHMgZm9yIGEgZ2l2ZW4gYWNjb3VudCwgcHJvamVjdCwgYW5kIGdyb3VwLiBBbGwgdGhyZWUgYXJlIHJlcXVpcmVkLCBhbmQgaWYgbm90IHNwZWNpZmllZCBhcyBwYXJhbWV0ZXJzLCBhcmUgcmVhZCBmcm9tIHRoZSBzZXJ2aWNlLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGxpc3RzIGFsbCB3b3JsZHMgaW4gZ3JvdXAgXCJ0ZWFtMVwiXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5saXN0KCk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGxpc3RzIGFsbCB3b3JsZHMgaW4gZ3JvdXAgXCJvdGhlci1ncm91cC1uYW1lXCJcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmxpc3QoeyBncm91cDogJ290aGVyLWdyb3VwLW5hbWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBsaXN0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBmaWx0ZXJzID0gX3BpY2soZ2V0T3B0aW9ucywgWydhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGFsbCB3b3JsZHMgdGhhdCBhbiBlbmQgdXNlciBiZWxvbmdzIHRvIGZvciBhIGdpdmVuIGFjY291bnQgKHRlYW0pLCBwcm9qZWN0LCBhbmQgZ3JvdXAuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuZ2V0V29ybGRzRm9yVXNlcignYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJylcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZHMgYXJlIGJlaW5nIHJldHJpZXZlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGdldFdvcmxkc0ZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB2YXIgZmlsdGVycyA9ICQuZXh0ZW5kKFxuICAgICAgICAgICAgICAgIF9waWNrKGdldE9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pLFxuICAgICAgICAgICAgICAgIHsgdXNlcklkOiB1c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGZpbHRlcnMsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2FkIGluZm9ybWF0aW9uIGZvciBhIHNwZWNpZmljIHdvcmxkLiBBbGwgZnVydGhlciBjYWxscyB0byB0aGUgd29ybGQgc2VydmljZSB3aWxsIHVzZSB0aGUgaWQgcHJvdmlkZWQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgd29ybGRJZGAgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBsb2FkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSB3b3JsZElkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwcm92aWRlIGEgd29ybGRpZCB0byBsb2FkJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy8nIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQWRkcyBhbiBlbmQgdXNlciBvciBsaXN0IG9mIGVuZCB1c2VycyB0byBhIGdpdmVuIHdvcmxkLiBUaGUgZW5kIHVzZXIgbXVzdCBiZSBhIG1lbWJlciBvZiB0aGUgYGdyb3VwYCB0aGF0IGlzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBvbmUgdXNlclxuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoWydiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2Vycyh7IHVzZXJJZDogJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHJvbGU6ICdWUCBTYWxlcycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBzZXZlcmFsIHVzZXJzXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgeyB1c2VySWQ6ICdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgcm9sZTogJ1ZQIE1hcmtldGluZycgfSxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICB7IHVzZXJJZDogJzhmMjYwNGNmLTk2Y2QtNDQ5Zi04MmZhLWUzMzE1MzA3MzRlZScsXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgICByb2xlOiAnVlAgRW5naW5lZXJpbmcnIH1cbiAgICAgICAgKiAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgICAgICAgICAvLyBhZGQgb25lIHVzZXIgdG8gYSBzcGVjaWZpYyB3b3JsZFxuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB7IGZpbHRlcjogd29ybGQuaWQgfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKiogUGFyYW1ldGVycyAqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdHxhcnJheX0gYHVzZXJzYCBVc2VyIGlkLCBhcnJheSBvZiB1c2VyIGlkcywgb2JqZWN0LCBvciBhcnJheSBvZiBvYmplY3RzIG9mIHRoZSB1c2VycyB0byBhZGQgdG8gdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJzLnJvbGVgIFRoZSBgcm9sZWAgdGhlIHVzZXIgc2hvdWxkIGhhdmUgaW4gdGhlIHdvcmxkLiBJdCBpcyB1cCB0byB0aGUgY2FsbGVyIHRvIGVuc3VyZSwgaWYgbmVlZGVkLCB0aGF0IHRoZSBgcm9sZWAgcGFzc2VkIGluIGlzIG9uZSBvZiB0aGUgYHJvbGVzYCBvciBgb3B0aW9uYWxSb2xlc2Agb2YgdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHdvcmxkSWRgIFRoZSB3b3JsZCB0byB3aGljaCB0aGUgdXNlcnMgc2hvdWxkIGJlIGFkZGVkLiBJZiBub3Qgc3BlY2lmaWVkLCB0aGUgZmlsdGVyIHBhcmFtZXRlciBvZiB0aGUgYG9wdGlvbnNgIG9iamVjdCBpcyB1c2VkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgYWRkVXNlcnM6IGZ1bmN0aW9uICh1c2Vycywgd29ybGRJZCwgb3B0aW9ucykge1xuXG4gICAgICAgICAgICBpZiAoIXVzZXJzKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhIGxpc3Qgb2YgdXNlcnMgdG8gYWRkIHRvIHRoZSB3b3JsZCcpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBub3JtYWxpemUgdGhlIGxpc3Qgb2YgdXNlcnMgdG8gYW4gYXJyYXkgb2YgdXNlciBvYmplY3RzXG4gICAgICAgICAgICB1c2VycyA9ICQubWFwKFtdLmNvbmNhdCh1c2VycyksIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgdmFyIGlzT2JqZWN0ID0gJC5pc1BsYWluT2JqZWN0KHUpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB1ICE9PSAnc3RyaW5nJyAmJiAhaXNPYmplY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTb21lIG9mIHRoZSB1c2VycyBpbiB0aGUgbGlzdCBhcmUgbm90IGluIHRoZSB2YWxpZCBmb3JtYXQ6ICcgKyB1KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gaXNPYmplY3QgPyB1IDogeyB1c2VySWQ6IHUgfTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyBjaGVjayBpZiBvcHRpb25zIHdlcmUgcGFzc2VkIGFzIHRoZSBzZWNvbmQgcGFyYW1ldGVyXG4gICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHdvcmxkSWQpICYmICFvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHdvcmxkSWQ7XG4gICAgICAgICAgICAgICAgd29ybGRJZCA9IG51bGw7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICAvLyB3ZSBtdXN0IGhhdmUgb3B0aW9ucyBieSBub3dcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygd29ybGRJZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgdXBkYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvdXNlcnMnIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QodXNlcnMsIHVwZGF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIHJvbGUgb2YgYW4gZW5kIHVzZXIgaW4gYSBnaXZlbiB3b3JsZC4gKFlvdSBjYW4gb25seSB1cGRhdGUgb25lIGVuZCB1c2VyIGF0IGEgdGltZS4pXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuY3JlYXRlKCkudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJyk7XG4gICAgICAgICogICAgICAgICAgIHdhLnVwZGF0ZVVzZXIoeyB1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCByb2xlOiAnbGVhZGVyJyB9KTtcbiAgICAgICAgKiAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHVzZXJgIFVzZXIgb2JqZWN0IHdpdGggYHVzZXJJZGAgYW5kIHRoZSBuZXcgYHJvbGVgLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICB1cGRhdGVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICghdXNlciB8fCAhdXNlci51c2VySWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1lvdSBuZWVkIHRvIHBhc3MgYSB1c2VySWQgdG8gdXBkYXRlIGZyb20gdGhlIHdvcmxkJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcGF0Y2hPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goX3BpY2sodXNlciwgJ3JvbGUnKSwgcGF0Y2hPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZW1vdmVzIGFuIGVuZCB1c2VyIGZyb20gYSBnaXZlbiB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbJ2E2ZmUwYzFlLWY0YjgtNGYwMS05ZjVmLTAxY2NmNGMyZWQ0NCcsICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5yZW1vdmVVc2VyKCdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnJlbW92ZVVzZXIoeyB1c2VySWQ6ICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdHxzdHJpbmd9IGB1c2VyYCBUaGUgYHVzZXJJZGAgb2YgdGhlIHVzZXIgdG8gcmVtb3ZlIGZyb20gdGhlIHdvcmxkLCBvciBhbiBvYmplY3QgY29udGFpbmluZyB0aGUgYHVzZXJJZGAgZmllbGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICByZW1vdmVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICh0eXBlb2YgdXNlciA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICB1c2VyID0geyB1c2VySWQ6IHVzZXIgfTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCF1c2VyLnVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignWW91IG5lZWQgdG8gcGFzcyBhIHVzZXJJZCB0byByZW1vdmUgZnJvbSB0aGUgd29ybGQnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIHJ1biBpZCBvZiBjdXJyZW50IHJ1biBmb3IgdGhlIGdpdmVuIHdvcmxkLiBJZiB0aGUgd29ybGQgZG9lcyBub3QgaGF2ZSBhIHJ1biwgY3JlYXRlcyBhIG5ldyBvbmUgYW5kIHJldHVybnMgdGhlIHJ1biBpZC5cbiAgICAgICAgKlxuICAgICAgICAqIFJlbWVtYmVyIHRoYXQgYSBbcnVuXSguLi8uLi9nbG9zc2FyeS8jcnVuKSBpcyBhIGNvbGxlY3Rpb24gb2YgaW50ZXJhY3Rpb25zIHdpdGggYSBwcm9qZWN0IGFuZCBpdHMgbW9kZWwuIEluIHRoZSBjYXNlIG9mIG11bHRpcGxheWVyIHByb2plY3RzLCB0aGUgcnVuIGlzIHNoYXJlZCBieSBhbGwgZW5kIHVzZXJzIGluIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5nZXRDdXJyZW50UnVuSWQoeyBtb2RlbDogJ21vZGVsLnB5JyB9KTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9ucy5tb2RlbGAgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRSdW5JZDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3J1bicgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvcihnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QoX3BpY2soZ2V0T3B0aW9ucywgJ21vZGVsJyksIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIGN1cnJlbnQgKG1vc3QgcmVjZW50KSB3b3JsZCBmb3IgdGhlIGdpdmVuIGVuZCB1c2VyIGluIHRoZSBnaXZlbiBncm91cC4gQnJpbmdzIHRoaXMgbW9zdCByZWNlbnQgd29ybGQgaW50byBtZW1vcnkgaWYgbmVlZGVkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIHVzZSBkYXRhIGZyb20gd29ybGRcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSBjdXJyZW50IChtb3N0IHJlY2VudCkgd29ybGQgaXMgYmVpbmcgcmV0cmlldmVkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIFRoZSBuYW1lIG9mIHRoZSBncm91cC4gSWYgbm90IHByb3ZpZGVkLCBkZWZhdWx0cyB0byB0aGUgZ3JvdXAgdXNlZCB0byBjcmVhdGUgdGhlIHNlcnZpY2UuXG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRXb3JsZEZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIGdyb3VwTmFtZSkge1xuICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgICAgICB0aGlzLmdldFdvcmxkc0ZvclVzZXIodXNlcklkLCB7IGdyb3VwOiBncm91cE5hbWUgfSlcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGRzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGFzc3VtZSB0aGUgbW9zdCByZWNlbnQgd29ybGQgYXMgdGhlICdhY3RpdmUnIHdvcmxkXG4gICAgICAgICAgICAgICAgICAgIHdvcmxkcy5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7IHJldHVybiBuZXcgRGF0ZShiLmxhc3RNb2RpZmllZCkgLSBuZXcgRGF0ZShhLmxhc3RNb2RpZmllZCk7IH0pO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3VycmVudFdvcmxkID0gd29ybGRzWzBdO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChjdXJyZW50V29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9ICBjdXJyZW50V29ybGQuaWQ7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShjdXJyZW50V29ybGQsIG1lKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBEZWxldGVzIHRoZSBjdXJyZW50IHJ1biBmcm9tIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIChOb3RlIHRoYXQgdGhlIHdvcmxkIGlkIHJlbWFpbnMgcGFydCBvZiB0aGUgcnVuIHJlY29yZCwgaW5kaWNhdGluZyB0aGF0IHRoZSBydW4gd2FzIGZvcm1lcmx5IGFuIGFjdGl2ZSBydW4gZm9yIHRoZSB3b3JsZC4pXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmRlbGV0ZVJ1bignc2FtcGxlLXdvcmxkLWlkJyk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHdvcmxkSWRgIFRoZSBgd29ybGRJZGAgb2YgdGhlIHdvcmxkIGZyb20gd2hpY2ggdGhlIGN1cnJlbnQgcnVuIGlzIGJlaW5nIGRlbGV0ZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBkZWxldGVSdW46IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZGVsZXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvcnVuJyB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZGVsZXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIG5ldyBydW4gZm9yIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgd2EubmV3UnVuRm9yV29ybGQod29ybGQuaWQpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgd29ybGRJZGAgd29ybGRJZCBpbiB3aGljaCB3ZSBjcmVhdGUgdGhlIG5ldyBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9ucy5tb2RlbGAgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICovXG4gICAgICAgIG5ld1J1bkZvcldvcmxkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGN1cnJlbnRSdW5PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IGZpbHRlcjogd29ybGRJZCB8fCBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgICAgIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IoY3VycmVudFJ1bk9wdGlvbnMpO1xuXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5kZWxldGVSdW4od29ybGRJZCwgb3B0aW9ucylcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5nZXRDdXJyZW50UnVuSWQoY3VycmVudFJ1bk9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEFzc2lnbnMgZW5kIHVzZXJzIHRvIHdvcmxkcywgY3JlYXRpbmcgbmV3IHdvcmxkcyBhcyBhcHByb3ByaWF0ZSwgYXV0b21hdGljYWxseS4gQXNzaWducyBhbGwgZW5kIHVzZXJzIGluIHRoZSBncm91cCwgYW5kIGNyZWF0ZXMgbmV3IHdvcmxkcyBhcyBuZWVkZWQgYmFzZWQgb24gdGhlIHByb2plY3QtbGV2ZWwgd29ybGQgY29uZmlndXJhdGlvbiAocm9sZXMsIG9wdGlvbmFsIHJvbGVzLCBhbmQgbWluaW11bSBlbmQgdXNlcnMgcGVyIHdvcmxkKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5hdXRvQXNzaWduKCk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBhdXRvQXNzaWduOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhc3NpZ25tZW50RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBwYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgYWNjb3VudDogb3B0LmFjY291bnQsXG4gICAgICAgICAgICAgICAgcHJvamVjdDogb3B0LnByb2plY3QsXG4gICAgICAgICAgICAgICAgZ3JvdXA6IG9wdC5ncm91cFxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKG9wdC5tYXhVc2Vycykge1xuICAgICAgICAgICAgICAgIHBhcmFtcy5tYXhVc2VycyA9IG9wdC5tYXhVc2VycztcbiAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgb3B0KTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIHRoZSBwcm9qZWN0J3Mgd29ybGQgY29uZmlndXJhdGlvbi5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgZXZlcnkgaW50ZXJhY3Rpb24gd2l0aCB5b3VyIHByb2plY3QgdXNlcyB0aGUgc2FtZSBjb25maWd1cmF0aW9uIG9mIGVhY2ggd29ybGQuIEZvciBleGFtcGxlLCBlYWNoIHdvcmxkIGluIHlvdXIgcHJvamVjdCBwcm9iYWJseSBoYXMgdGhlIHNhbWUgcm9sZXMgZm9yIGVuZCB1c2Vycy4gQW5kIHlvdXIgcHJvamVjdCBpcyBwcm9iYWJseSBlaXRoZXIgY29uZmlndXJlZCBzbyB0aGF0IGFsbCBlbmQgdXNlcnMgc2hhcmUgdGhlIHNhbWUgd29ybGQgKGFuZCBydW4pLCBvciBzbWFsbGVyIHNldHMgb2YgZW5kIHVzZXJzIHNoYXJlIHdvcmxkcyDigJQgYnV0IG5vdCBib3RoLlxuICAgICAgICAqXG4gICAgICAgICogKFRoZSBbTXVsdGlwbGF5ZXIgUHJvamVjdCBSRVNUIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL211bHRpcGxheWVyX3Byb2plY3QvKSBhbGxvd3MgeW91IHRvIHNldCB0aGVzZSBwcm9qZWN0LWxldmVsIHdvcmxkIGNvbmZpZ3VyYXRpb25zLiBUaGUgV29ybGQgQWRhcHRlciBzaW1wbHkgcmV0cmlldmVzIHRoZW0sIGZvciBleGFtcGxlIHNvIHRoZXkgY2FuIGJlIHVzZWQgaW4gYXV0by1hc3NpZ25tZW50IG9mIGVuZCB1c2VycyB0byB3b3JsZHMuKVxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmdldFByb2plY3RTZXR0aW5ncygpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHNldHRpbmdzKSB7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5yb2xlcyk7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5vcHRpb25hbFJvbGVzKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0UHJvamVjdFNldHRpbmdzOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChwcm9qZWN0RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIG9wdC51cmwgKz0gW29wdC5hY2NvdW50LCBvcHQucHJvamVjdF0uam9pbignLycpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQobnVsbCwgb3B0KTtcbiAgICAgICAgfVxuXG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKiBAY2xhc3MgQ29va2llIFN0b3JhZ2UgU2VydmljZVxuICpcbiAqIEBleGFtcGxlXG4gKiAgICAgIHZhciBwZW9wbGUgPSByZXF1aXJlKCdjb29raWUtc3RvcmUnKSh7IHJvb3Q6ICdwZW9wbGUnIH0pO1xuICAgICAgICBwZW9wbGVcbiAgICAgICAgICAgIC5zYXZlKHtsYXN0TmFtZTogJ3NtaXRoJyB9KVxuXG4gKi9cblxuXG4ndXNlIHN0cmljdCc7XG5cbi8vIFRoaW4gZG9jdW1lbnQuY29va2llIHdyYXBwZXIgdG8gYWxsb3cgdW5pdCB0ZXN0aW5nXG52YXIgQ29va2llID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuZ2V0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gZG9jdW1lbnQuY29va2llO1xuICAgIH07XG5cbiAgICB0aGlzLnNldCA9IGZ1bmN0aW9uIChuZXdDb29raWUpIHtcbiAgICAgICAgZG9jdW1lbnQuY29va2llID0gbmV3Q29va2llO1xuICAgIH07XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgaG9zdCA9IHdpbmRvdy5sb2NhdGlvbi5ob3N0bmFtZTtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBOYW1lIG9mIGNvbGxlY3Rpb25cbiAgICAgICAgICogQHR5cGUgeyBzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICByb290OiAnLycsXG5cbiAgICAgICAgZG9tYWluOiAnLicgKyBob3N0LFxuICAgICAgICBjb29raWU6IG5ldyBDb29raWUoKVxuICAgIH07XG4gICAgdGhpcy5zZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG4gICAgICAgIC8vICogVEJEXG4gICAgICAgIC8vICAqIFF1ZXJ5IGNvbGxlY3Rpb247IHVzZXMgTW9uZ29EQiBzeW50YXhcbiAgICAgICAgLy8gICogQHNlZSAgPFRCRDogRGF0YSBBUEkgVVJMPlxuICAgICAgICAvLyAgKlxuICAgICAgICAvLyAgKiBAcGFyYW0geyBzdHJpbmd9IHFzIFF1ZXJ5IEZpbHRlclxuICAgICAgICAvLyAgKiBAcGFyYW0geyBzdHJpbmd9IGxpbWl0ZXJzIEBzZWUgPFRCRDogdXJsIGZvciBsaW1pdHMsIHBhZ2luZyBldGM+XG4gICAgICAgIC8vICAqXG4gICAgICAgIC8vICAqIEBleGFtcGxlXG4gICAgICAgIC8vICAqICAgICBjcy5xdWVyeShcbiAgICAgICAgLy8gICogICAgICB7IG5hbWU6ICdKb2huJywgY2xhc3NOYW1lOiAnQ1NDMTAxJyB9LFxuICAgICAgICAvLyAgKiAgICAgIHtsaW1pdDogMTB9XG4gICAgICAgIC8vICAqICAgICApXG5cbiAgICAgICAgLy8gcXVlcnk6IGZ1bmN0aW9uIChxcywgbGltaXRlcnMpIHtcblxuICAgICAgICAvLyB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGNvb2tpZSB2YWx1ZVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5ICAgSWYgZ2l2ZW4gYSBrZXkgc2F2ZSB2YWx1ZXMgdW5kZXIgaXQsIGlmIGdpdmVuIGFuIG9iamVjdCBkaXJlY3RseSwgc2F2ZSB0byB0b3AtbGV2ZWwgYXBpXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gdmFsdWUgKE9wdGlvbmFsKVxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBPdmVycmlkZXMgZm9yIHNlcnZpY2Ugb3B0aW9uc1xuICAgICAgICAgKlxuICAgICAgICAgKiBAcmV0dXJuIHsqfSBUaGUgc2F2ZWQgdmFsdWVcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLnNldCgncGVyc29uJywgeyBmaXJzdE5hbWU6ICdqb2huJywgbGFzdE5hbWU6ICdzbWl0aCcgfSk7XG4gICAgICAgICAqICAgICBjcy5zZXQoeyBuYW1lOidzbWl0aCcsIGFnZTonMzInIH0pO1xuICAgICAgICAgKi9cbiAgICAgICAgc2V0OiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHNldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdGhpcy5zZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBkb21haW4gPSBzZXRPcHRpb25zLmRvbWFpbjtcbiAgICAgICAgICAgIHZhciBwYXRoID0gc2V0T3B0aW9ucy5yb290O1xuICAgICAgICAgICAgdmFyIGNvb2tpZSA9IHNldE9wdGlvbnMuY29va2llO1xuXG4gICAgICAgICAgICBjb29raWUuc2V0KGVuY29kZVVSSUNvbXBvbmVudChrZXkpICsgJz0nICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5jb2RlVVJJQ29tcG9uZW50KHZhbHVlKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChkb21haW4gPyAnOyBkb21haW49JyArIGRvbWFpbiA6ICcnKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChwYXRoID8gJzsgcGF0aD0nICsgcGF0aCA6ICcnKVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2FkIGNvb2tpZSB2YWx1ZVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5ICAgSWYgZ2l2ZW4gYSBrZXkgc2F2ZSB2YWx1ZXMgdW5kZXIgaXQsIGlmIGdpdmVuIGFuIG9iamVjdCBkaXJlY3RseSwgc2F2ZSB0byB0b3AtbGV2ZWwgYXBpXG4gICAgICAgICAqIEByZXR1cm4geyp9IFRoZSB2YWx1ZSBzdG9yZWRcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLmdldCgncGVyc29uJyk7XG4gICAgICAgICAqL1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgIHZhciBjb29raWUgPSB0aGlzLnNlcnZpY2VPcHRpb25zLmNvb2tpZTtcbiAgICAgICAgICAgIHZhciBjb29raWVSZWcgPSBuZXcgUmVnRXhwKCcoPzpefDspXFxcXHMqJyArIGVuY29kZVVSSUNvbXBvbmVudChrZXkpLnJlcGxhY2UoL1tcXC1cXC5cXCtcXCpdL2csICdcXFxcJCYnKSArICdcXFxccypcXFxcPVxcXFxzKihbXjtdKikuKiQnKTtcbiAgICAgICAgICAgIHZhciByZXMgPSBjb29raWVSZWcuZXhlYyhjb29raWUuZ2V0KCkpO1xuICAgICAgICAgICAgdmFyIHZhbCA9IHJlcyA/IGRlY29kZVVSSUNvbXBvbmVudChyZXNbMV0pIDogbnVsbDtcbiAgICAgICAgICAgIHJldHVybiB2YWw7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMga2V5IGZyb20gY29sbGVjdGlvblxuICAgICAgICAgKiBAcGFyYW0geyBzdHJpbmd9IGtleSBrZXkgdG8gcmVtb3ZlXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9IGtleSBUaGUga2V5IHJlbW92ZWRcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLnJlbW92ZSgncGVyc29uJyk7XG4gICAgICAgICAqL1xuICAgICAgICByZW1vdmU6IGZ1bmN0aW9uIChrZXksIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciByZW1PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMuc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZG9tYWluID0gcmVtT3B0aW9ucy5kb21haW47XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHJlbU9wdGlvbnMucm9vdDtcbiAgICAgICAgICAgIHZhciBjb29raWUgPSByZW1PcHRpb25zLmNvb2tpZTtcblxuICAgICAgICAgICAgY29va2llLnNldChlbmNvZGVVUklDb21wb25lbnQoa2V5KSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJz07IGV4cGlyZXM9VGh1LCAwMSBKYW4gMTk3MCAwMDowMDowMCBHTVQnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZG9tYWluID8gJzsgZG9tYWluPScgKyBkb21haW4gOiAnJykgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChwYXRoID8gJzsgcGF0aD0nICsgcGF0aCA6ICcnKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybiBrZXk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMgY29sbGVjdGlvbiBiZWluZyByZWZlcmVuY2VkXG4gICAgICAgICAqIEByZXR1cm4geyBhcnJheX0ga2V5cyBBbGwgdGhlIGtleXMgcmVtb3ZlZFxuICAgICAgICAgKi9cbiAgICAgICAgZGVzdHJveTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGNvb2tpZSA9IHRoaXMuc2VydmljZU9wdGlvbnMuY29va2llO1xuICAgICAgICAgICAgdmFyIGFLZXlzID0gY29va2llLmdldCgpLnJlcGxhY2UoLygoPzpefFxccyo7KVteXFw9XSspKD89O3wkKXxeXFxzKnxcXHMqKD86XFw9W147XSopPyg/OlxcMXwkKS9nLCAnJykuc3BsaXQoL1xccyooPzpcXD1bXjtdKik/O1xccyovKTtcbiAgICAgICAgICAgIGZvciAodmFyIG5JZHggPSAwOyBuSWR4IDwgYUtleXMubGVuZ3RoOyBuSWR4KyspIHtcbiAgICAgICAgICAgICAgICB2YXIgY29va2llS2V5ID0gZGVjb2RlVVJJQ29tcG9uZW50KGFLZXlzW25JZHhdKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbW92ZShjb29raWVLZXkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGFLZXlzO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuLi9tYW5hZ2Vycy9rZXktbmFtZXMnKTtcbnZhciBTdG9yYWdlRmFjdG9yeSA9IHJlcXVpcmUoJy4vc3RvcmUtZmFjdG9yeScpO1xudmFyIG9wdGlvblV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbC9vcHRpb24tdXRpbHMnKTtcblxudmFyIEVQSV9TRVNTSU9OX0tFWSA9IGtleU5hbWVzLkVQSV9TRVNTSU9OX0tFWTtcbnZhciBkZWZhdWx0cyA9IHtcbiAgICAvKipcbiAgICAgKiBXaGVyZSB0byBzdG9yZSB1c2VyIGFjY2VzcyB0b2tlbnMgZm9yIHRlbXBvcmFyeSBhY2Nlc3MuIERlZmF1bHRzIHRvIHN0b3JpbmcgaW4gYSBjb29raWUgaW4gdGhlIGJyb3dzZXIuXG4gICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgKi9cbiAgICBzdG9yZTogeyBzeW5jaHJvbm91czogdHJ1ZSB9XG59O1xuXG52YXIgU2Vzc2lvbk1hbmFnZXIgPSBmdW5jdGlvbiAobWFuYWdlck9wdGlvbnMpIHtcbiAgICBtYW5hZ2VyT3B0aW9ucyA9IG1hbmFnZXJPcHRpb25zIHx8IHt9O1xuICAgIGZ1bmN0aW9uIGdldEJhc2VPcHRpb25zKG92ZXJyaWRlcykge1xuICAgICAgICBvdmVycmlkZXMgPSBvdmVycmlkZXMgfHwge307XG4gICAgICAgIHZhciBsaWJPcHRpb25zID0gb3B0aW9uVXRpbHMuZ2V0T3B0aW9ucygpO1xuICAgICAgICB2YXIgZmluYWxPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBsaWJPcHRpb25zLCBtYW5hZ2VyT3B0aW9ucywgb3ZlcnJpZGVzKTtcbiAgICAgICAgcmV0dXJuIGZpbmFsT3B0aW9ucztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBnZXRTdG9yZShvdmVycmlkZXMpIHtcbiAgICAgICAgdmFyIGJhc2VPcHRpb25zID0gZ2V0QmFzZU9wdGlvbnMob3ZlcnJpZGVzKTtcbiAgICAgICAgdmFyIHN0b3JlT3B0cyA9IGJhc2VPcHRpb25zLnN0b3JlIHx8IHt9O1xuICAgICAgICBpZiAoc3RvcmVPcHRzLnJvb3QgPT09IHVuZGVmaW5lZCAmJiBiYXNlT3B0aW9ucy5hY2NvdW50ICYmIGJhc2VPcHRpb25zLnByb2plY3QgJiYgIWJhc2VPcHRpb25zLmlzTG9jYWwpIHtcbiAgICAgICAgICAgIHN0b3JlT3B0cy5yb290ID0gJy9hcHAvJyArIGJhc2VPcHRpb25zLmFjY291bnQgKyAnLycgKyBiYXNlT3B0aW9ucy5wcm9qZWN0O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBuZXcgU3RvcmFnZUZhY3Rvcnkoc3RvcmVPcHRzKTtcbiAgICB9XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICBzYXZlU2Vzc2lvbjogZnVuY3Rpb24gKHVzZXJJbmZvLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgc2VyaWFsaXplZCA9IEpTT04uc3RyaW5naWZ5KHVzZXJJbmZvKTtcbiAgICAgICAgICAgIGdldFN0b3JlKG9wdGlvbnMpLnNldChFUElfU0VTU0lPTl9LRVksIHNlcmlhbGl6ZWQpO1xuICAgICAgICB9LFxuICAgICAgICBnZXRTZXNzaW9uOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgLy8gdmFyIHNlc3Npb24gPSBnZXRTdG9yZShvcHRpb25zKS5nZXQoRVBJX1NFU1NJT05fS0VZKSB8fCAne30nO1xuICAgICAgICAgICAgLy8gcmV0dXJuIEpTT04ucGFyc2Uoc2Vzc2lvbik7XG4gICAgICAgICAgICB2YXIgc3RvcmUgPSBnZXRTdG9yZShvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBmaW5hbE9wdHMgPSBzdG9yZS5zZXJ2aWNlT3B0aW9ucztcbiAgICAgICAgICAgIHZhciBzZXJpYWxpemVkID0gc3RvcmUuZ2V0KEVQSV9TRVNTSU9OX0tFWSkgfHwgJ3t9JztcbiAgICAgICAgICAgIHZhciBzZXNzaW9uID0gSlNPTi5wYXJzZShzZXJpYWxpemVkKTtcbiAgICAgICAgICAgIC8vIElmIHRoZSB1cmwgY29udGFpbnMgdGhlIHByb2plY3QgYW5kIGFjY291bnRcbiAgICAgICAgICAgIC8vIHZhbGlkYXRlIHRoZSBhY2NvdW50IGFuZCBwcm9qZWN0IGluIHRoZSBzZXNzaW9uXG4gICAgICAgICAgICAvLyBhbmQgb3ZlcnJpZGUgcHJvamVjdCwgZ3JvdXBOYW1lLCBncm91cElkIGFuZCBpc0ZhY1xuICAgICAgICAgICAgLy8gT3RoZXJ3aXNlIChpLmUuIGxvY2FsaG9zdCkgdXNlIHRoZSBzYXZlZCBzZXNzaW9uIHZhbHVlc1xuICAgICAgICAgICAgdmFyIGFjY291bnQgPSBmaW5hbE9wdHMuYWNjb3VudDtcbiAgICAgICAgICAgIHZhciBwcm9qZWN0ID0gZmluYWxPcHRzLnByb2plY3Q7XG4gICAgICAgICAgICBpZiAoYWNjb3VudCAmJiBzZXNzaW9uLmFjY291bnQgIT09IGFjY291bnQpIHtcbiAgICAgICAgICAgICAgICAvLyBUaGlzIG1lYW5zIHRoYXQgdGhlIHRva2VuIHdhcyBub3QgdXNlZCB0byBsb2dpbiB0byB0aGUgc2FtZSBhY2NvdW50XG4gICAgICAgICAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHNlc3Npb24uZ3JvdXBzICYmIGFjY291bnQgJiYgcHJvamVjdCkge1xuICAgICAgICAgICAgICAgIHZhciBncm91cCA9IHNlc3Npb24uZ3JvdXBzW3Byb2plY3RdIHx8IHsgZ3JvdXBJZDogJycsIGdyb3VwTmFtZTogJycsIGlzRmFjOiBmYWxzZSB9O1xuICAgICAgICAgICAgICAgICQuZXh0ZW5kKHNlc3Npb24sIHsgcHJvamVjdDogcHJvamVjdCB9LCBncm91cCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gc2Vzc2lvbjtcbiAgICAgICAgfSxcbiAgICAgICAgcmVtb3ZlU2Vzc2lvbjogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBnZXRTdG9yZShvcHRpb25zKS5yZW1vdmUoRVBJX1NFU1NJT05fS0VZKTtcbiAgICAgICAgfSxcbiAgICAgICAgZ2V0U3RvcmU6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gZ2V0U3RvcmUob3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgZ2V0TWVyZ2VkT3B0aW9uczogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuICAgICAgICAgICAgdmFyIG92ZXJyaWRlcyA9ICQuZXh0ZW5kLmFwcGx5KCQsIFt0cnVlLCB7fV0uY29uY2F0KGFyZ3MpKTtcbiAgICAgICAgICAgIHZhciBiYXNlT3B0aW9ucyA9IGdldEJhc2VPcHRpb25zKG92ZXJyaWRlcyk7XG4gICAgICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuZ2V0U2Vzc2lvbihvdmVycmlkZXMpO1xuXG4gICAgICAgICAgICB2YXIgc2Vzc2lvbkRlZmF1bHRzID0ge1xuICAgICAgICAgICAgICAgIC8qKlxuICAgICAgICAgICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgICAgICAgICAqIEBzZWUgW0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXSguLi9hdXRoLWFwaS1zZXJ2aWNlLykgZm9yIGdldHRpbmcgdG9rZW5zLlxuICAgICAgICAgICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAgICAgICAgICovXG4gICAgICAgICAgICAgICAgLy9qc2hpbnQgY2FtZWxjYXNlOiBmYWxzZVxuICAgICAgICAgICAgICAgIC8vanNjczpkaXNhYmxlXG4gICAgICAgICAgICAgICAgdG9rZW46IHNlc3Npb24uYXV0aF90b2tlbixcbiAgICAgICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAgICAgKiBUaGUgZ3JvdXAgbmFtZS4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIGNvb2tpZSBzZXNzaW9uLlxuICAgICAgICAgICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAgICAgICAgICovXG4gICAgICAgICAgICAgICAgZ3JvdXA6IHNlc3Npb24uZ3JvdXBOYW1lLFxuICAgICAgICAgICAgICAgIC8qKlxuICAgICAgICAgICAgICAgICAqIFRoZSBncm91cCBpZC4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIGNvb2tpZSBzZXNzaW9uLlxuICAgICAgICAgICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAgICAgICAgICovXG4gICAgICAgICAgICAgICAgZ3JvdXBJZDogc2Vzc2lvbi5ncm91cElkLFxuICAgICAgICAgICAgICAgIHVzZXJJZDogc2Vzc2lvbi51c2VySWRcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwgc2Vzc2lvbkRlZmF1bHRzLCBiYXNlT3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFNlc3Npb25NYW5hZ2VyOyIsIi8qKlxuICAgIERlY2lkZXMgdHlwZSBvZiBzdG9yZSB0byBwcm92aWRlXG4qL1xuXG4ndXNlIHN0cmljdCc7XG4vLyB2YXIgaXNOb2RlID0gZmFsc2U7IEZJWE1FOiBCcm93c2VyaWZ5L21pbmlmeWlmeSBoYXMgaXNzdWVzIHdpdGggdGhlIG5leHQgbGlua1xuLy8gdmFyIHN0b3JlID0gKGlzTm9kZSkgPyByZXF1aXJlKCcuL3Nlc3Npb24tc3RvcmUnKSA6IHJlcXVpcmUoJy4vY29va2llLXN0b3JlJyk7XG52YXIgc3RvcmUgPSByZXF1aXJlKCcuL2Nvb2tpZS1zdG9yZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHN0b3JlO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgcXV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICB1cmw6ICcnLFxuXG4gICAgICAgIGNvbnRlbnRUeXBlOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICAgIGhlYWRlcnM6IHt9LFxuICAgICAgICBzdGF0dXNDb2RlOiB7XG4gICAgICAgICAgICA0MDQ6ICQubm9vcFxuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPTkxZIGZvciBzdHJpbmdzIGluIHRoZSB1cmwuIEFsbCBHRVQgJiBERUxFVEUgcGFyYW1zIGFyZSBydW4gdGhyb3VnaCB0aGlzXG4gICAgICAgICAqIEB0eXBlIHtbdHlwZV0gfVxuICAgICAgICAgKi9cbiAgICAgICAgcGFyYW1ldGVyUGFyc2VyOiBxdXRpbHMudG9RdWVyeUZvcm1hdCxcblxuICAgICAgICAvLyBUbyBhbGxvdyBlcGljZW50ZXIudG9rZW4gYW5kIG90aGVyIHNlc3Npb24gY29va2llcyB0byBiZSBwYXNzZWRcbiAgICAgICAgLy8gd2l0aCB0aGUgcmVxdWVzdHNcbiAgICAgICAgeGhyRmllbGRzOiB7XG4gICAgICAgICAgICB3aXRoQ3JlZGVudGlhbHM6IHRydWVcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciByZXN1bHQgPSBmdW5jdGlvbiAoZCkge1xuICAgICAgICByZXR1cm4gKCQuaXNGdW5jdGlvbihkKSkgPyBkKCkgOiBkO1xuICAgIH07XG5cbiAgICB2YXIgY29ubmVjdCA9IGZ1bmN0aW9uIChtZXRob2QsIHBhcmFtcywgY29ubmVjdE9wdGlvbnMpIHtcbiAgICAgICAgcGFyYW1zID0gcmVzdWx0KHBhcmFtcyk7XG4gICAgICAgIHBhcmFtcyA9ICgkLmlzUGxhaW5PYmplY3QocGFyYW1zKSB8fCAkLmlzQXJyYXkocGFyYW1zKSkgPyBKU09OLnN0cmluZ2lmeShwYXJhbXMpIDogcGFyYW1zO1xuXG4gICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHRyYW5zcG9ydE9wdGlvbnMsIGNvbm5lY3RPcHRpb25zLCB7XG4gICAgICAgICAgICB0eXBlOiBtZXRob2QsXG4gICAgICAgICAgICBkYXRhOiBwYXJhbXNcbiAgICAgICAgfSk7XG4gICAgICAgIHZhciBBTExPV0VEX1RPX0JFX0ZVTkNUSU9OUyA9IFsnZGF0YScsICd1cmwnXTtcbiAgICAgICAgJC5lYWNoKG9wdGlvbnMsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICBpZiAoJC5pc0Z1bmN0aW9uKHZhbHVlKSAmJiAkLmluQXJyYXkoa2V5LCBBTExPV0VEX1RPX0JFX0ZVTkNUSU9OUykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9uc1trZXldID0gdmFsdWUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKG9wdGlvbnMubG9nTGV2ZWwgJiYgb3B0aW9ucy5sb2dMZXZlbCA9PT0gJ0RFQlVHJykge1xuICAgICAgICAgICAgY29uc29sZS5sb2cob3B0aW9ucy51cmwpO1xuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3NGbiA9IG9wdGlvbnMuc3VjY2VzcyB8fCAkLm5vb3A7XG4gICAgICAgICAgICBvcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UsIGFqYXhTdGF0dXMsIGFqYXhSZXEpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhyZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgb2xkU3VjY2Vzc0ZuLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGJlZm9yZVNlbmQgPSBvcHRpb25zLmJlZm9yZVNlbmQ7XG4gICAgICAgIG9wdGlvbnMuYmVmb3JlU2VuZCA9IGZ1bmN0aW9uICh4aHIsIHNldHRpbmdzKSB7XG4gICAgICAgICAgICB4aHIucmVxdWVzdFVybCA9IChjb25uZWN0T3B0aW9ucyB8fCB7fSkudXJsO1xuICAgICAgICAgICAgaWYgKGJlZm9yZVNlbmQpIHtcbiAgICAgICAgICAgICAgICBiZWZvcmVTZW5kLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuICQuYWpheChvcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgZ2V0OmZ1bmN0aW9uIChwYXJhbXMsIGFqYXhPcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCB0cmFuc3BvcnRPcHRpb25zLCBhamF4T3B0aW9ucyk7XG4gICAgICAgICAgICBwYXJhbXMgPSBvcHRpb25zLnBhcmFtZXRlclBhcnNlcihyZXN1bHQocGFyYW1zKSk7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5jYWxsKHRoaXMsICdHRVQnLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuICAgICAgICBzcGxpdEdldDogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgIH0sXG4gICAgICAgIHBvc3Q6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncG9zdCddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfSxcbiAgICAgICAgcGF0Y2g6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncGF0Y2gnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIHB1dDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydwdXQnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKHBhcmFtcywgYWpheE9wdGlvbnMpIHtcbiAgICAgICAgICAgIC8vREVMRVRFIGRvZXNuJ3Qgc3VwcG9ydCBib2R5IHBhcmFtcywgYnV0IGpRdWVyeSB0aGlua3MgaXQgZG9lcy5cbiAgICAgICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQoe30sIHRyYW5zcG9ydE9wdGlvbnMsIGFqYXhPcHRpb25zKTtcbiAgICAgICAgICAgIHBhcmFtcyA9IG9wdGlvbnMucGFyYW1ldGVyUGFyc2VyKHJlc3VsdChwYXJhbXMpKTtcbiAgICAgICAgICAgIGlmICgkLnRyaW0ocGFyYW1zKSkge1xuICAgICAgICAgICAgICAgIHZhciBkZWxpbWl0ZXIgPSAocmVzdWx0KG9wdGlvbnMudXJsKS5pbmRleE9mKCc/JykgPT09IC0xKSA/ICc/JyA6ICcmJztcbiAgICAgICAgICAgICAgICBvcHRpb25zLnVybCA9IHJlc3VsdChvcHRpb25zLnVybCkgKyBkZWxpbWl0ZXIgKyBwYXJhbXM7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5jYWxsKHRoaXMsICdERUxFVEUnLCBudWxsLCBvcHRpb25zKTtcbiAgICAgICAgfSxcbiAgICAgICAgaGVhZDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydoZWFkJ10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9LFxuICAgICAgICBvcHRpb25zOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ29wdGlvbnMnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcmV0dXJuICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyB2YXIgaXNOb2RlID0gZmFsc2U7IEZJWE1FOiBCcm93c2VyaWZ5L21pbmlmeWlmeSBoYXMgaXNzdWVzIHdpdGggdGhlIG5leHQgbGlua1xuLy8gdmFyIHRyYW5zcG9ydCA9IChpc05vZGUpID8gcmVxdWlyZSgnLi9ub2RlLWh0dHAtdHJhbnNwb3J0JykgOiByZXF1aXJlKCcuL2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcbnZhciB0cmFuc3BvcnQgPSByZXF1aXJlKCcuL2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcbm1vZHVsZS5leHBvcnRzID0gdHJhbnNwb3J0O1xuIiwiLyoqXG4vKiBJbmhlcml0IGZyb20gYSBjbGFzcyAodXNpbmcgcHJvdG90eXBlIGJvcnJvd2luZylcbiovXG4ndXNlIHN0cmljdCc7XG5cbmZ1bmN0aW9uIGluaGVyaXQoQywgUCkge1xuICAgIHZhciBGID0gZnVuY3Rpb24gKCkge307XG4gICAgRi5wcm90b3R5cGUgPSBQLnByb3RvdHlwZTtcbiAgICBDLnByb3RvdHlwZSA9IG5ldyBGKCk7XG4gICAgQy5fX3N1cGVyID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDO1xufVxuXG4vKipcbiogU2hhbGxvdyBjb3B5IG9mIGFuIG9iamVjdFxuKi9cbnZhciBleHRlbmQgPSBmdW5jdGlvbiAoZGVzdCAvKiwgdmFyX2FyZ3MqLykge1xuICAgIHZhciBvYmogPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgIHZhciBjdXJyZW50O1xuICAgIGZvciAodmFyIGogPSAwOyBqPG9iai5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAoIShjdXJyZW50ID0gb2JqW2pdKSkge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkbyBub3Qgd3JhcCBpbm5lciBpbiBkZXN0Lmhhc093blByb3BlcnR5IG9yIGJhZCB0aGluZ3Mgd2lsbCBoYXBwZW5cbiAgICAgICAgLypqc2hpbnQgLVcwODkgKi9cbiAgICAgICAgZm9yICh2YXIga2V5IGluIGN1cnJlbnQpIHtcbiAgICAgICAgICAgIGRlc3Rba2V5XSA9IGN1cnJlbnRba2V5XTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBkZXN0O1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoYmFzZSwgcHJvcHMsIHN0YXRpY1Byb3BzKSB7XG4gICAgdmFyIHBhcmVudCA9IGJhc2U7XG4gICAgdmFyIGNoaWxkO1xuXG4gICAgY2hpbGQgPSBwcm9wcyAmJiBwcm9wcy5oYXNPd25Qcm9wZXJ0eSgnY29uc3RydWN0b3InKSA/IHByb3BzLmNvbnN0cnVjdG9yIDogZnVuY3Rpb24gKCkgeyByZXR1cm4gcGFyZW50LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7IH07XG5cbiAgICAvLyBhZGQgc3RhdGljIHByb3BlcnRpZXMgdG8gdGhlIGNoaWxkIGNvbnN0cnVjdG9yIGZ1bmN0aW9uXG4gICAgZXh0ZW5kKGNoaWxkLCBwYXJlbnQsIHN0YXRpY1Byb3BzKTtcblxuICAgIC8vIGFzc29jaWF0ZSBwcm90b3R5cGUgY2hhaW5cbiAgICBpbmhlcml0KGNoaWxkLCBwYXJlbnQpO1xuXG4gICAgLy8gYWRkIGluc3RhbmNlIHByb3BlcnRpZXNcbiAgICBpZiAocHJvcHMpIHtcbiAgICAgICAgZXh0ZW5kKGNoaWxkLnByb3RvdHlwZSwgcHJvcHMpO1xuICAgIH1cblxuICAgIC8vIGRvbmVcbiAgICByZXR1cm4gY2hpbGQ7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLypqc2hpbnQgbG9vcGZ1bmM6ZmFsc2UgKi9cblxuZnVuY3Rpb24gX3codmFsKSB7XG4gICAgaWYgKHZhbCAmJiB2YWwudGhlbikge1xuICAgICAgICByZXR1cm4gdmFsO1xuICAgIH1cbiAgICB2YXIgcCA9ICQuRGVmZXJyZWQoKTtcbiAgICBwLnJlc29sdmUodmFsKTtcblxuICAgIHJldHVybiBwLnByb21pc2UoKTtcbn1cblxuZnVuY3Rpb24gc2VxKCkge1xuICAgIHZhciBsaXN0ID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmFwcGx5KGFyZ3VtZW50cyk7XG5cbiAgICBmdW5jdGlvbiBuZXh0KHApIHtcbiAgICAgICAgdmFyIGN1ciA9IGxpc3Quc3BsaWNlKDAsMSlbMF07XG5cbiAgICAgICAgaWYgKCFjdXIpIHtcbiAgICAgICAgICAgIHJldHVybiBwO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIF93KGN1cihwKSkudGhlbihuZXh0KTtcbiAgICB9XG5cbiAgICByZXR1cm4gZnVuY3Rpb24gKHNlZWQpIHtcbiAgICAgICAgcmV0dXJuIG5leHQoc2VlZCkuZmFpbChzZXEuZmFpbCk7XG4gICAgfTtcbn1cblxuZnVuY3Rpb24gTWFrZVNlcShvYmopIHtcbiAgICB2YXIgcmVzID0ge1xuICAgICAgICBfX2NhbGxzOiBbXSxcblxuICAgICAgICBvcmlnaW5hbDogb2JqLFxuXG4gICAgICAgIHRoZW46IGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgICAgdGhpcy5fX2NhbGxzLnB1c2goZm4pO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgc3RhcnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgICAgIC8vIGNsZWFuIHVwXG4gICAgICAgICAgICB0aGlzLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIF90aGlzLl9fY2FsbHMubGVuZ3RoID0gMDtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiBzZXEuYXBwbHkobnVsbCwgdGhpcy5fX2NhbGxzKSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGZhaWw6IGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgICAgc2VxLmZhaWwgPSBmbjtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBmdW5jTWFrZXIgPSBmdW5jdGlvbiAocCwgb2JqKSB7XG4gICAgICAgIHZhciBmbiA9IG9ialtwXS5iaW5kKG9iaik7XG4gICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5hcHBseShhcmd1bWVudHMpO1xuICAgICAgICAgICAgdGhpcy5fX2NhbGxzLnB1c2goRnVuY3Rpb24uYmluZC5hcHBseShmbiwgW251bGxdLmNvbmNhdChhcmdzKSkpO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH07XG4gICAgfTtcblxuICAgIGZvciAodmFyIHByb3AgaW4gb2JqKSB7XG4gICAgICAgIGlmICh0eXBlb2Ygb2JqW3Byb3BdID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICByZXNbcHJvcF0gPSBmdW5jTWFrZXIocHJvcCwgb2JqKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJlc1twcm9wXSA9IG9ialtwcm9wXTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXM7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gTWFrZVNlcTtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgX3BpY2s6IGZ1bmN0aW9uIChvYmosIHByb3BzKSB7XG4gICAgICAgIHZhciByZXMgPSB7fTtcbiAgICAgICAgZm9yICh2YXIgcCBpbiBvYmopIHtcbiAgICAgICAgICAgIGlmIChwcm9wcy5pbmRleE9mKHApICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIHJlc1twXSA9IG9ialtwXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xuXG52YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2UoKS5nZXQoJ3NlcnZlcicpO1xudmFyIGN1c3RvbURlZmF1bHRzID0ge307XG52YXIgbGliRGVmYXVsdHMgPSB7XG4gICAgLyoqXG4gICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAqL1xuICAgIGFjY291bnQ6IHVybENvbmZpZy5hY2NvdW50UGF0aCxcbiAgICAvKipcbiAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICovXG4gICAgcHJvamVjdDogdXJsQ29uZmlnLnByb2plY3RQYXRoLFxuICAgIGlzTG9jYWw6IHVybENvbmZpZy5pc0xvY2FsaG9zdCgpLFxuICAgIHN0b3JlOiB7fVxufTtcblxudmFyIG9wdGlvblV0aWxzID0ge1xuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIGZpbmFsIG9wdGlvbnMgYnkgb3ZlcnJpZGluZyB0aGUgZ2xvYmFsIG9wdGlvbnMgc2V0IHdpdGhcbiAgICAgKiBvcHRpb25VdGlscyNzZXREZWZhdWx0cygpIGFuZCB0aGUgbGliIGRlZmF1bHRzLlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgVGhlIGZpbmFsIG9wdGlvbnMgb2JqZWN0LlxuICAgICAqL1xuICAgIGdldE9wdGlvbnM6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCB7fSwgbGliRGVmYXVsdHMsIGN1c3RvbURlZmF1bHRzLCBvcHRpb25zKTtcbiAgICB9LFxuICAgIC8qKlxuICAgICAqIFNldHMgdGhlIGdsb2JhbCBkZWZhdWx0cyBmb3IgdGhlIG9wdGlvblV0aWxzI2dldE9wdGlvbnMoKSBtZXRob2QuXG4gICAgICogQHBhcmFtIHtvYmplY3R9IGBkZWZhdWx0c2AgVGhlIGRlZmF1bHRzIG9iamVjdC5cbiAgICAgKi9cbiAgICBzZXREZWZhdWx0czogZnVuY3Rpb24gKGRlZmF1bHRzKSB7XG4gICAgICAgIGN1c3RvbURlZmF1bHRzID0gZGVmYXVsdHM7XG4gICAgfVxufTtcbm1vZHVsZS5leHBvcnRzID0gb3B0aW9uVXRpbHM7XG4iLCIvKipcbiAqIFV0aWxpdGllcyBmb3Igd29ya2luZyB3aXRoIHF1ZXJ5IHN0cmluZ3NcbiovXG4ndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gKGZ1bmN0aW9uICgpIHtcblxuICAgIHJldHVybiB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZXJ0cyB0byBtYXRyaXggZm9ybWF0XG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gcXMgT2JqZWN0IHRvIGNvbnZlcnQgdG8gcXVlcnkgc3RyaW5nXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9ICAgIE1hdHJpeC1mb3JtYXQgcXVlcnkgcGFyYW1ldGVyc1xuICAgICAgICAgKi9cbiAgICAgICAgdG9NYXRyaXhGb3JtYXQ6IGZ1bmN0aW9uIChxcykge1xuICAgICAgICAgICAgaWYgKHFzID09PSBudWxsIHx8IHFzID09PSB1bmRlZmluZWQgfHwgcXMgPT09ICcnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICc7JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0eXBlb2YgcXMgPT09ICdzdHJpbmcnIHx8IHFzIGluc3RhbmNlb2YgU3RyaW5nKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHFzO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcmV0dXJuQXJyYXkgPSBbXTtcbiAgICAgICAgICAgIHZhciBPUEVSQVRPUlMgPSBbJzwnLCAnPicsICchJ107XG4gICAgICAgICAgICAkLmVhY2gocXMsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gJ3N0cmluZycgfHwgJC5pbkFycmF5KCQudHJpbSh2YWx1ZSkuY2hhckF0KDApLCBPUEVSQVRPUlMpID09PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9ICc9JyArIHZhbHVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5BcnJheS5wdXNoKGtleSArIHZhbHVlKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICB2YXIgbXRyeCA9ICc7JyArIHJldHVybkFycmF5LmpvaW4oJzsnKTtcbiAgICAgICAgICAgIHJldHVybiBtdHJ4O1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZXJ0cyBzdHJpbmdzL2FycmF5cy9vYmplY3RzIHRvIHR5cGUgJ2E9YiZiPWMnXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8QXJyYXl8T2JqZWN0fSBxc1xuICAgICAgICAgKiBAcmV0dXJuIHsgc3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdG9RdWVyeUZvcm1hdDogZnVuY3Rpb24gKHFzKSB7XG4gICAgICAgICAgICBpZiAocXMgPT09IG51bGwgfHwgcXMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0eXBlb2YgcXMgPT09ICdzdHJpbmcnIHx8IHFzIGluc3RhbmNlb2YgU3RyaW5nKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHFzO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcmV0dXJuQXJyYXkgPSBbXTtcbiAgICAgICAgICAgICQuZWFjaChxcywgZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgICAgICAgICAgICAgICBpZiAoJC5pc0FycmF5KHZhbHVlKSkge1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IHZhbHVlLmpvaW4oJywnKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdCh2YWx1ZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgLy9Nb3N0bHkgZm9yIGRhdGEgYXBpXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gSlNPTi5zdHJpbmdpZnkodmFsdWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5BcnJheS5wdXNoKGtleSArICc9JyArIHZhbHVlKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gcmV0dXJuQXJyYXkuam9pbignJicpO1xuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVydHMgc3RyaW5ncyBvZiB0eXBlICdhPWImYj1jJyB0byB7IGE6YiwgYjpjfVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfSBxc1xuICAgICAgICAgKiBAcmV0dXJuIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBxc1RvT2JqZWN0OiBmdW5jdGlvbiAocXMpIHtcbiAgICAgICAgICAgIGlmIChxcyA9PT0gbnVsbCB8fCBxcyA9PT0gdW5kZWZpbmVkIHx8IHFzID09PSAnJykge1xuICAgICAgICAgICAgICAgIHJldHVybiB7fTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHFzQXJyYXkgPSBxcy5zcGxpdCgnJicpO1xuICAgICAgICAgICAgdmFyIHJldHVybk9iaiA9IHt9O1xuICAgICAgICAgICAgJC5lYWNoKHFzQXJyYXksIGZ1bmN0aW9uIChpbmRleCwgdmFsdWUpIHtcbiAgICAgICAgICAgICAgICB2YXIgcUtleSA9IHZhbHVlLnNwbGl0KCc9JylbMF07XG4gICAgICAgICAgICAgICAgdmFyIHFWYWwgPSB2YWx1ZS5zcGxpdCgnPScpWzFdO1xuXG4gICAgICAgICAgICAgICAgaWYgKHFWYWwuaW5kZXhPZignLCcpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICBxVmFsID0gcVZhbC5zcGxpdCgnLCcpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybk9ialtxS2V5XSA9IHFWYWw7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgcmV0dXJuIHJldHVybk9iajtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTm9ybWFsaXplcyBhbmQgbWVyZ2VzIHN0cmluZ3Mgb2YgdHlwZSAnYT1iJywgeyBiOmN9IHRvIHsgYTpiLCBiOmN9XG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8QXJyYXl8T2JqZWN0fSBxczFcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xBcnJheXxPYmplY3R9IHFzMlxuICAgICAgICAgKiBAcmV0dXJuIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBtZXJnZVFTOiBmdW5jdGlvbiAocXMxLCBxczIpIHtcbiAgICAgICAgICAgIHZhciBvYmoxID0gdGhpcy5xc1RvT2JqZWN0KHRoaXMudG9RdWVyeUZvcm1hdChxczEpKTtcbiAgICAgICAgICAgIHZhciBvYmoyID0gdGhpcy5xc1RvT2JqZWN0KHRoaXMudG9RdWVyeUZvcm1hdChxczIpKTtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCB7fSwgb2JqMSwgb2JqMik7XG4gICAgICAgIH0sXG5cbiAgICAgICAgYWRkVHJhaWxpbmdTbGFzaDogZnVuY3Rpb24gKHVybCkge1xuICAgICAgICAgICAgaWYgKCF1cmwpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJyc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gKHVybC5jaGFyQXQodXJsLmxlbmd0aCAtIDEpID09PSAnLycpID8gdXJsIDogKHVybCArICcvJyk7XG4gICAgICAgIH1cbiAgICB9O1xufSgpKTtcblxuXG5cbiIsIi8qKlxuICogVXRpbGl0aWVzIGZvciB3b3JraW5nIHdpdGggdGhlIHJ1biBzZXJ2aWNlXG4qL1xuJ3VzZSBzdHJpY3QnO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi9xdWVyeS11dGlsJyk7XG52YXIgTUFYX1VSTF9MRU5HVEggPSAyMDQ4O1xuXG5tb2R1bGUuZXhwb3J0cyA9IChmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIHJldHVybnMgb3BlcmF0aW9ucyBvZiB0aGUgZm9ybSBgW1tvcDEsb3AyXSwgW2FyZzEsIGFyZzJdXWBcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fEFycmF5fFN0cmluZ30gYG9wZXJhdGlvbnNgIG9wZXJhdGlvbnMgdG8gcGVyZm9ybVxuICAgICAgICAgKiBAcGFyYW0gIHtBcnJheX0gYGFyZ3NgIGFyZ3VtZW50cyBmb3Igb3BlcmF0aW9uXG4gICAgICAgICAqIEByZXR1cm4ge1N0cmluZ30gICAgTWF0cml4LWZvcm1hdCBxdWVyeSBwYXJhbWV0ZXJzXG4gICAgICAgICAqL1xuICAgICAgICBub3JtYWxpemVPcGVyYXRpb25zOiBmdW5jdGlvbiAob3BlcmF0aW9ucywgYXJncykge1xuICAgICAgICAgICAgaWYgKCFhcmdzKSB7XG4gICAgICAgICAgICAgICAgYXJncyA9IFtdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHJldHVybkxpc3QgPSB7XG4gICAgICAgICAgICAgICAgb3BzOiBbXSxcbiAgICAgICAgICAgICAgICBhcmdzOiBbXVxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIF9jb25jYXQgPSBmdW5jdGlvbiAoYXJyKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIChhcnIgIT09IG51bGwgJiYgYXJyICE9PSB1bmRlZmluZWQpID8gW10uY29uY2F0KGFycikgOiBbXTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIC8veyBhZGQ6IFsxLDJdLCBzdWJ0cmFjdDogWzIsNF0gfVxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVQbGFpbk9iamVjdHMgPSBmdW5jdGlvbiAob3BlcmF0aW9ucywgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIGlmICghcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0ID0geyBvcHM6IFtdLCBhcmdzOiBbXSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAkLmVhY2gob3BlcmF0aW9ucywgZnVuY3Rpb24gKG9wbiwgYXJnKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3Qub3BzLnB1c2gob3BuKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5hcmdzLnB1c2goX2NvbmNhdChhcmcpKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICAvL3sgbmFtZTogJ2FkZCcsIHBhcmFtczogWzFdIH1cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplU3RydWN0dXJlZE9iamVjdHMgPSBmdW5jdGlvbiAob3BlcmF0aW9uLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkxpc3Qub3BzLnB1c2gob3BlcmF0aW9uLm5hbWUpO1xuICAgICAgICAgICAgICAgIHJldHVybkxpc3QuYXJncy5wdXNoKF9jb25jYXQob3BlcmF0aW9uLnBhcmFtcykpO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVPYmplY3QgPSBmdW5jdGlvbiAob3BlcmF0aW9uLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICgob3BlcmF0aW9uLm5hbWUpID8gX25vcm1hbGl6ZVN0cnVjdHVyZWRPYmplY3RzIDogX25vcm1hbGl6ZVBsYWluT2JqZWN0cykob3BlcmF0aW9uLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplTGl0ZXJhbHMgPSBmdW5jdGlvbiAob3BlcmF0aW9uLCBhcmdzLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkxpc3Qub3BzLnB1c2gob3BlcmF0aW9uKTtcbiAgICAgICAgICAgICAgICByZXR1cm5MaXN0LmFyZ3MucHVzaChfY29uY2F0KGFyZ3MpKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgICAgIH07XG5cblxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVBcnJheXMgPSBmdW5jdGlvbiAob3BlcmF0aW9ucywgYXJnLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICQuZWFjaChvcGVyYXRpb25zLCBmdW5jdGlvbiAoaW5kZXgsIG9wbikge1xuICAgICAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KG9wbikpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIF9ub3JtYWxpemVPYmplY3Qob3BuLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIF9ub3JtYWxpemVMaXRlcmFscyhvcG4sIGFyZ3NbaW5kZXhdLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdChvcGVyYXRpb25zKSkge1xuICAgICAgICAgICAgICAgIF9ub3JtYWxpemVPYmplY3Qob3BlcmF0aW9ucywgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCQuaXNBcnJheShvcGVyYXRpb25zKSkge1xuICAgICAgICAgICAgICAgIF9ub3JtYWxpemVBcnJheXMob3BlcmF0aW9ucywgYXJncywgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIF9ub3JtYWxpemVMaXRlcmFscyhvcGVyYXRpb25zLCBhcmdzLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgIH0sXG5cbiAgICAgICAgc3BsaXRHZXRGYWN0b3J5OiBmdW5jdGlvbiAoaHR0cE9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgdmFyIGh0dHAgPSB0aGlzO1xuICAgICAgICAgICAgICAgIHZhciBnZXRWYWx1ZSA9IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciB2YWx1ZSA9IG9wdGlvbnNbbmFtZV0gfHwgaHR0cE9wdGlvbnNbbmFtZV07XG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gdmFsdWUoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB2YXIgZ2V0RmluYWxVcmwgPSBmdW5jdGlvbiAocGFyYW1zKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciB1cmwgPSBnZXRWYWx1ZSgndXJsJywgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBkYXRhID0gcGFyYW1zO1xuICAgICAgICAgICAgICAgICAgICAvLyBUaGVyZSBpcyBlYXN5IChvciBrbm93bikgd2F5IHRvIGdldCB0aGUgZmluYWwgVVJMIGpxdWVyeSBpcyBnb2luZyB0byBzZW5kIHNvXG4gICAgICAgICAgICAgICAgICAgIC8vIHdlJ3JlIHJlcGxpY2F0aW5nIGl0LiBUaGUgcHJvY2VzcyBtaWdodCBjaGFuZ2UgYXQgc29tZSBwb2ludCBidXQgaXQgcHJvYmFibHkgd2lsbCBub3QuXG4gICAgICAgICAgICAgICAgICAgIC8vIDEuIFJlbW92ZSBoYXNoXG4gICAgICAgICAgICAgICAgICAgIHVybCA9IHVybC5yZXBsYWNlKC8jLiokLywgJycpO1xuICAgICAgICAgICAgICAgICAgICAvLyAxLiBBcHBlbmQgcXVlcnkgc3RyaW5nXG4gICAgICAgICAgICAgICAgICAgIHZhciBxdWVyeVBhcmFtcyA9IHF1dGlsLnRvUXVlcnlGb3JtYXQoZGF0YSk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBxdWVzdGlvbklkeCA9IHVybC5pbmRleE9mKCc/Jyk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChxdWVyeVBhcmFtcyAmJiBxdWVzdGlvbklkeCA+IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdXJsICsgJyYnICsgcXVlcnlQYXJhbXM7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAocXVlcnlQYXJhbXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB1cmwgKyAnPycgKyBxdWVyeVBhcmFtcztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdXJsO1xuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdmFyIHVybCA9IGdldEZpbmFsVXJsKHBhcmFtcyk7XG4gICAgICAgICAgICAgICAgLy8gV2UgbXVzdCBzcGxpdCB0aGUgR0VUIGluIG11bHRpcGxlIHNob3J0IFVSTCdzXG4gICAgICAgICAgICAgICAgLy8gVGhlIG9ubHkgcHJvcGVydHkgYWxsb3dlZCB0byBiZSBzcGxpdCBpcyBcImluY2x1ZGVcIlxuICAgICAgICAgICAgICAgIGlmIChwYXJhbXMgJiYgcGFyYW1zLmluY2x1ZGUgJiYgZW5jb2RlVVJJKHVybCkubGVuZ3RoID4gTUFYX1VSTF9MRU5HVEgpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHBhcmFtc0NvcHkgPSAkLmV4dGVuZCh0cnVlLCB7fSwgcGFyYW1zKTtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHBhcmFtc0NvcHkuaW5jbHVkZTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHVybE5vSW5jbHVkZXMgPSBnZXRGaW5hbFVybChwYXJhbXNDb3B5KTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGRpZmYgPSBNQVhfVVJMX0xFTkdUSCAtIHVybE5vSW5jbHVkZXMubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICB2YXIgb2xkU3VjY2VzcyA9IG9wdGlvbnMuc3VjY2VzcyB8fCBodHRwT3B0aW9ucy5zdWNjZXNzIHx8ICQubm9vcDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9sZEVycm9yID0gb3B0aW9ucy5lcnJvciB8fCBodHRwT3B0aW9ucy5lcnJvciB8fCAkLm5vb3A7XG4gICAgICAgICAgICAgICAgICAgIC8vIHJlbW92ZSB0aGUgb3JpZ2luYWwgc3VjY2VzcyBhbmQgZXJyb3IgY2FsbGJhY2tzXG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuc3VjY2VzcyA9ICQubm9vcDtcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5lcnJvciA9ICQubm9vcDtcblxuICAgICAgICAgICAgICAgICAgICB2YXIgaW5jbHVkZSA9IHBhcmFtcy5pbmNsdWRlO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3VyckluY2x1ZGVzID0gW107XG4gICAgICAgICAgICAgICAgICAgIHZhciBpbmNsdWRlT3B0cyA9IFtjdXJySW5jbHVkZXNdO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3Vyckxlbmd0aCA9IGVuY29kZVVSSUNvbXBvbmVudCgnP2luY2x1ZGU9JykubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICB2YXIgdmFyaWFibGUgPSBpbmNsdWRlLnBvcCgpO1xuICAgICAgICAgICAgICAgICAgICB3aGlsZSAodmFyaWFibGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciB2YXJMZW5naHQgPSBlbmNvZGVVUklDb21wb25lbnQodmFyaWFibGUpLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFVzZSBhIGdyZWVkeSBhcHByb2FjaCBmb3Igbm93LCBjYW4gYmUgb3B0aW1pemVkIHRvIGJlIHNvbHZlZCBpbiBhIG1vcmVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGVmZmljaWVudCB3YXlcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICsgMSBpcyB0aGUgY29tbWFcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjdXJyTGVuZ3RoICsgdmFyTGVuZ2h0ICsgMSA8IGRpZmYpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJySW5jbHVkZXMucHVzaCh2YXJpYWJsZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3Vyckxlbmd0aCArPSB2YXJMZW5naHQgKyAxO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJySW5jbHVkZXMgPSBbdmFyaWFibGVdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGVPcHRzLnB1c2goY3VyckluY2x1ZGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyTGVuZ3RoID0gJz9pbmNsdWRlPScubGVuZ3RoICsgdmFyTGVuZ2h0O1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGUgPSBpbmNsdWRlLnBvcCgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHZhciByZXFzID0gJC5tYXAoaW5jbHVkZU9wdHMsIGZ1bmN0aW9uIChpbmNsdWRlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgcmVxUGFyYW1zID0gJC5leHRlbmQoe30sIHBhcmFtcywgeyBpbmNsdWRlOiBpbmNsdWRlIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHJlcVBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAkLndoZW4uYXBwbHkoJCwgcmVxcykudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBFYWNoIGFyZ3VtZW50IGFyZSBhcnJheXMgb2YgdGhlIGFyZ3VtZW50cyBvZiBlYWNoIGRvbmUgcmVxdWVzdFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gU28gdGhlIGZpcnN0IGFyZ3VtZW50IG9mIHRoZSBmaXJzdCBhcnJheSBvZiBhcmd1bWVudHMgaXMgdGhlIGRhdGFcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBpc1ZhbGlkID0gYXJndW1lbnRzWzBdICYmIGFyZ3VtZW50c1swXVswXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghaXNWYWxpZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNob3VsZCBuZXZlciBoYXBwZW4uLi5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRFcnJvcigpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBkdGQucmVqZWN0KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZmlyc3RSZXNwb25zZSA9IGFyZ3VtZW50c1swXVswXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBpc09iamVjdCA9ICQuaXNQbGFpbk9iamVjdChmaXJzdFJlc3BvbnNlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBpc1J1bkFQSSA9IChpc09iamVjdCAmJiAkLmlzUGxhaW5PYmplY3QoZmlyc3RSZXNwb25zZS52YXJpYWJsZXMpKSB8fCAhaXNPYmplY3Q7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNSdW5BUEkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNPYmplY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWdncmVnYXRlIHRoZSB2YXJpYWJsZXMgcHJvcGVydHkgb25seVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgYWdncmVnYXRlUnVuID0gYXJndW1lbnRzWzBdWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2goYXJndW1lbnRzLCBmdW5jdGlvbiAoaWR4LCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcnVuID0gYXJnc1swXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZVJ1bi52YXJpYWJsZXMsIHJ1bi52YXJpYWJsZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkU3VjY2VzcyhhZ2dyZWdhdGVSdW4sIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUoYWdncmVnYXRlUnVuLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYXJyYXkgb2YgcnVuc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBZ3JlZ2F0ZSB2YXJpYWJsZXMgaW4gZWFjaCBydW5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGFnZ3JlZ2F0ZWRSdW5zID0ge307XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChhcmd1bWVudHMsIGZ1bmN0aW9uIChpZHgsIGFyZ3MpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBydW5zID0gYXJnc1swXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghJC5pc0FycmF5KHJ1bnMpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKHJ1bnMsIGZ1bmN0aW9uIChpZHhSdW4sIHJ1bikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChydW4uaWQgJiYgIWFnZ3JlZ2F0ZWRSdW5zW3J1bi5pZF0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnVuLnZhcmlhYmxlcyA9IHJ1bi52YXJpYWJsZXMgfHwge307XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZ3JlZ2F0ZWRSdW5zW3J1bi5pZF0gPSBydW47XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChydW4uaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5leHRlbmQodHJ1ZSwgYWdncmVnYXRlZFJ1bnNbcnVuLmlkXS52YXJpYWJsZXMsIHJ1bi52YXJpYWJsZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdHVybiBpdCBpbnRvIGFuIGFycmF5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZ3JlZ2F0ZWRSdW5zID0gJC5tYXAoYWdncmVnYXRlZFJ1bnMsIGZ1bmN0aW9uIChydW4pIHsgcmV0dXJuIHJ1bjsgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlZFJ1bnMsIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUoYWdncmVnYXRlZFJ1bnMsIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGlzIHZhcmlhYmxlcyBBUElcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhZ2dyZWdhdGUgdGhlIHJlc3BvbnNlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGFnZ3JlZ2F0ZWRWYXJpYWJsZXMgPSB7fTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2goYXJndW1lbnRzLCBmdW5jdGlvbiAoaWR4LCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciB2YXJzID0gYXJnc1swXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5leHRlbmQodHJ1ZSwgYWdncmVnYXRlZFZhcmlhYmxlcywgdmFycyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkU3VjY2VzcyhhZ2dyZWdhdGVkVmFyaWFibGVzLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUoYWdncmVnYXRlZFZhcmlhYmxlcywgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9LCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBvbGRFcnJvci5hcHBseShodHRwLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlamVjdC5hcHBseShkdGQsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQocGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgfTtcbn0oKSk7XG4iXX0= +>>>>>>> dms3-version diff --git a/dist/epicenter.min.js b/dist/epicenter.min.js index 7792fdbc..18f5d5a3 100644 --- a/dist/epicenter.min.js +++ b/dist/epicenter.min.js @@ -2,7 +2,7 @@ "use strict";function init(){var code="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(var i=0,len=code.length;i0)throw new Error("Invalid string. Length must be a multiple of 4");placeHolders="="===b64[len-2]?2:"="===b64[len-1]?1:0,arr=new Arr(3*len/4-placeHolders),l=placeHolders>0?len-4:len;var L=0;for(i=0,j=0;i>16&255,arr[L++]=tmp>>8&255,arr[L++]=255&tmp;return 2===placeHolders?(tmp=revLookup[b64.charCodeAt(i)]<<2|revLookup[b64.charCodeAt(i+1)]>>4,arr[L++]=255&tmp):1===placeHolders&&(tmp=revLookup[b64.charCodeAt(i)]<<10|revLookup[b64.charCodeAt(i+1)]<<4|revLookup[b64.charCodeAt(i+2)]>>2,arr[L++]=tmp>>8&255,arr[L++]=255&tmp),arr}function tripletToBase64(num){return lookup[num>>18&63]+lookup[num>>12&63]+lookup[num>>6&63]+lookup[63&num]}function encodeChunk(uint8,start,end){var tmp;var output=[];for(var i=start;ilen2?len2:i+maxChunkLength));return 1===extraBytes?(tmp=uint8[len-1],output+=lookup[tmp>>2],output+=lookup[tmp<<4&63],output+="=="):2===extraBytes&&(tmp=(uint8[len-2]<<8)+uint8[len-1],output+=lookup[tmp>>10],output+=lookup[tmp>>4&63],output+=lookup[tmp<<2&63],output+="="),parts.push(output),parts.join("")}exports.toByteArray=toByteArray,exports.fromByteArray=fromByteArray;var lookup=[];var revLookup=[];var Arr="undefined"!=typeof Uint8Array?Uint8Array:Array;init(); },{}],2:[function(require,module,exports){ (function (global){ -"use strict";function typedArraySupport(){try{var arr=new Uint8Array(1);return arr.__proto__={__proto__:Uint8Array.prototype,foo:function(){return 42}},42===arr.foo()&&"function"==typeof arr.subarray&&0===arr.subarray(1,1).byteLength}catch(e){return!1}}function kMaxLength(){return Buffer.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function createBuffer(that,length){if(kMaxLength()=kMaxLength())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+kMaxLength().toString(16)+" bytes");return 0|length}function SlowBuffer(length){return+length!=length&&(length=0),Buffer.alloc(+length)}function byteLength(string,encoding){if(Buffer.isBuffer(string))return string.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(string)||string instanceof ArrayBuffer))return string.byteLength;"string"!=typeof string&&(string=""+string);var len=string.length;if(0===len)return 0;var loweredCase=!1;for(;;)switch(encoding){case"ascii":case"binary":case"raw":case"raws":return len;case"utf8":case"utf-8":case void 0:return utf8ToBytes(string).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*len;case"hex":return len>>>1;case"base64":return base64ToBytes(string).length;default:if(loweredCase)return utf8ToBytes(string).length;encoding=(""+encoding).toLowerCase(),loweredCase=!0}}function slowToString(encoding,start,end){var loweredCase=!1;if((void 0===start||start<0)&&(start=0),start>this.length)return"";if((void 0===end||end>this.length)&&(end=this.length),end<=0)return"";if(end>>>=0,start>>>=0,end<=start)return"";for(encoding||(encoding="utf8");;)switch(encoding){case"hex":return hexSlice(this,start,end);case"utf8":case"utf-8":return utf8Slice(this,start,end);case"ascii":return asciiSlice(this,start,end);case"binary":return binarySlice(this,start,end);case"base64":return base64Slice(this,start,end);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return utf16leSlice(this,start,end);default:if(loweredCase)throw new TypeError("Unknown encoding: "+encoding);encoding=(encoding+"").toLowerCase(),loweredCase=!0}}function swap(b,n,m){var i=b[n];b[n]=b[m],b[m]=i}function arrayIndexOf(arr,val,byteOffset,encoding){function read(buf,i){return 1===indexSize?buf[i]:buf.readUInt16BE(i*indexSize)}var indexSize=1;var arrLength=arr.length;var valLength=val.length;if(void 0!==encoding&&(encoding=String(encoding).toLowerCase(),"ucs2"===encoding||"ucs-2"===encoding||"utf16le"===encoding||"utf-16le"===encoding)){if(arr.length<2||val.length<2)return-1;indexSize=2,arrLength/=2,valLength/=2,byteOffset/=2}var foundIndex=-1;for(var i=byteOffset;iremaining&&(length=remaining)):length=remaining;var strLen=string.length;if(strLen%2!==0)throw new Error("Invalid hex string");length>strLen/2&&(length=strLen/2);for(var i=0;i239?4:firstByte>223?3:firstByte>191?2:1;if(i+bytesPerSequence<=end){var secondByte,thirdByte,fourthByte,tempCodePoint;switch(bytesPerSequence){case 1:firstByte<128&&(codePoint=firstByte);break;case 2:secondByte=buf[i+1],128===(192&secondByte)&&(tempCodePoint=(31&firstByte)<<6|63&secondByte,tempCodePoint>127&&(codePoint=tempCodePoint));break;case 3:secondByte=buf[i+1],thirdByte=buf[i+2],128===(192&secondByte)&&128===(192&thirdByte)&&(tempCodePoint=(15&firstByte)<<12|(63&secondByte)<<6|63&thirdByte,tempCodePoint>2047&&(tempCodePoint<55296||tempCodePoint>57343)&&(codePoint=tempCodePoint));break;case 4:secondByte=buf[i+1],thirdByte=buf[i+2],fourthByte=buf[i+3],128===(192&secondByte)&&128===(192&thirdByte)&&128===(192&fourthByte)&&(tempCodePoint=(15&firstByte)<<18|(63&secondByte)<<12|(63&thirdByte)<<6|63&fourthByte,tempCodePoint>65535&&tempCodePoint<1114112&&(codePoint=tempCodePoint))}}null===codePoint?(codePoint=65533,bytesPerSequence=1):codePoint>65535&&(codePoint-=65536,res.push(codePoint>>>10&1023|55296),codePoint=56320|1023&codePoint),res.push(codePoint),i+=bytesPerSequence}return decodeCodePointsArray(res)}function decodeCodePointsArray(codePoints){var len=codePoints.length;if(len<=MAX_ARGUMENTS_LENGTH)return String.fromCharCode.apply(String,codePoints);var res="";var i=0;for(;ilen)&&(end=len);var out="";for(var i=start;ilength)throw new RangeError("Trying to access beyond buffer length")}function checkInt(buf,value,offset,ext,max,min){if(!Buffer.isBuffer(buf))throw new TypeError('"buffer" argument must be a Buffer instance');if(value>max||valuebuf.length)throw new RangeError("Index out of range")}function objectWriteUInt16(buf,value,offset,littleEndian){value<0&&(value=65535+value+1);for(var i=0,j=Math.min(buf.length-offset,2);i>>8*(littleEndian?i:1-i)}function objectWriteUInt32(buf,value,offset,littleEndian){value<0&&(value=4294967295+value+1);for(var i=0,j=Math.min(buf.length-offset,4);i>>8*(littleEndian?i:3-i)&255}function checkIEEE754(buf,value,offset,ext,max,min){if(offset+ext>buf.length)throw new RangeError("Index out of range");if(offset<0)throw new RangeError("Index out of range")}function writeFloat(buf,value,offset,littleEndian,noAssert){return noAssert||checkIEEE754(buf,value,offset,4,3.4028234663852886e38,-3.4028234663852886e38),ieee754.write(buf,value,offset,littleEndian,23,4),offset+4}function writeDouble(buf,value,offset,littleEndian,noAssert){return noAssert||checkIEEE754(buf,value,offset,8,1.7976931348623157e308,-1.7976931348623157e308),ieee754.write(buf,value,offset,littleEndian,52,8),offset+8}function base64clean(str){if(str=stringtrim(str).replace(INVALID_BASE64_RE,""),str.length<2)return"";for(;str.length%4!==0;)str+="=";return str}function stringtrim(str){return str.trim?str.trim():str.replace(/^\s+|\s+$/g,"")}function toHex(n){return n<16?"0"+n.toString(16):n.toString(16)}function utf8ToBytes(string,units){units=units||1/0;var codePoint;var length=string.length;var leadSurrogate=null;var bytes=[];for(var i=0;i55295&&codePoint<57344){if(!leadSurrogate){if(codePoint>56319){(units-=3)>-1&&bytes.push(239,191,189);continue}if(i+1===length){(units-=3)>-1&&bytes.push(239,191,189);continue}leadSurrogate=codePoint;continue}if(codePoint<56320){(units-=3)>-1&&bytes.push(239,191,189),leadSurrogate=codePoint;continue}codePoint=(leadSurrogate-55296<<10|codePoint-56320)+65536}else leadSurrogate&&(units-=3)>-1&&bytes.push(239,191,189);if(leadSurrogate=null,codePoint<128){if((units-=1)<0)break;bytes.push(codePoint)}else if(codePoint<2048){if((units-=2)<0)break;bytes.push(codePoint>>6|192,63&codePoint|128)}else if(codePoint<65536){if((units-=3)<0)break;bytes.push(codePoint>>12|224,codePoint>>6&63|128,63&codePoint|128)}else{if(!(codePoint<1114112))throw new Error("Invalid code point");if((units-=4)<0)break;bytes.push(codePoint>>18|240,codePoint>>12&63|128,codePoint>>6&63|128,63&codePoint|128)}}return bytes}function asciiToBytes(str){var byteArray=[];for(var i=0;i>8,lo=c%256,byteArray.push(lo),byteArray.push(hi);return byteArray}function base64ToBytes(str){return base64.toByteArray(base64clean(str))}function blitBuffer(src,dst,offset,length){for(var i=0;i=dst.length||i>=src.length);++i)dst[i+offset]=src[i];return i}function isnan(val){return val!==val}var base64=require("base64-js");var ieee754=require("ieee754");var isArray=require("isarray");exports.Buffer=Buffer,exports.SlowBuffer=SlowBuffer,exports.INSPECT_MAX_BYTES=50,Buffer.TYPED_ARRAY_SUPPORT=void 0!==global.TYPED_ARRAY_SUPPORT?global.TYPED_ARRAY_SUPPORT:typedArraySupport(),exports.kMaxLength=kMaxLength(),Buffer.poolSize=8192,Buffer._augment=function(arr){return arr.__proto__=Buffer.prototype,arr},Buffer.from=function(value,encodingOrOffset,length){return from(null,value,encodingOrOffset,length)},Buffer.TYPED_ARRAY_SUPPORT&&(Buffer.prototype.__proto__=Uint8Array.prototype,Buffer.__proto__=Uint8Array,"undefined"!=typeof Symbol&&Symbol.species&&Buffer[Symbol.species]===Buffer&&Object.defineProperty(Buffer,Symbol.species,{value:null,configurable:!0})),Buffer.alloc=function(size,fill,encoding){return alloc(null,size,fill,encoding)},Buffer.allocUnsafe=function(size){return allocUnsafe(null,size)},Buffer.allocUnsafeSlow=function(size){return allocUnsafe(null,size)},Buffer.isBuffer=function(b){return!(null==b||!b._isBuffer)},Buffer.compare=function(a,b){if(!Buffer.isBuffer(a)||!Buffer.isBuffer(b))throw new TypeError("Arguments must be Buffers");if(a===b)return 0;var x=a.length;var y=b.length;for(var i=0,len=Math.min(x,y);i0&&(str=this.toString("hex",0,max).match(/.{2}/g).join(" "),this.length>max&&(str+=" ... ")),""},Buffer.prototype.compare=function(target,start,end,thisStart,thisEnd){if(!Buffer.isBuffer(target))throw new TypeError("Argument must be a Buffer");if(void 0===start&&(start=0),void 0===end&&(end=target?target.length:0),void 0===thisStart&&(thisStart=0),void 0===thisEnd&&(thisEnd=this.length),start<0||end>target.length||thisStart<0||thisEnd>this.length)throw new RangeError("out of range index");if(thisStart>=thisEnd&&start>=end)return 0;if(thisStart>=thisEnd)return-1;if(start>=end)return 1;if(start>>>=0,end>>>=0,thisStart>>>=0,thisEnd>>>=0,this===target)return 0;var x=thisEnd-thisStart;var y=end-start;var len=Math.min(x,y);var thisCopy=this.slice(thisStart,thisEnd);var targetCopy=target.slice(start,end);for(var i=0;i2147483647?byteOffset=2147483647:byteOffset<-2147483648&&(byteOffset=-2147483648),byteOffset>>=0,0===this.length)return-1;if(byteOffset>=this.length)return-1;if(byteOffset<0&&(byteOffset=Math.max(this.length+byteOffset,0)),"string"==typeof val&&(val=Buffer.from(val,encoding)),Buffer.isBuffer(val))return 0===val.length?-1:arrayIndexOf(this,val,byteOffset,encoding);if("number"==typeof val)return Buffer.TYPED_ARRAY_SUPPORT&&"function"===Uint8Array.prototype.indexOf?Uint8Array.prototype.indexOf.call(this,val,byteOffset):arrayIndexOf(this,[val],byteOffset,encoding);throw new TypeError("val must be string, number or Buffer")},Buffer.prototype.includes=function(val,byteOffset,encoding){return this.indexOf(val,byteOffset,encoding)!==-1},Buffer.prototype.write=function(string,offset,length,encoding){if(void 0===offset)encoding="utf8",length=this.length,offset=0;else if(void 0===length&&"string"==typeof offset)encoding=offset,length=this.length,offset=0;else{if(!isFinite(offset))throw new Error("Buffer.write(string, encoding, offset[, length]) is no longer supported");offset=0|offset,isFinite(length)?(length=0|length,void 0===encoding&&(encoding="utf8")):(encoding=length,length=void 0)}var remaining=this.length-offset;if((void 0===length||length>remaining)&&(length=remaining),string.length>0&&(length<0||offset<0)||offset>this.length)throw new RangeError("Attempt to write outside buffer bounds");encoding||(encoding="utf8");var loweredCase=!1;for(;;)switch(encoding){case"hex":return hexWrite(this,string,offset,length);case"utf8":case"utf-8":return utf8Write(this,string,offset,length);case"ascii":return asciiWrite(this,string,offset,length);case"binary":return binaryWrite(this,string,offset,length);case"base64":return base64Write(this,string,offset,length);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return ucs2Write(this,string,offset,length);default:if(loweredCase)throw new TypeError("Unknown encoding: "+encoding);encoding=(""+encoding).toLowerCase(),loweredCase=!0}},Buffer.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var MAX_ARGUMENTS_LENGTH=4096;Buffer.prototype.slice=function(start,end){var len=this.length;start=~~start,end=void 0===end?len:~~end,start<0?(start+=len,start<0&&(start=0)):start>len&&(start=len),end<0?(end+=len,end<0&&(end=0)):end>len&&(end=len),end0&&(mul*=256);)val+=this[offset+--byteLength]*mul;return val},Buffer.prototype.readUInt8=function(offset,noAssert){return noAssert||checkOffset(offset,1,this.length),this[offset]},Buffer.prototype.readUInt16LE=function(offset,noAssert){return noAssert||checkOffset(offset,2,this.length),this[offset]|this[offset+1]<<8},Buffer.prototype.readUInt16BE=function(offset,noAssert){return noAssert||checkOffset(offset,2,this.length),this[offset]<<8|this[offset+1]},Buffer.prototype.readUInt32LE=function(offset,noAssert){return noAssert||checkOffset(offset,4,this.length),(this[offset]|this[offset+1]<<8|this[offset+2]<<16)+16777216*this[offset+3]},Buffer.prototype.readUInt32BE=function(offset,noAssert){return noAssert||checkOffset(offset,4,this.length),16777216*this[offset]+(this[offset+1]<<16|this[offset+2]<<8|this[offset+3])},Buffer.prototype.readIntLE=function(offset,byteLength,noAssert){offset=0|offset,byteLength=0|byteLength,noAssert||checkOffset(offset,byteLength,this.length);var val=this[offset];var mul=1;var i=0;for(;++i=mul&&(val-=Math.pow(2,8*byteLength)),val},Buffer.prototype.readIntBE=function(offset,byteLength,noAssert){offset=0|offset,byteLength=0|byteLength,noAssert||checkOffset(offset,byteLength,this.length);var i=byteLength;var mul=1;var val=this[offset+--i];for(;i>0&&(mul*=256);)val+=this[offset+--i]*mul;return mul*=128,val>=mul&&(val-=Math.pow(2,8*byteLength)),val},Buffer.prototype.readInt8=function(offset,noAssert){return noAssert||checkOffset(offset,1,this.length),128&this[offset]?(255-this[offset]+1)*-1:this[offset]},Buffer.prototype.readInt16LE=function(offset,noAssert){noAssert||checkOffset(offset,2,this.length);var val=this[offset]|this[offset+1]<<8;return 32768&val?4294901760|val:val},Buffer.prototype.readInt16BE=function(offset,noAssert){noAssert||checkOffset(offset,2,this.length);var val=this[offset+1]|this[offset]<<8;return 32768&val?4294901760|val:val},Buffer.prototype.readInt32LE=function(offset,noAssert){return noAssert||checkOffset(offset,4,this.length),this[offset]|this[offset+1]<<8|this[offset+2]<<16|this[offset+3]<<24},Buffer.prototype.readInt32BE=function(offset,noAssert){return noAssert||checkOffset(offset,4,this.length),this[offset]<<24|this[offset+1]<<16|this[offset+2]<<8|this[offset+3]},Buffer.prototype.readFloatLE=function(offset,noAssert){return noAssert||checkOffset(offset,4,this.length),ieee754.read(this,offset,!0,23,4)},Buffer.prototype.readFloatBE=function(offset,noAssert){return noAssert||checkOffset(offset,4,this.length),ieee754.read(this,offset,!1,23,4)},Buffer.prototype.readDoubleLE=function(offset,noAssert){return noAssert||checkOffset(offset,8,this.length),ieee754.read(this,offset,!0,52,8)},Buffer.prototype.readDoubleBE=function(offset,noAssert){return noAssert||checkOffset(offset,8,this.length),ieee754.read(this,offset,!1,52,8)},Buffer.prototype.writeUIntLE=function(value,offset,byteLength,noAssert){if(value=+value,offset=0|offset,byteLength=0|byteLength,!noAssert){var maxBytes=Math.pow(2,8*byteLength)-1;checkInt(this,value,offset,byteLength,maxBytes,0)}var mul=1;var i=0;for(this[offset]=255&value;++i=0&&(mul*=256);)this[offset+i]=value/mul&255;return offset+byteLength},Buffer.prototype.writeUInt8=function(value,offset,noAssert){return value=+value,offset=0|offset,noAssert||checkInt(this,value,offset,1,255,0),Buffer.TYPED_ARRAY_SUPPORT||(value=Math.floor(value)),this[offset]=255&value,offset+1},Buffer.prototype.writeUInt16LE=function(value,offset,noAssert){return value=+value,offset=0|offset,noAssert||checkInt(this,value,offset,2,65535,0),Buffer.TYPED_ARRAY_SUPPORT?(this[offset]=255&value,this[offset+1]=value>>>8):objectWriteUInt16(this,value,offset,!0),offset+2},Buffer.prototype.writeUInt16BE=function(value,offset,noAssert){return value=+value,offset=0|offset,noAssert||checkInt(this,value,offset,2,65535,0),Buffer.TYPED_ARRAY_SUPPORT?(this[offset]=value>>>8,this[offset+1]=255&value):objectWriteUInt16(this,value,offset,!1),offset+2},Buffer.prototype.writeUInt32LE=function(value,offset,noAssert){return value=+value,offset=0|offset,noAssert||checkInt(this,value,offset,4,4294967295,0),Buffer.TYPED_ARRAY_SUPPORT?(this[offset+3]=value>>>24,this[offset+2]=value>>>16,this[offset+1]=value>>>8,this[offset]=255&value):objectWriteUInt32(this,value,offset,!0),offset+4},Buffer.prototype.writeUInt32BE=function(value,offset,noAssert){return value=+value,offset=0|offset,noAssert||checkInt(this,value,offset,4,4294967295,0),Buffer.TYPED_ARRAY_SUPPORT?(this[offset]=value>>>24,this[offset+1]=value>>>16,this[offset+2]=value>>>8,this[offset+3]=255&value):objectWriteUInt32(this,value,offset,!1),offset+4},Buffer.prototype.writeIntLE=function(value,offset,byteLength,noAssert){if(value=+value,offset=0|offset,!noAssert){var limit=Math.pow(2,8*byteLength-1);checkInt(this,value,offset,byteLength,limit-1,-limit)}var i=0;var mul=1;var sub=0;for(this[offset]=255&value;++i>0)-sub&255;return offset+byteLength},Buffer.prototype.writeIntBE=function(value,offset,byteLength,noAssert){if(value=+value,offset=0|offset,!noAssert){var limit=Math.pow(2,8*byteLength-1);checkInt(this,value,offset,byteLength,limit-1,-limit)}var i=byteLength-1;var mul=1;var sub=0;for(this[offset+i]=255&value;--i>=0&&(mul*=256);)value<0&&0===sub&&0!==this[offset+i+1]&&(sub=1),this[offset+i]=(value/mul>>0)-sub&255;return offset+byteLength},Buffer.prototype.writeInt8=function(value,offset,noAssert){return value=+value,offset=0|offset,noAssert||checkInt(this,value,offset,1,127,-128),Buffer.TYPED_ARRAY_SUPPORT||(value=Math.floor(value)),value<0&&(value=255+value+1),this[offset]=255&value,offset+1},Buffer.prototype.writeInt16LE=function(value,offset,noAssert){return value=+value,offset=0|offset,noAssert||checkInt(this,value,offset,2,32767,-32768),Buffer.TYPED_ARRAY_SUPPORT?(this[offset]=255&value,this[offset+1]=value>>>8):objectWriteUInt16(this,value,offset,!0),offset+2},Buffer.prototype.writeInt16BE=function(value,offset,noAssert){return value=+value,offset=0|offset,noAssert||checkInt(this,value,offset,2,32767,-32768),Buffer.TYPED_ARRAY_SUPPORT?(this[offset]=value>>>8,this[offset+1]=255&value):objectWriteUInt16(this,value,offset,!1),offset+2},Buffer.prototype.writeInt32LE=function(value,offset,noAssert){return value=+value,offset=0|offset,noAssert||checkInt(this,value,offset,4,2147483647,-2147483648),Buffer.TYPED_ARRAY_SUPPORT?(this[offset]=255&value,this[offset+1]=value>>>8,this[offset+2]=value>>>16,this[offset+3]=value>>>24):objectWriteUInt32(this,value,offset,!0),offset+4},Buffer.prototype.writeInt32BE=function(value,offset,noAssert){return value=+value,offset=0|offset,noAssert||checkInt(this,value,offset,4,2147483647,-2147483648),value<0&&(value=4294967295+value+1),Buffer.TYPED_ARRAY_SUPPORT?(this[offset]=value>>>24,this[offset+1]=value>>>16,this[offset+2]=value>>>8,this[offset+3]=255&value):objectWriteUInt32(this,value,offset,!1),offset+4},Buffer.prototype.writeFloatLE=function(value,offset,noAssert){return writeFloat(this,value,offset,!0,noAssert)},Buffer.prototype.writeFloatBE=function(value,offset,noAssert){return writeFloat(this,value,offset,!1,noAssert)},Buffer.prototype.writeDoubleLE=function(value,offset,noAssert){return writeDouble(this,value,offset,!0,noAssert)},Buffer.prototype.writeDoubleBE=function(value,offset,noAssert){return writeDouble(this,value,offset,!1,noAssert)},Buffer.prototype.copy=function(target,targetStart,start,end){if(start||(start=0),end||0===end||(end=this.length),targetStart>=target.length&&(targetStart=target.length),targetStart||(targetStart=0),end>0&&end=this.length)throw new RangeError("sourceStart out of bounds");if(end<0)throw new RangeError("sourceEnd out of bounds");end>this.length&&(end=this.length),target.length-targetStart=0;--i)target[i+targetStart]=this[i+start];else if(len<1e3||!Buffer.TYPED_ARRAY_SUPPORT)for(i=0;i>>=0,end=void 0===end?this.length:end>>>0,val||(val=0);var i;if("number"==typeof val)for(i=start;i=kMaxLength())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+kMaxLength().toString(16)+" bytes");return 0|length}function SlowBuffer(length){return+length!=length&&(length=0),Buffer.alloc(+length)}function byteLength(string,encoding){if(Buffer.isBuffer(string))return string.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(string)||string instanceof ArrayBuffer))return string.byteLength;"string"!=typeof string&&(string=""+string);var len=string.length;if(0===len)return 0;var loweredCase=!1;for(;;)switch(encoding){case"ascii":case"binary":case"raw":case"raws":return len;case"utf8":case"utf-8":case void 0:return utf8ToBytes(string).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*len;case"hex":return len>>>1;case"base64":return base64ToBytes(string).length;default:if(loweredCase)return utf8ToBytes(string).length;encoding=(""+encoding).toLowerCase(),loweredCase=!0}}function slowToString(encoding,start,end){var loweredCase=!1;if((void 0===start||start<0)&&(start=0),start>this.length)return"";if((void 0===end||end>this.length)&&(end=this.length),end<=0)return"";if(end>>>=0,start>>>=0,end<=start)return"";for(encoding||(encoding="utf8");;)switch(encoding){case"hex":return hexSlice(this,start,end);case"utf8":case"utf-8":return utf8Slice(this,start,end);case"ascii":return asciiSlice(this,start,end);case"binary":return binarySlice(this,start,end);case"base64":return base64Slice(this,start,end);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return utf16leSlice(this,start,end);default:if(loweredCase)throw new TypeError("Unknown encoding: "+encoding);encoding=(encoding+"").toLowerCase(),loweredCase=!0}}function swap(b,n,m){var i=b[n];b[n]=b[m],b[m]=i}function arrayIndexOf(arr,val,byteOffset,encoding){function read(buf,i){return 1===indexSize?buf[i]:buf.readUInt16BE(i*indexSize)}var indexSize=1;var arrLength=arr.length;var valLength=val.length;if(void 0!==encoding&&(encoding=String(encoding).toLowerCase(),"ucs2"===encoding||"ucs-2"===encoding||"utf16le"===encoding||"utf-16le"===encoding)){if(arr.length<2||val.length<2)return-1;indexSize=2,arrLength/=2,valLength/=2,byteOffset/=2}var foundIndex=-1;for(var i=byteOffset;iremaining&&(length=remaining)):length=remaining;var strLen=string.length;if(strLen%2!==0)throw new Error("Invalid hex string");length>strLen/2&&(length=strLen/2);for(var i=0;i239?4:firstByte>223?3:firstByte>191?2:1;if(i+bytesPerSequence<=end){var secondByte,thirdByte,fourthByte,tempCodePoint;switch(bytesPerSequence){case 1:firstByte<128&&(codePoint=firstByte);break;case 2:secondByte=buf[i+1],128===(192&secondByte)&&(tempCodePoint=(31&firstByte)<<6|63&secondByte,tempCodePoint>127&&(codePoint=tempCodePoint));break;case 3:secondByte=buf[i+1],thirdByte=buf[i+2],128===(192&secondByte)&&128===(192&thirdByte)&&(tempCodePoint=(15&firstByte)<<12|(63&secondByte)<<6|63&thirdByte,tempCodePoint>2047&&(tempCodePoint<55296||tempCodePoint>57343)&&(codePoint=tempCodePoint));break;case 4:secondByte=buf[i+1],thirdByte=buf[i+2],fourthByte=buf[i+3],128===(192&secondByte)&&128===(192&thirdByte)&&128===(192&fourthByte)&&(tempCodePoint=(15&firstByte)<<18|(63&secondByte)<<12|(63&thirdByte)<<6|63&fourthByte,tempCodePoint>65535&&tempCodePoint<1114112&&(codePoint=tempCodePoint))}}null===codePoint?(codePoint=65533,bytesPerSequence=1):codePoint>65535&&(codePoint-=65536,res.push(codePoint>>>10&1023|55296),codePoint=56320|1023&codePoint),res.push(codePoint),i+=bytesPerSequence}return decodeCodePointsArray(res)}function decodeCodePointsArray(codePoints){var len=codePoints.length;if(len<=MAX_ARGUMENTS_LENGTH)return String.fromCharCode.apply(String,codePoints);var res="";var i=0;for(;ilen)&&(end=len);var out="";for(var i=start;ilength)throw new RangeError("Trying to access beyond buffer length")}function checkInt(buf,value,offset,ext,max,min){if(!Buffer.isBuffer(buf))throw new TypeError('"buffer" argument must be a Buffer instance');if(value>max||valuebuf.length)throw new RangeError("Index out of range")}function objectWriteUInt16(buf,value,offset,littleEndian){value<0&&(value=65535+value+1);for(var i=0,j=Math.min(buf.length-offset,2);i>>8*(littleEndian?i:1-i)}function objectWriteUInt32(buf,value,offset,littleEndian){value<0&&(value=4294967295+value+1);for(var i=0,j=Math.min(buf.length-offset,4);i>>8*(littleEndian?i:3-i)&255}function checkIEEE754(buf,value,offset,ext,max,min){if(offset+ext>buf.length)throw new RangeError("Index out of range");if(offset<0)throw new RangeError("Index out of range")}function writeFloat(buf,value,offset,littleEndian,noAssert){return noAssert||checkIEEE754(buf,value,offset,4,3.4028234663852886e38,-3.4028234663852886e38),ieee754.write(buf,value,offset,littleEndian,23,4),offset+4}function writeDouble(buf,value,offset,littleEndian,noAssert){return noAssert||checkIEEE754(buf,value,offset,8,1.7976931348623157e308,-1.7976931348623157e308),ieee754.write(buf,value,offset,littleEndian,52,8),offset+8}function base64clean(str){if(str=stringtrim(str).replace(INVALID_BASE64_RE,""),str.length<2)return"";for(;str.length%4!==0;)str+="=";return str}function stringtrim(str){return str.trim?str.trim():str.replace(/^\s+|\s+$/g,"")}function toHex(n){return n<16?"0"+n.toString(16):n.toString(16)}function utf8ToBytes(string,units){units=units||1/0;var codePoint;var length=string.length;var leadSurrogate=null;var bytes=[];for(var i=0;i55295&&codePoint<57344){if(!leadSurrogate){if(codePoint>56319){(units-=3)>-1&&bytes.push(239,191,189);continue}if(i+1===length){(units-=3)>-1&&bytes.push(239,191,189);continue}leadSurrogate=codePoint;continue}if(codePoint<56320){(units-=3)>-1&&bytes.push(239,191,189),leadSurrogate=codePoint;continue}codePoint=(leadSurrogate-55296<<10|codePoint-56320)+65536}else leadSurrogate&&(units-=3)>-1&&bytes.push(239,191,189);if(leadSurrogate=null,codePoint<128){if((units-=1)<0)break;bytes.push(codePoint)}else if(codePoint<2048){if((units-=2)<0)break;bytes.push(codePoint>>6|192,63&codePoint|128)}else if(codePoint<65536){if((units-=3)<0)break;bytes.push(codePoint>>12|224,codePoint>>6&63|128,63&codePoint|128)}else{if(!(codePoint<1114112))throw new Error("Invalid code point");if((units-=4)<0)break;bytes.push(codePoint>>18|240,codePoint>>12&63|128,codePoint>>6&63|128,63&codePoint|128)}}return bytes}function asciiToBytes(str){var byteArray=[];for(var i=0;i>8,lo=c%256,byteArray.push(lo),byteArray.push(hi);return byteArray}function base64ToBytes(str){return base64.toByteArray(base64clean(str))}function blitBuffer(src,dst,offset,length){for(var i=0;i=dst.length||i>=src.length);++i)dst[i+offset]=src[i];return i}function isnan(val){return val!==val}var base64=require("base64-js");var ieee754=require("ieee754");var isArray=require("isarray");exports.Buffer=Buffer,exports.SlowBuffer=SlowBuffer,exports.INSPECT_MAX_BYTES=50,Buffer.TYPED_ARRAY_SUPPORT=void 0!==global.TYPED_ARRAY_SUPPORT?global.TYPED_ARRAY_SUPPORT:typedArraySupport(),exports.kMaxLength=kMaxLength(),Buffer.poolSize=8192,Buffer._augment=function(arr){return arr.__proto__=Buffer.prototype,arr},Buffer.from=function(value,encodingOrOffset,length){return from(null,value,encodingOrOffset,length)},Buffer.TYPED_ARRAY_SUPPORT&&(Buffer.prototype.__proto__=Uint8Array.prototype,Buffer.__proto__=Uint8Array,"undefined"!=typeof Symbol&&Symbol.species&&Buffer[Symbol.species]===Buffer&&Object.defineProperty(Buffer,Symbol.species,{value:null,configurable:!0})),Buffer.alloc=function(size,fill,encoding){return alloc(null,size,fill,encoding)},Buffer.allocUnsafe=function(size){return allocUnsafe(null,size)},Buffer.allocUnsafeSlow=function(size){return allocUnsafe(null,size)},Buffer.isBuffer=function(b){return!(null==b||!b._isBuffer)},Buffer.compare=function(a,b){if(!Buffer.isBuffer(a)||!Buffer.isBuffer(b))throw new TypeError("Arguments must be Buffers");if(a===b)return 0;var x=a.length;var y=b.length;for(var i=0,len=Math.min(x,y);i0&&(str=this.toString("hex",0,max).match(/.{2}/g).join(" "),this.length>max&&(str+=" ... ")),""},Buffer.prototype.compare=function(target,start,end,thisStart,thisEnd){if(!Buffer.isBuffer(target))throw new TypeError("Argument must be a Buffer");if(void 0===start&&(start=0),void 0===end&&(end=target?target.length:0),void 0===thisStart&&(thisStart=0),void 0===thisEnd&&(thisEnd=this.length),start<0||end>target.length||thisStart<0||thisEnd>this.length)throw new RangeError("out of range index");if(thisStart>=thisEnd&&start>=end)return 0;if(thisStart>=thisEnd)return-1;if(start>=end)return 1;if(start>>>=0,end>>>=0,thisStart>>>=0,thisEnd>>>=0,this===target)return 0;var x=thisEnd-thisStart;var y=end-start;var len=Math.min(x,y);var thisCopy=this.slice(thisStart,thisEnd);var targetCopy=target.slice(start,end);for(var i=0;i2147483647?byteOffset=2147483647:byteOffset<-2147483648&&(byteOffset=-2147483648),byteOffset>>=0,0===this.length)return-1;if(byteOffset>=this.length)return-1;if(byteOffset<0&&(byteOffset=Math.max(this.length+byteOffset,0)),"string"==typeof val&&(val=Buffer.from(val,encoding)),Buffer.isBuffer(val))return 0===val.length?-1:arrayIndexOf(this,val,byteOffset,encoding);if("number"==typeof val)return Buffer.TYPED_ARRAY_SUPPORT&&"function"===Uint8Array.prototype.indexOf?Uint8Array.prototype.indexOf.call(this,val,byteOffset):arrayIndexOf(this,[val],byteOffset,encoding);throw new TypeError("val must be string, number or Buffer")},Buffer.prototype.includes=function(val,byteOffset,encoding){return this.indexOf(val,byteOffset,encoding)!==-1},Buffer.prototype.write=function(string,offset,length,encoding){if(void 0===offset)encoding="utf8",length=this.length,offset=0;else if(void 0===length&&"string"==typeof offset)encoding=offset,length=this.length,offset=0;else{if(!isFinite(offset))throw new Error("Buffer.write(string, encoding, offset[, length]) is no longer supported");offset=0|offset,isFinite(length)?(length=0|length,void 0===encoding&&(encoding="utf8")):(encoding=length,length=void 0)}var remaining=this.length-offset;if((void 0===length||length>remaining)&&(length=remaining),string.length>0&&(length<0||offset<0)||offset>this.length)throw new RangeError("Attempt to write outside buffer bounds");encoding||(encoding="utf8");var loweredCase=!1;for(;;)switch(encoding){case"hex":return hexWrite(this,string,offset,length);case"utf8":case"utf-8":return utf8Write(this,string,offset,length);case"ascii":return asciiWrite(this,string,offset,length);case"binary":return binaryWrite(this,string,offset,length);case"base64":return base64Write(this,string,offset,length);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return ucs2Write(this,string,offset,length);default:if(loweredCase)throw new TypeError("Unknown encoding: "+encoding);encoding=(""+encoding).toLowerCase(),loweredCase=!0}},Buffer.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var MAX_ARGUMENTS_LENGTH=4096;Buffer.prototype.slice=function(start,end){var len=this.length;start=~~start,end=void 0===end?len:~~end,start<0?(start+=len,start<0&&(start=0)):start>len&&(start=len),end<0?(end+=len,end<0&&(end=0)):end>len&&(end=len),end0&&(mul*=256);)val+=this[offset+--byteLength]*mul;return val},Buffer.prototype.readUInt8=function(offset,noAssert){return noAssert||checkOffset(offset,1,this.length),this[offset]},Buffer.prototype.readUInt16LE=function(offset,noAssert){return noAssert||checkOffset(offset,2,this.length),this[offset]|this[offset+1]<<8},Buffer.prototype.readUInt16BE=function(offset,noAssert){return noAssert||checkOffset(offset,2,this.length),this[offset]<<8|this[offset+1]},Buffer.prototype.readUInt32LE=function(offset,noAssert){return noAssert||checkOffset(offset,4,this.length),(this[offset]|this[offset+1]<<8|this[offset+2]<<16)+16777216*this[offset+3]},Buffer.prototype.readUInt32BE=function(offset,noAssert){return noAssert||checkOffset(offset,4,this.length),16777216*this[offset]+(this[offset+1]<<16|this[offset+2]<<8|this[offset+3])},Buffer.prototype.readIntLE=function(offset,byteLength,noAssert){offset=0|offset,byteLength=0|byteLength,noAssert||checkOffset(offset,byteLength,this.length);var val=this[offset];var mul=1;var i=0;for(;++i=mul&&(val-=Math.pow(2,8*byteLength)),val},Buffer.prototype.readIntBE=function(offset,byteLength,noAssert){offset=0|offset,byteLength=0|byteLength,noAssert||checkOffset(offset,byteLength,this.length);var i=byteLength;var mul=1;var val=this[offset+--i];for(;i>0&&(mul*=256);)val+=this[offset+--i]*mul;return mul*=128,val>=mul&&(val-=Math.pow(2,8*byteLength)),val},Buffer.prototype.readInt8=function(offset,noAssert){return noAssert||checkOffset(offset,1,this.length),128&this[offset]?(255-this[offset]+1)*-1:this[offset]},Buffer.prototype.readInt16LE=function(offset,noAssert){noAssert||checkOffset(offset,2,this.length);var val=this[offset]|this[offset+1]<<8;return 32768&val?4294901760|val:val},Buffer.prototype.readInt16BE=function(offset,noAssert){noAssert||checkOffset(offset,2,this.length);var val=this[offset+1]|this[offset]<<8;return 32768&val?4294901760|val:val},Buffer.prototype.readInt32LE=function(offset,noAssert){return noAssert||checkOffset(offset,4,this.length),this[offset]|this[offset+1]<<8|this[offset+2]<<16|this[offset+3]<<24},Buffer.prototype.readInt32BE=function(offset,noAssert){return noAssert||checkOffset(offset,4,this.length),this[offset]<<24|this[offset+1]<<16|this[offset+2]<<8|this[offset+3]},Buffer.prototype.readFloatLE=function(offset,noAssert){return noAssert||checkOffset(offset,4,this.length),ieee754.read(this,offset,!0,23,4)},Buffer.prototype.readFloatBE=function(offset,noAssert){return noAssert||checkOffset(offset,4,this.length),ieee754.read(this,offset,!1,23,4)},Buffer.prototype.readDoubleLE=function(offset,noAssert){return noAssert||checkOffset(offset,8,this.length),ieee754.read(this,offset,!0,52,8)},Buffer.prototype.readDoubleBE=function(offset,noAssert){return noAssert||checkOffset(offset,8,this.length),ieee754.read(this,offset,!1,52,8)},Buffer.prototype.writeUIntLE=function(value,offset,byteLength,noAssert){if(value=+value,offset=0|offset,byteLength=0|byteLength,!noAssert){var maxBytes=Math.pow(2,8*byteLength)-1;checkInt(this,value,offset,byteLength,maxBytes,0)}var mul=1;var i=0;for(this[offset]=255&value;++i=0&&(mul*=256);)this[offset+i]=value/mul&255;return offset+byteLength},Buffer.prototype.writeUInt8=function(value,offset,noAssert){return value=+value,offset=0|offset,noAssert||checkInt(this,value,offset,1,255,0),Buffer.TYPED_ARRAY_SUPPORT||(value=Math.floor(value)),this[offset]=255&value,offset+1},Buffer.prototype.writeUInt16LE=function(value,offset,noAssert){return value=+value,offset=0|offset,noAssert||checkInt(this,value,offset,2,65535,0),Buffer.TYPED_ARRAY_SUPPORT?(this[offset]=255&value,this[offset+1]=value>>>8):objectWriteUInt16(this,value,offset,!0),offset+2},Buffer.prototype.writeUInt16BE=function(value,offset,noAssert){return value=+value,offset=0|offset,noAssert||checkInt(this,value,offset,2,65535,0),Buffer.TYPED_ARRAY_SUPPORT?(this[offset]=value>>>8,this[offset+1]=255&value):objectWriteUInt16(this,value,offset,!1),offset+2},Buffer.prototype.writeUInt32LE=function(value,offset,noAssert){return value=+value,offset=0|offset,noAssert||checkInt(this,value,offset,4,4294967295,0),Buffer.TYPED_ARRAY_SUPPORT?(this[offset+3]=value>>>24,this[offset+2]=value>>>16,this[offset+1]=value>>>8,this[offset]=255&value):objectWriteUInt32(this,value,offset,!0),offset+4},Buffer.prototype.writeUInt32BE=function(value,offset,noAssert){return value=+value,offset=0|offset,noAssert||checkInt(this,value,offset,4,4294967295,0),Buffer.TYPED_ARRAY_SUPPORT?(this[offset]=value>>>24,this[offset+1]=value>>>16,this[offset+2]=value>>>8,this[offset+3]=255&value):objectWriteUInt32(this,value,offset,!1),offset+4},Buffer.prototype.writeIntLE=function(value,offset,byteLength,noAssert){if(value=+value,offset=0|offset,!noAssert){var limit=Math.pow(2,8*byteLength-1);checkInt(this,value,offset,byteLength,limit-1,-limit)}var i=0;var mul=1;var sub=0;for(this[offset]=255&value;++i>0)-sub&255;return offset+byteLength},Buffer.prototype.writeIntBE=function(value,offset,byteLength,noAssert){if(value=+value,offset=0|offset,!noAssert){var limit=Math.pow(2,8*byteLength-1);checkInt(this,value,offset,byteLength,limit-1,-limit)}var i=byteLength-1;var mul=1;var sub=0;for(this[offset+i]=255&value;--i>=0&&(mul*=256);)value<0&&0===sub&&0!==this[offset+i+1]&&(sub=1),this[offset+i]=(value/mul>>0)-sub&255;return offset+byteLength},Buffer.prototype.writeInt8=function(value,offset,noAssert){return value=+value,offset=0|offset,noAssert||checkInt(this,value,offset,1,127,-128),Buffer.TYPED_ARRAY_SUPPORT||(value=Math.floor(value)),value<0&&(value=255+value+1),this[offset]=255&value,offset+1},Buffer.prototype.writeInt16LE=function(value,offset,noAssert){return value=+value,offset=0|offset,noAssert||checkInt(this,value,offset,2,32767,-32768),Buffer.TYPED_ARRAY_SUPPORT?(this[offset]=255&value,this[offset+1]=value>>>8):objectWriteUInt16(this,value,offset,!0),offset+2},Buffer.prototype.writeInt16BE=function(value,offset,noAssert){return value=+value,offset=0|offset,noAssert||checkInt(this,value,offset,2,32767,-32768),Buffer.TYPED_ARRAY_SUPPORT?(this[offset]=value>>>8,this[offset+1]=255&value):objectWriteUInt16(this,value,offset,!1),offset+2},Buffer.prototype.writeInt32LE=function(value,offset,noAssert){return value=+value,offset=0|offset,noAssert||checkInt(this,value,offset,4,2147483647,-2147483648),Buffer.TYPED_ARRAY_SUPPORT?(this[offset]=255&value,this[offset+1]=value>>>8,this[offset+2]=value>>>16,this[offset+3]=value>>>24):objectWriteUInt32(this,value,offset,!0),offset+4},Buffer.prototype.writeInt32BE=function(value,offset,noAssert){return value=+value,offset=0|offset,noAssert||checkInt(this,value,offset,4,2147483647,-2147483648),value<0&&(value=4294967295+value+1),Buffer.TYPED_ARRAY_SUPPORT?(this[offset]=value>>>24,this[offset+1]=value>>>16,this[offset+2]=value>>>8,this[offset+3]=255&value):objectWriteUInt32(this,value,offset,!1),offset+4},Buffer.prototype.writeFloatLE=function(value,offset,noAssert){return writeFloat(this,value,offset,!0,noAssert)},Buffer.prototype.writeFloatBE=function(value,offset,noAssert){return writeFloat(this,value,offset,!1,noAssert)},Buffer.prototype.writeDoubleLE=function(value,offset,noAssert){return writeDouble(this,value,offset,!0,noAssert)},Buffer.prototype.writeDoubleBE=function(value,offset,noAssert){return writeDouble(this,value,offset,!1,noAssert)},Buffer.prototype.copy=function(target,targetStart,start,end){if(start||(start=0),end||0===end||(end=this.length),targetStart>=target.length&&(targetStart=target.length),targetStart||(targetStart=0),end>0&&end=this.length)throw new RangeError("sourceStart out of bounds");if(end<0)throw new RangeError("sourceEnd out of bounds");end>this.length&&(end=this.length),target.length-targetStart=0;--i)target[i+targetStart]=this[i+start];else if(len<1e3||!Buffer.TYPED_ARRAY_SUPPORT)for(i=0;i>>=0,end=void 0===end?this.length:end>>>0,val||(val=0);var i;if("number"==typeof val)for(i=start;i\n * https://github.com/forio/epicenter-js-libs\n */\n\nvar F = {\n util: {},\n factory: {},\n transport: {},\n store: {},\n service: {},\n manager: {\n strategy: {}\n },\n\n};\n\nF.load = require('./env-load');\nF.load();\n\nF.util.query = require('./util/query-util');\nF.util.makeSequence = require('./util/make-sequence');\nF.util.run = require('./util/run-util');\nF.util.classFrom = require('./util/inherit');\n\nF.factory.Transport = require('./transport/http-transport-factory');\nF.transport.Ajax = require('./transport/ajax-http-transport');\n\nF.service.URL = require('./service/url-config-service');\nF.service.Config = require('./service/configuration-service');\nF.service.Run = require('./service/run-api-service');\nF.service.File = require('./service/admin-file-service');\nF.service.Variables = require('./service/variables-api-service');\nF.service.Data = require('./service/data-api-service');\nF.service.Auth = require('./service/auth-api-service');\nF.service.World = require('./service/world-api-adapter');\nF.service.State = require('./service/state-api-adapter');\nF.service.User = require('./service/user-api-adapter');\nF.service.Member = require('./service/member-api-adapter');\nF.service.Asset = require('./service/asset-api-adapter');\n\nF.store.Cookie = require('./store/cookie-store');\nF.factory.Store = require('./store/store-factory');\n\nF.manager.ScenarioManager = require('./managers/scenario-manager');\nF.manager.RunManager = require('./managers/run-manager');\nF.manager.AuthManager = require('./managers/auth-manager');\nF.manager.WorldManager = require('./managers/world-manager');\n\nF.manager.strategy['always-new'] = require('./managers/run-strategies/always-new-strategy');\nF.manager.strategy['conditional-creation'] = require('./managers/run-strategies/conditional-creation-strategy');\nF.manager.strategy.identity = require('./managers/run-strategies/identity-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-persisted'] = require('./managers/run-strategies/new-if-persisted-strategy');\nF.manager.strategy['new-if-initialized'] = require('./managers/run-strategies/new-if-initialized-strategy');\n\nF.manager.ChannelManager = require('./managers/epicenter-channel-manager');\nF.service.Channel = require('./service/channel-service');\n\nF.version = '<%= version %>';\nF.api = require('./api-version.json');\n\nglobal.F = F;\nmodule.exports = F;\n","'use strict';\n\nvar urlConfigService = require('./service/url-config-service');\n\nvar envLoad = function (callback) {\n var envPromise;\n var host;\n var urlService = urlConfigService();\n var envPath = '/epicenter/v1/config';\n if (urlService.isLocalhost()) {\n host = 'https://forio.com';\n } else {\n host = '';\n }\n var infoUrl = host + envPath;\n envPromise = $.ajax({ url: infoUrl, async: false });\n envPromise.done(function (res) {\n var api = res.api;\n $.extend(urlConfigService, api);\n }).fail(function (res) {\n // Epicenter/webserver not properly configured\n // fallback to api.forio.com\n $.extend(urlConfigService, { protocol: 'https', host: 'api.forio.com' });\n });\n return envPromise.done(callback).fail(callback);\n};\n\nmodule.exports = envLoad;\n","/**\n * Utilities for working with query strings\n*/\n'use strict';\n\nmodule.exports = (function () {\n\n return {\n /**\n * Converts to matrix format\n * @param {Object} qs Object to convert to query string\n * @return { string} Matrix-format query parameters\n */\n toMatrixFormat: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return ';';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n var OPERATORS = ['<', '>', '!'];\n $.each(qs, function (key, value) {\n if (typeof value !== 'string' || $.inArray($.trim(value).charAt(0), OPERATORS) === -1) {\n value = '=' + value;\n }\n returnArray.push(key + value);\n });\n\n var mtrx = ';' + returnArray.join(';');\n return mtrx;\n },\n\n /**\n * Converts strings/arrays/objects to type 'a=b&b=c'\n * @param { string|Array|Object} qs\n * @return { string}\n */\n toQueryFormat: function (qs) {\n if (qs === null || qs === undefined) {\n return '';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n $.each(qs, function (key, value) {\n if ($.isArray(value)) {\n value = value.join(',');\n }\n if ($.isPlainObject(value)) {\n //Mostly for data api\n value = JSON.stringify(value);\n }\n returnArray.push(key + '=' + value);\n });\n\n var result = returnArray.join('&');\n return result;\n },\n\n /**\n * Converts strings of type 'a=b&b=c' to { a:b, b:c}\n * @param { string} qs\n * @return {object}\n */\n qsToObject: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return {};\n }\n\n var qsArray = qs.split('&');\n var returnObj = {};\n $.each(qsArray, function (index, value) {\n var qKey = value.split('=')[0];\n var qVal = value.split('=')[1];\n\n if (qVal.indexOf(',') !== -1) {\n qVal = qVal.split(',');\n }\n\n returnObj[qKey] = qVal;\n });\n\n return returnObj;\n },\n\n /**\n * Normalizes and merges strings of type 'a=b', { b:c} to { a:b, b:c}\n * @param { string|Array|Object} qs1\n * @param { string|Array|Object} qs2\n * @return {Object}\n */\n mergeQS: function (qs1, qs2) {\n var obj1 = this.qsToObject(this.toQueryFormat(qs1));\n var obj2 = this.qsToObject(this.toQueryFormat(qs2));\n return $.extend(true, {}, obj1, obj2);\n },\n\n addTrailingSlash: function (url) {\n if (!url) {\n return '';\n }\n return (url.charAt(url.length - 1) === '/') ? url : (url + '/');\n }\n };\n}());\n\n\n\n","'use strict';\n/*jshint loopfunc:false */\n\nfunction _w(val) {\n if (val && val.then) {\n return val;\n }\n var p = $.Deferred();\n p.resolve(val);\n\n return p.promise();\n}\n\nfunction seq() {\n var list = Array.prototype.slice.apply(arguments);\n\n function next(p) {\n var cur = list.splice(0,1)[0];\n\n if (!cur) {\n return p;\n }\n\n return _w(cur(p)).then(next);\n }\n\n return function (seed) {\n return next(seed).fail(seq.fail);\n };\n}\n\nfunction MakeSeq(obj) {\n var res = {\n __calls: [],\n\n original: obj,\n\n then: function (fn) {\n this.__calls.push(fn);\n return this;\n },\n\n start: function () {\n var _this = this;\n\n // clean up\n this.then(function (run) {\n _this.__calls.length = 0;\n return run;\n });\n\n return seq.apply(null, this.__calls)();\n },\n\n fail: function (fn) {\n seq.fail = fn;\n return this;\n }\n };\n\n var funcMaker = function (p, obj) {\n var fn = obj[p].bind(obj);\n return function () {\n var args = Array.prototype.slice.apply(arguments);\n this.__calls.push(Function.bind.apply(fn, [null].concat(args)));\n return this;\n };\n };\n\n for (var prop in obj) {\n if (typeof obj[prop] === 'function') {\n res[prop] = funcMaker(prop, obj);\n } else {\n res[prop] = obj[prop];\n }\n }\n\n return res;\n}\n\nmodule.exports = MakeSeq;\n","/**\n * Utilities for working with the run service\n*/\n'use strict';\nvar qutil = require('./query-util');\nvar MAX_URL_LENGTH = 2048;\n\nmodule.exports = (function () {\n return {\n /**\n * returns operations of the form `[[op1,op2], [arg1, arg2]]`\n * @param {Object|Array|String} `operations` operations to perform\n * @param {Array} `args` arguments for operation\n * @return {String} Matrix-format query parameters\n */\n normalizeOperations: function (operations, args) {\n if (!args) {\n args = [];\n }\n var returnList = {\n ops: [],\n args: []\n };\n\n var _concat = function (arr) {\n return (arr !== null && arr !== undefined) ? [].concat(arr) : [];\n };\n\n //{ add: [1,2], subtract: [2,4] }\n var _normalizePlainObjects = function (operations, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (opn, arg) {\n returnList.ops.push(opn);\n returnList.args.push(_concat(arg));\n });\n return returnList;\n };\n //{ name: 'add', params: [1] }\n var _normalizeStructuredObjects = function (operation, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation.name);\n returnList.args.push(_concat(operation.params));\n return returnList;\n };\n\n var _normalizeObject = function (operation, returnList) {\n return ((operation.name) ? _normalizeStructuredObjects : _normalizePlainObjects)(operation, returnList);\n };\n\n var _normalizeLiterals = function (operation, args, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation);\n returnList.args.push(_concat(args));\n return returnList;\n };\n\n\n var _normalizeArrays = function (operations, arg, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (index, opn) {\n if ($.isPlainObject(opn)) {\n _normalizeObject(opn, returnList);\n } else {\n _normalizeLiterals(opn, args[index], returnList);\n }\n });\n return returnList;\n };\n\n if ($.isPlainObject(operations)) {\n _normalizeObject(operations, returnList);\n } else if ($.isArray(operations)) {\n _normalizeArrays(operations, args, returnList);\n } else {\n _normalizeLiterals(operations, args, returnList);\n }\n\n return returnList;\n },\n\n splitGetFactory: function (httpOptions) {\n return function (params, options) {\n var http = this;\n var getValue = function (name) {\n var value = options[name] || httpOptions[name];\n if (typeof value === 'function') {\n value = value();\n }\n return value;\n };\n var getFinalUrl = function (params) {\n var url = getValue('url', options);\n var data = params;\n // There is easy (or known) way to get the final URL jquery is going to send so\n // we're replicating it. The process might change at some point but it probably will not.\n // 1. Remove hash\n url = url.replace(/#.*$/, '');\n // 1. Append query string\n var queryParams = qutil.toQueryFormat(data);\n var questionIdx = url.indexOf('?');\n if (queryParams && questionIdx > -1) {\n return url + '&' + queryParams;\n } else if (queryParams) {\n return url + '?' + queryParams;\n }\n return url;\n };\n var url = getFinalUrl(params);\n // We must split the GET in multiple short URL's\n // The only property allowed to be split is \"include\"\n if (params && params.include && encodeURI(url).length > MAX_URL_LENGTH) {\n var dtd = $.Deferred();\n var paramsCopy = $.extend(true, {}, params);\n delete paramsCopy.include;\n var urlNoIncludes = getFinalUrl(paramsCopy);\n var diff = MAX_URL_LENGTH - urlNoIncludes.length;\n var oldSuccess = options.success || httpOptions.success || $.noop;\n var oldError = options.error || httpOptions.error || $.noop;\n // remove the original success and error callbacks\n options.success = $.noop;\n options.error = $.noop;\n\n var include = params.include;\n var currIncludes = [];\n var includeOpts = [currIncludes];\n var currLength = encodeURIComponent('?include=').length;\n var variable = include.pop();\n while (variable) {\n var varLenght = encodeURIComponent(variable).length;\n // Use a greedy approach for now, can be optimized to be solved in a more\n // efficient way\n // + 1 is the comma\n if (currLength + varLenght + 1 < diff) {\n currIncludes.push(variable);\n currLength += varLenght + 1;\n } else {\n currIncludes = [variable];\n includeOpts.push(currIncludes);\n currLength = '?include='.length + varLenght;\n }\n variable = include.pop();\n }\n var reqs = $.map(includeOpts, function (include) {\n var reqParams = $.extend({}, params, { include: include });\n return http.get(reqParams, options);\n });\n $.when.apply($, reqs).then(function () {\n // Each argument are arrays of the arguments of each done request\n // So the first argument of the first array of arguments is the data\n var isValid = arguments[0] && arguments[0][0];\n if (!isValid) {\n // Should never happen...\n oldError();\n return dtd.reject();\n }\n var firstResponse = arguments[0][0];\n var isObject = $.isPlainObject(firstResponse);\n var isRunAPI = (isObject && $.isPlainObject(firstResponse.variables)) || !isObject;\n if (isRunAPI) {\n if (isObject) {\n // aggregate the variables property only\n var aggregateRun = arguments[0][0];\n $.each(arguments, function (idx, args) {\n var run = args[0];\n $.extend(true, aggregateRun.variables, run.variables);\n });\n oldSuccess(aggregateRun, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregateRun, arguments[0][1], arguments[0][2]);\n } else {\n // array of runs\n // Agregate variables in each run\n var aggregatedRuns = {};\n $.each(arguments, function (idx, args) {\n var runs = args[0];\n if (!$.isArray(runs)) {\n return;\n }\n $.each(runs, function (idxRun, run) {\n if (run.id && !aggregatedRuns[run.id]) {\n run.variables = run.variables || {};\n aggregatedRuns[run.id] = run;\n } else if (run.id) {\n $.extend(true, aggregatedRuns[run.id].variables, run.variables);\n }\n });\n });\n // turn it into an array\n aggregatedRuns = $.map(aggregatedRuns, function (run) { return run; });\n oldSuccess(aggregatedRuns, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedRuns, arguments[0][1], arguments[0][2]);\n }\n } else {\n // is variables API\n // aggregate the response\n var aggregatedVariables = {};\n $.each(arguments, function (idx, args) {\n var vars = args[0];\n $.extend(true, aggregatedVariables, vars);\n });\n oldSuccess(aggregatedVariables, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedVariables, arguments[0][1], arguments[0][2]);\n }\n }, function () {\n oldError.apply(http, arguments);\n dtd.reject.apply(dtd, arguments);\n });\n return dtd.promise();\n } else {\n return http.get(params, options);\n }\n };\n }\n };\n}());\n","/**\n/* Inherit from a class (using prototype borrowing)\n*/\n'use strict';\n\nfunction inherit(C, P) {\n var F = function () {};\n F.prototype = P.prototype;\n C.prototype = new F();\n C.__super = P.prototype;\n C.prototype.constructor = C;\n}\n\n/**\n* Shallow copy of an object\n*/\nvar extend = function (dest /*, var_args*/) {\n var obj = Array.prototype.slice.call(arguments, 1);\n var current;\n for (var j = 0; j 1,\n * // where variables.price has been persisted (recorded)\n * // in the model.\n * rs.query({\n * 'saved': 'true',\n * '.price': '>1'\n * },\n * {\n * startrecord: 2,\n * endrecord: 5\n * });\n *\n * **Parameters**\n * @param {Object} `qs` Query object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Querying for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n query: function (qs, outputModifier, options) {\n serviceOptions.filter = qs; //shouldn't be able to over-ride\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Returns particular runs, based on conditions specified in the `qs` object.\n *\n * Similar to `.query()`.\n *\n * **Parameters**\n * @param {Object} `filter` Filter object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Filtering for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n filter: function (filter, outputModifier, options) {\n if ($.isPlainObject(serviceOptions.filter)) {\n $.extend(serviceOptions.filter, filter);\n } else {\n serviceOptions.filter = filter;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Get data for a specific run. This includes standard run data such as the account, model, project, and created and last modified dates. To request specific model variables, pass them as part of the `filters` parameter.\n *\n * Note that if the run is [in memory](../../../run_persistence/#runs-in-memory), any model variables are available; if the run is [in the database](../../../run_persistence/#runs-in-db), only model variables that have been persisted — that is, `record`ed in your Julia model — are available.\n *\n * **Example**\n *\n * rs.load('bb589677-d476-4971-a68e-0c58d191e450', { include: ['.price', '.sales'] });\n *\n * **Parameters**\n * @param {String} `runID` The run id.\n * @param {Object} `filters` (Optional) Object containing filters and operation modifiers. Use key `include` to list model variables that you want to include in the response. Other available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (runID, filters, options) {\n if (runID) {\n serviceOptions.filter = runID; //shouldn't be able to over-ride\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.get(filters, httpOptions);\n },\n\n\n /**\n * Save attributes (data, model variables) of the run.\n *\n * **Examples**\n *\n * // add 'completed' field to run record\n * rs.save({ completed: true });\n *\n * // update 'saved' field of run record, and update values of model variables for this run\n * rs.save({ saved: true, variables: { a: 23, b: 23 } });\n *\n * **Parameters**\n * @param {Object} `attributes` The run data and variables to save.\n * @param {Object} `attributes.variables` Model variables must be included in a `variables` field within the `attributes` object. (Otherwise they are treated as run data and added to the run record directly.)\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (attributes, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n setFilterOrThrowError(httpOptions);\n return http.patch(attributes, httpOptions);\n },\n\n /**\n * Call a method from the model.\n *\n * Depending on the language in which you have written your model, the method may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * The `params` argument is normally an array of arguments to the `operation`. In the special case where `operation` only takes one argument, you are not required to put that argument into an array.\n *\n * Note that you can combine the `operation` and `params` arguments into a single object if you prefer, as in the last example.\n *\n * **Examples**\n *\n * // method \"solve\" takes no arguments\n * rs.do('solve');\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', ['hello']);\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', 'hello');\n * // method \"sumArray\" takes one argument, an array\n * rs.do('sumArray', [[4,2,1]]);\n * // method \"add\" takes two arguments, both integers\n * rs.do({ name:'add', params:[2,4] });\n *\n * **Parameters**\n * @param {String} `operation` Name of method.\n * @param {Array} `params` (Optional) Any parameters the operation takes, passed as an array. In the special case where `operation` only takes one argument, you are not required to put that argument into an array, and can just pass it directly.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n do: function (operation, params, options) {\n // console.log('do', operation, params);\n var opsArgs;\n var postOptions;\n if (options) {\n opsArgs = params;\n postOptions = options;\n } else {\n if ($.isPlainObject(params)) {\n opsArgs = null;\n postOptions = params;\n } else {\n opsArgs = params;\n }\n }\n var result = rutil.normalizeOperations(operation, opsArgs);\n var httpOptions = $.extend(true, {}, serviceOptions, postOptions);\n\n setFilterOrThrowError(httpOptions);\n\n var prms = (result.args[0].length && (result.args[0] !== null && result.args[0] !== undefined)) ? result.args[0] : [];\n return http.post({ arguments: prms }, $.extend(true, {}, httpOptions, {\n url: urlConfig.getFilterURL() + 'operations/' + result.ops[0] + '/'\n }));\n },\n\n /**\n * Call several methods from the model, sequentially.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Examples**\n *\n * // methods \"initialize\" and \"solve\" do not take any arguments\n * rs.serial(['initialize', 'solve']);\n * // methods \"init\" and \"reset\" take two arguments each\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'reset', params: [2,3] }]);\n * // method \"init\" takes two arguments,\n * // method \"runmodel\" takes none\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'runmodel', params: [] }]);\n *\n * **Parameters**\n * @param {Array} `operations` If none of the methods take parameters, pass an array of the method names (strings). If any of the methods do take parameters, pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n serial: function (operations, params, options) {\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var me = this;\n\n var $d = $.Deferred();\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var doSingleOp = function () {\n var op = ops.shift();\n var arg = args.shift();\n\n me.do(op, arg, {\n success: function () {\n if (ops.length) {\n doSingleOp();\n } else {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this, arguments);\n }\n },\n error: function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this, arguments);\n }\n });\n };\n\n doSingleOp();\n\n return $d.promise();\n },\n\n /**\n * Call several methods from the model, executing them in parallel.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Example**\n *\n * // methods \"solve\" and \"reset\" do not take any arguments\n * rs.parallel(['solve', 'reset']);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel([ { name: 'add', params: [1,2] },\n * { name: 'subtract', params:[2,3] }]);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel({ add: [1,2], subtract: [2,4] });\n *\n * **Parameters**\n * @param {Array|Object} `operations` If none of the methods take parameters, pass an array of the method names (as strings). If any of the methods do take parameters, you have two options. You can pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters. Alternatively, you can pass a single object with the method name and a (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n parallel: function (operations, params, options) {\n var $d = $.Deferred();\n\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var queue = [];\n for (var i = 0; i< ops.length; i++) {\n queue.push(\n this.do(ops[i], args[i])\n );\n }\n $.when.apply(this, queue)\n .done(function () {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this.arguments);\n })\n .fail(function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this.arguments);\n });\n\n return $d.promise();\n }\n };\n\n var publicSyncAPI = {\n getCurrentConfig: function () {\n return serviceOptions;\n },\n /**\n * Returns a Variables Service instance. Use the variables instance to load, save, and query for specific model variables. See the [Variable API Service](../variables-api-service/) for more information.\n *\n * **Example**\n *\n * var vs = rs.variables();\n * vs.save({ sample_int: 4 });\n *\n * **Parameters**\n * @param {Object} `config` (Optional) Overrides for configuration options.\n */\n variables: function (config) {\n var vs = new VariablesService($.extend(true, {}, serviceOptions, config, {\n runService: this\n }));\n return vs;\n },\n\n introspection: function (config) {\n var introspection = new IntrospectionService($.extend(true, {}, serviceOptions, config));\n return introspection;\n }\n };\n\n $.extend(this, publicAsyncAPI);\n $.extend(this, publicSyncAPI);\n};\n","/**\n * ## File API Service\n *\n * This is used to upload/download files directly onto Epicenter, analogous to using the File Manager UI in Epicenter directly or SFTPing files in. The Asset API is typically used for all project use-cases, and it's unlikely this File Service will be used directly except by Admin tools (e.g. Flow Inspector).\n *\n * Partially implemented.\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The project id. Defaults to empty string.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The folder type. One of Model|Static|Node\n * @type {String}\n */\n folderType: 'static',\n\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('file')\n });\n\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAsyncAPI = {\n /**\n * Get a directory listing, or contents of a file\n * @param {String} `filePath` Path to the file\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getContents: function (filePath, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.get('', httpOptions);\n },\n\n /**\n * Writes to the given file path; replaces the existing file if it exists\n * @param {String} `filePath` Path to the file\n * @param {String} `contents` Contents to write to file\n * @param {Object} `options` (Optional) Overrides for configuration options\n */\n writeToFile: function (filePath, contents, options) {\n filePath = filePath.split('/');\n var fileName = filePath.pop();\n filePath = filePath.join('/');\n var path = serviceOptions.folderType + '/' + filePath;\n var boundary = '---------------------------7da24f2e50046';\n\n var body = '--' + boundary + '\\r\\n' +\n 'Content-Disposition: form-data; name=\"file\";' +\n 'filename=\"' + fileName + '\"\\r\\n' +\n 'Content-type: text/html\\r\\n\\r\\n' +\n contents + '\\r\\n' +\n '--' + boundary + '--';\n\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path,\n data: body,\n contentType: 'multipart/form-data; boundary=' + boundary\n });\n\n return http.put(body, httpOptions);\n },\n\n /**\n * Removes the file\n * @param {String} `filePath` Path to the file\n * @param {Object} `options` (Optional) Overrides for configuration options\n */\n remove: function (filePath, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.delete(null, httpOptions);\n },\n\n /**\n * Rename the file\n * @param {String} filePath Path to the file\n * @param {Stirng} newName New name of file\n * @param {Object} options (Optional) Overrides for configuration options\n */\n rename: function (filePath, newName, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.patch({ 'name': newName }, httpOptions);\n }\n };\n\n $.extend(this, publicAsyncAPI);\n};\n","/**\n *\n * ## Variables API Service\n *\n * Used in conjunction with the [Run API Service](../run-api-service/) to read, write, and search for specific model variables.\n *\n * var rm = new F.manager.RunManager({\n * run: {\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'supply-chain-model.jl'\n * }\n * });\n * rm.getRun()\n * .then(function() {\n * var vs = rm.run.variables();\n * vs.save({sample_int: 4});\n * });\n *\n */\n\n\n 'use strict';\n\n var TransportFactory = require('../transport/http-transport-factory');\n var rutil = require('../util/run-util');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * The runs object to which the variable filters apply. Defaults to null.\n * @type {runService}\n */\n runService: null\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var getURL = function () {\n return serviceOptions.runService.urlConfig.getFilterURL() + 'variables/';\n };\n\n var addAutoRestoreHeader = function (options) {\n return serviceOptions.runService.urlConfig.addAutoRestoreHeader(options);\n };\n\n var httpOptions = {\n url: getURL\n };\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n http.splitGet = rutil.splitGetFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Get values for a variable.\n *\n * **Example**\n *\n * vs.load('sample_int')\n * .then(function(val){\n * // val contains the value of sample_int\n * });\n *\n * **Parameters**\n * @param {String} `variable` Name of variable to load.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (variable, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n return http.get(outputModifier, $.extend({}, httpOptions, {\n url: getURL() + variable + '/'\n }));\n },\n\n /**\n * Returns particular variables, based on conditions specified in the `query` object.\n *\n * **Example**\n *\n * vs.query(['price', 'sales'])\n * .then(function(val) {\n * // val is an object with the values of the requested variables: val.price, val.sales\n * });\n *\n * vs.query({ include:['price', 'sales'] });\n *\n * **Parameters**\n * @param {Object|Array} `query` The names of the variables requested.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (query, outputModifier, options) {\n //Query and outputModifier are both querystrings in the url; only calling them out separately here to be consistent with the other calls\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n\n if ($.isArray(query)) {\n query = { include: query };\n }\n $.extend(query, outputModifier);\n return http.splitGet(query, httpOptions);\n },\n\n /**\n * Save values to model variables. Overwrites existing values. Note that you can only update model variables if the run is [in memory](../../../run_persistence/#runs-in-memory). (An alternate way to update model variables is to call a method from the model and make sure that the method persists the variables. See `do`, `serial`, and `parallel` in the [Run API Service](../run-api-service/) for calling methods from the model.)\n *\n * **Example**\n *\n * vs.save('price', 4);\n * vs.save({ price: 4, quantity: 5, products: [2,3,4] });\n *\n * **Parameters**\n * @param {Object|String} `variable` An object composed of the model variables and the values to save. Alternatively, a string with the name of the variable.\n * @param {Object} `val` (Optional) If passing a string for `variable`, use this argument for the value to save.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (variable, val, options) {\n var attrs;\n if (typeof variable === 'object') {\n attrs = variable;\n options = val;\n } else {\n (attrs = {})[variable] = val;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n return http.patch.call(this, attrs, httpOptions);\n }\n\n // Not Available until underlying API supports PUT. Otherwise save would be PUT and merge would be PATCH\n // *\n // * Save values to the api. Merges arrays, but otherwise same as save\n // * @param {Object|String} variable Object with attributes, or string key\n // * @param {Object} val Optional if prev parameter was a string, set value here\n // * @param {Object} options Overrides for configuration options\n // *\n // * @example\n // * vs.merge({ price: 4, quantity: 5, products: [2,3,4] })\n // * vs.merge('price', 4);\n\n // merge: function (variable, val, options) {\n // var attrs;\n // if (typeof variable === 'object') {\n // attrs = variable;\n // options = val;\n // } else {\n // (attrs = {})[variable] = val;\n // }\n // var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n // return http.patch.call(this, attrs, httpOptions);\n // }\n };\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ## Authentication API Service\n *\n * The Authentication API Service provides a method for logging in, which creates and returns a user access token.\n *\n * User access tokens are required for each call to Epicenter. (See [Project Access](../../../project_access/) for more information.)\n *\n * If you need additional functionality -- such as tracking session information, easily retrieving the user token, or getting the groups to which an end user belongs -- consider using the [Authorization Manager](../auth-manager/) instead.\n *\n * var auth = new F.service.Auth();\n * auth.login({ userName: 'jsmith@acmesimulations.com',\n * password: 'passw0rd' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Email or username to use for logging in. Defaults to empty string.\n * @type {String}\n */\n userName: '',\n\n /**\n * Password for specified `userName`. Defaults to empty string.\n * @type {String}\n */\n password: '',\n\n /**\n * The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects). Required if the `userName` is for an [end user](../../../glossary/#users). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('authentication')\n });\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Logs user in, returning the user access token.\n *\n * If no `userName` or `password` were provided in the initial configuration options, they are required in the `options` here. If no `account` was provided in the initial configuration options and the `userName` is for an [end user](../../../glossary/#users), the `account` is required as well.\n *\n * **Example**\n *\n * auth.login({\n * userName: 'jsmith',\n * password: 'passw0rd',\n * account: 'acme-simulations' })\n * .then(function (token) {\n * console.log(\"user access token is: \", token.access_token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n login: function (options) {\n var httpOptions = $.extend(true, { success: $.noop }, serviceOptions, options);\n if (!httpOptions.userName || !httpOptions.password) {\n var resp = { status: 401, statusMessage: 'No username or password specified.' };\n if (options.error) {\n options.error.call(this, resp);\n }\n\n return $.Deferred().reject(resp).promise();\n }\n\n var postParams = {\n userName: httpOptions.userName,\n password: httpOptions.password,\n };\n if (httpOptions.account) {\n //pass in null for account under options if you don't want it to be sent\n postParams.account = httpOptions.account;\n }\n\n return http.post(postParams, httpOptions);\n },\n\n // (replace with /* */ comment block, to make visible in docs, once this is more than a noop)\n //\n // Logs user out from specified accounts.\n //\n // Epicenter logout is not implemented yet, so for now this is a dummy promise that gets automatically resolved.\n //\n // **Example**\n //\n // auth.logout();\n //\n // **Parameters**\n // @param {Object} `options` (Optional) Overrides for configuration options.\n //\n logout: function (options) {\n var dtd = $.Deferred();\n dtd.resolve();\n return dtd.promise();\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * ## Data API Service\n *\n * The Data API Service allows you to create, access, and manipulate data related to any of your projects. Data are organized in collections. Each collection contains a document; each element of this top-level document is a JSON object. (See additional information on the underlying [Data API](../../../rest_apis/data_api/).)\n *\n * All API calls take in an \"options\" object as the last parameter. The options can be used to extend/override the Data API Service defaults. In particular, there are three required parameters when you instantiate the Data Service:\n *\n * * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `project`: Epicenter project id.\n * * `root`: The the name of the collection. If you have multiple collections within each of your projects, you can also pass the collection name as an option for each call.\n *\n * var ds = new F.service.Data({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * root: 'survey-responses',\n * server: { host: 'api.forio.com' }\n * });\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('user2',\n * { 'question1': 3, 'question2': 8,\n * 'question3': true, 'question4': 'always' } );\n * ds.query('',{ 'question2': { '$gt': 9} });\n *\n * Note that in addition to the `account`, `project`, and `root`, the Data Service parameters optionally include a `server` object, whose `host` field contains the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Name of collection. Defaults to `/`, that is, the root level of your project at `forio.com/app/your-account-id/your-project-id/`. Required.\n * @type {String}\n */\n root: '/',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The project id. Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * For operations that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n //Options to pass on to the underlying transport layer\n transport: {}\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var getURL = function (key, root) {\n if (!root) {\n root = serviceOptions.root;\n }\n var url = urlConfig.getAPIPath('data') + qutil.addTrailingSlash(root);\n if (key) {\n url+= qutil.addTrailingSlash(key);\n }\n return url;\n };\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: getURL\n });\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Search for data within a collection.\n *\n * Searching using comparison or logical operators (as opposed to exact matches) requires MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional details.\n *\n * **Examples**\n *\n * // request all data associated with document 'user1'\n * ds.query('user1');\n *\n * // exact matching:\n * // request all documents in collection where 'question2' is 9\n * ds.query('', { 'question2': 9});\n *\n * // comparison operators:\n * // request all documents in collection\n * // where 'question2' is greater than 9\n * ds.query('', { 'question2': { '$gt': 9} });\n *\n * // logical operators:\n * // request all documents in collection\n * // where 'question2' is less than 10, and 'question3' is false\n * ds.query('', { '$and': [ { 'question2': { '$lt':10} }, { 'question3': false }] });\n *\n * // regular expresssions: use any Perl-compatible regular expressions\n * // request all documents in collection\n * // where 'question5' contains the string '.*day'\n * ds.query('', { 'question5': { '$regex': '.*day' } });\n *\n * **Parameters**\n * @param {String} `key` The name of the document to search. Pass the empty string ('') to search the entire collection.\n * @param {Object} `query` The query object. For exact matching, this object contains the field name and field value to match. For matching based on comparison, this object contains the field name and the comparison expression. For matching based on logical operators, this object contains an expression using MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional examples.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (key, query, outputModifier, options) {\n var params = $.extend(true, { q: query }, outputModifier);\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(params, httpOptions);\n },\n\n /**\n * Save data to an anonymous document within the collection.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.save('question1', 'yes');\n * ds.save({question1:'yes', question2: 32 });\n * ds.save({ name:'John', className: 'CS101' }, { root: 'students' });\n *\n * **Parameters**\n *\n * @param {String|Object} `key` If `key` is a string, it is the id of the element to save (create) in this document. If `key` is an object, the object is the data to save (create) in this document. In both cases, the id for the document is generated automatically.\n * @param {Object} `value` (Optional) The data to save. If `key` is a string, this is the value to save. If `key` is an object, the value(s) to save are already part of `key` and this argument is not required.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (key, value, options) {\n var attrs;\n if (typeof key === 'object') {\n attrs = key;\n options = value;\n } else {\n (attrs = {})[key] = value;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL('', httpOptions.root);\n\n return http.post(attrs, httpOptions);\n },\n\n /**\n * Save data to a named document or element within the collection. The `root` of the collection must be specified separately in configuration options, either as part of the call or as part of the initialization of ds.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('student1',\n * { firstName: 'john', lastName: 'smith' },\n * { root: 'students' });\n * ds.saveAs('mgmt100/groupB',\n * { scenarioYear: '2015' },\n * { root: 'myclasses' });\n *\n * **Parameters**\n *\n * @param {String} `key` Id of the document.\n * @param {Object} `value` (Optional) The data to save, in key:value pairs.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n saveAs: function (key, value, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n\n return http.put(value, httpOptions);\n },\n\n /**\n * Get data for a specific document or field.\n *\n * **Example**\n *\n * ds.load('user1');\n * ds.load('user1/question3');\n *\n * **Parameters**\n * @param {String|Object} `key` The id of the data to return. Can be the id of a document, or a path to data within that document.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` Overrides for configuration options.\n */\n load: function (key, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(outputModifier, httpOptions);\n },\n\n /**\n * Removes data from collection. Only documents (top-level elements in each collection) can be deleted.\n *\n * **Example**\n *\n * ds.remove('user1');\n *\n *\n * **Parameters**\n *\n * @param {String|Array} `keys` The id of the document to remove from this collection, or an array of such ids.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n remove: function (keys, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n var params;\n if ($.isArray(keys)) {\n params = { id: keys };\n } else {\n params = '';\n httpOptions.url = getURL(keys, httpOptions.root);\n }\n return http.delete(params, httpOptions);\n }\n\n // Epicenter doesn't allow nuking collections\n // /**\n // * Removes collection being referenced\n // * @return null\n // */\n // destroy: function (options) {\n // return this.remove('', options);\n // }\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n * ## State API Adapter\n *\n * The State API Adapter allows you to replay or clone runs. It brings existing, persisted run data from the database back into memory, using the same run id (`replay`) or a new run id (`clone`). Runs must be in memory in order for you to update variables or call operations on them.\n *\n * Specifically, the State API Adapter works by \"re-running\" the run (user interactions) from the creation of the run up to the time it was last persisted in the database. This process uses the current version of the run's model. Therefore, if the model has changed since the original run was created, the retrieved run will use the new model — and may end up having different values or behavior as a result. Use with care!\n *\n * To use the State API Adapter, instantiate it and then call its methods:\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f'});\n *\n * The constructor takes an optional `options` parameter in which you can specify the `account` and `project` if they are not already available in the current context.\n *\n */\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar SessionManager = require('../store/session-manager');\nvar apiEndpoint = 'model/state';\n\nmodule.exports = function (config) {\n\n var defaults = {\n\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n var parseRunIdOrError = function (params) {\n if ($.isPlainObject(params) && params.runId) {\n return params.runId;\n } else {\n throw new Error('Please pass in a run id');\n }\n };\n\n var publicAPI = {\n /**\n * Replay a run. After this call, the run, with its original run id, is now available [in memory](../../../run_persistence/#runs-in-memory). (It continues to be persisted into the Epicenter database at regular intervals.)\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore'});\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to bring back to memory.\n * @param {string} `params.stopBefore` (Optional) The run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n replay: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'replay' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n },\n\n /**\n * Clone a given run and return a new run in the same state as the given run.\n *\n * The new run id is now available [in memory](../../../run_persistence/#runs-in-memory). The new run includes a copy of all of the data from the original run, EXCEPT:\n *\n * * The `saved` field in the new run record is not copied from the original run record. It defaults to `false`.\n * * The `initialized` field in the new run record is not copied from the original run record. It defaults to `false` but may change to `true` as the new run is advanced. For example, if there has been a call to the `step` function (for Vensim models), the `initialized` field is set to `true`.\n * * The `created` field in the new run record is the date and time at which the clone was created (not the time that the original run was created.)\n *\n * The original run remains only [in the database](../../../run_persistence/#runs-in-db).\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.clone({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore', exclude: ['interimCalculation'] });\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to clone from memory.\n * @param {string} `params.stopBefore` (Optional) The newly cloned run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the newly cloned run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n clone: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'clone' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * ## World API Adapter\n *\n * A [run](../../../glossary/#run) is a collection of end user interactions with a project and its model -- including setting variables, making decisions, and calling operations. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases. Only [team projects](../../../glossary/#team) can be multiplayer.\n *\n * The World API Adapter allows you to create, access, and manipulate multiplayer worlds within your Epicenter project. You can use this to add and remove end users from the world, and to create, access, and remove their runs. Because of this, typically the World Adapter is used for facilitator pages in your project. (The related [World Manager](../world-manager/) provides an easy way to access runs and worlds for particular end users, so is typically used in pages that end users will interact with.)\n *\n * As with all the other [API Adapters](../../), all methods take in an \"options\" object as the last parameter. The options can be used to extend/override the World API Service defaults.\n *\n * To use the World Adapter, instantiate it and then access the methods provided. Instantiating requires the account id (**Team ID** in the Epicenter user interface), project id (**Project ID**), and group (**Group Name**).\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // call methods, e.g. wa.addUsers()\n * });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar _pick = require('../util/object-util')._pick;\n\nvar apiBase = 'multiplayer/';\nvar assignmentEndpoint = apiBase + 'assign';\nvar apiEndpoint = apiBase + 'world';\nvar projectEndpoint = apiBase + 'project';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The group name. Defaults to undefined.\n * @type {String}\n */\n group: undefined,\n\n /**\n * The model file to use to create runs in this world. Defaults to undefined.\n * @type {String}\n */\n model: undefined,\n\n /**\n * Criteria by which to filter world. Currently only supports world-ids as filters.\n * @type {String}\n */\n filter: '',\n\n /**\n * Convenience alias for filter\n * @type {String}\n */\n id: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {},\n\n /**\n * Called when the call completes successfully. Defaults to `$.noop`.\n * @type {function}\n */\n success: $.noop,\n\n /**\n * Called when the call fails. Defaults to `$.noop`.\n * @type {function}\n */\n error: $.noop\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n if (serviceOptions.id) {\n serviceOptions.filter = serviceOptions.id;\n }\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var setIdFilterOrThrowError = function (options) {\n if (options.id) {\n serviceOptions.filter = options.id;\n }\n if (options.filter) {\n serviceOptions.filter = options.filter;\n }\n if (!serviceOptions.filter) {\n throw new Error('No world id specified to apply operations against. This could happen if the user is not assigned to a world and is trying to work with runs from that world.');\n }\n };\n\n var validateModelOrThrowError = function (options) {\n if (!options.model) {\n throw new Error('No model specified to get the current run');\n }\n };\n\n var publicAPI = {\n\n /**\n * Creates a new World.\n *\n * Using this method is rare. It is more common to create worlds automatically while you `autoAssign()` end users to worlds. (In this case, configuration data for the world, such as the roles, are read from the project-level world configuration information, for example by `getProjectSettings()`.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create({\n * roles: ['VP Marketing', 'VP Sales', 'VP Engineering']\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to create the world.\n * @param {string} `params.group` (Optional) The **Group Name** to create this world under. Only end users in this group are eligible to join the world. Optional here; required when instantiating the service (`new F.service.World()`).\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (params, options) {\n var createOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) });\n var worldApiParams = ['scope', 'files', 'roles', 'optionalRoles', 'minUsers', 'group', 'name'];\n var validParams = _pick(serviceOptions, ['account', 'project', 'group']);\n // whitelist the fields that we actually can send to the api\n params = _pick(params, worldApiParams);\n\n // account and project go in the body, not in the url\n params = $.extend({}, validParams, params);\n\n var oldSuccess = createOptions.success;\n createOptions.success = function (response) {\n serviceOptions.filter = response.id; //all future chained calls to operate on this id\n return oldSuccess.apply(this, arguments);\n };\n\n return http.post(params, createOptions);\n },\n\n /**\n * Updates a World, for example to replace the roles in the world.\n *\n * Typically, you complete world configuration at the project level, rather than at the world level. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both. However, this method is available if you need to update the configuration of a particular world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.update({ roles: ['VP Marketing', 'VP Sales', 'VP Engineering'] });\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to update the world.\n * @param {string} `params.name` A string identifier for the linked end users, for example, \"name\": \"Our Team\".\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n update: function (params, options) {\n var whitelist = ['roles', 'optionalRoles', 'minUsers'];\n options = options || {};\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n params = _pick(params || {}, whitelist);\n\n return http.patch(params, updateOptions);\n },\n\n /**\n * Deletes an existing world.\n *\n * This function optionally takes one argument. If the argument is a string, it is the id of the world to delete. If the argument is an object, it is the override for global options.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.delete();\n * });\n *\n * **Parameters**\n * @param {String|Object} `options` (Optional) The id of the world to delete, or options object to override global options.\n *\n */\n delete: function (options) {\n options = (options && (typeof options === 'string')) ? { filter: options } : {};\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Updates the configuration for the current instance of the World API Adapter (including all subsequent function calls, until the configuration is updated again).\n *\n * **Example**\n *\n * var wa = new F.service.World({...}).updateConfig({ filter: '123' }).addUser({ userId: '123' });\n *\n * **Parameters**\n * @param {object} `config` The configuration object to use in updating existing configuration.\n */\n updateConfig: function (config) {\n $.extend(serviceOptions, config);\n\n return this;\n },\n\n /**\n * Lists all worlds for a given account, project, and group. All three are required, and if not specified as parameters, are read from the service.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // lists all worlds in group \"team1\"\n * wa.list();\n *\n * // lists all worlds in group \"other-group-name\"\n * wa.list({ group: 'other-group-name' });\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n list: function (options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = _pick(getOptions, ['account', 'project', 'group']);\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Gets all worlds that an end user belongs to for a given account (team), project, and group.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getWorldsForUser('b1c19dda-2d2e-4777-ad5d-3929f17e86d3')\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose worlds are being retrieved.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getWorldsForUser: function (userId, options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = $.extend(\n _pick(getOptions, ['account', 'project', 'group']),\n { userId: userId }\n );\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Load information for a specific world. All further calls to the world service will use the id provided.\n *\n * **Parameters**\n * @param {String} `worldId` The id of the world to load.\n * @param {Object} `options` (Optional) Options object to override global options.\n */\n load: function (worldId, options) {\n if (worldId) {\n serviceOptions.filter = worldId;\n }\n if (!serviceOptions.filter) {\n throw new Error('Please provide a worldid to load');\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/' });\n return http.get('', httpOptions);\n },\n\n /**\n * Adds an end user or list of end users to a given world. The end user must be a member of the `group` that is associated with this world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // add one user\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.addUsers(['b1c19dda-2d2e-4777-ad5d-3929f17e86d3']);\n * wa.addUsers({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'VP Sales' });\n *\n * // add several users\n * wa.addUsers([\n * { userId: 'a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44',\n * role: 'VP Marketing' },\n * { userId: '8f2604cf-96cd-449f-82fa-e331530734ee',\n * role: 'VP Engineering' }\n * ]);\n *\n * // add one user to a specific world\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', world.id);\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', { filter: world.id });\n * });\n *\n * ** Parameters **\n * @param {string|object|array} `users` User id, array of user ids, object, or array of objects of the users to add to this world.\n * @param {string} `users.role` The `role` the user should have in the world. It is up to the caller to ensure, if needed, that the `role` passed in is one of the `roles` or `optionalRoles` of this world.\n * @param {string} `worldId` The world to which the users should be added. If not specified, the filter parameter of the `options` object is used.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n addUsers: function (users, worldId, options) {\n\n if (!users) {\n throw new Error('Please provide a list of users to add to the world');\n }\n\n // normalize the list of users to an array of user objects\n users = $.map([].concat(users), function (u) {\n var isObject = $.isPlainObject(u);\n\n if (typeof u !== 'string' && !isObject) {\n throw new Error('Some of the users in the list are not in the valid format: ' + u);\n }\n\n return isObject ? u : { userId: u };\n });\n\n // check if options were passed as the second parameter\n if ($.isPlainObject(worldId) && !options) {\n options = worldId;\n worldId = null;\n }\n\n options = options || {};\n\n // we must have options by now\n if (typeof worldId === 'string') {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users' }\n );\n\n return http.post(users, updateOptions);\n },\n\n /**\n * Updates the role of an end user in a given world. (You can only update one end user at a time.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.create().then(function(world) {\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.updateUser({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'leader' });\n * });\n *\n * **Parameters**\n * @param {object} `user` User object with `userId` and the new `role`.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n updateUser: function (user, options) {\n options = options || {};\n\n if (!user || !user.userId) {\n throw new Error('You need to pass a userId to update from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var patchOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.patch(_pick(user, 'role'), patchOptions);\n },\n\n /**\n * Removes an end user from a given world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.addUsers(['a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44', '8f2604cf-96cd-449f-82fa-e331530734ee']);\n * wa.removeUser('a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44');\n * wa.removeUser({ userId: '8f2604cf-96cd-449f-82fa-e331530734ee' });\n * });\n *\n * ** Parameters **\n * @param {object|string} `user` The `userId` of the user to remove from the world, or an object containing the `userId` field.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n removeUser: function (user, options) {\n options = options || {};\n\n if (typeof user === 'string') {\n user = { userId: user };\n }\n\n if (!user.userId) {\n throw new Error('You need to pass a userId to remove from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.delete(null, getOptions);\n },\n\n /**\n * Gets the run id of current run for the given world. If the world does not have a run, creates a new one and returns the run id.\n *\n * Remember that a [run](../../glossary/#run) is a collection of interactions with a project and its model. In the case of multiplayer projects, the run is shared by all end users in the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getCurrentRunId({ model: 'model.py' });\n * });\n *\n * ** Parameters **\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n getCurrentRunId: function (options) {\n options = options || {};\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n validateModelOrThrowError(getOptions);\n return http.post(_pick(getOptions, 'model'), getOptions);\n },\n\n /**\n * Gets the current (most recent) world for the given end user in the given group. Brings this most recent world into memory if needed.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function(world) {\n * // use data from world\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose current (most recent) world is being retrieved.\n * @param {string} `groupName` (Optional) The name of the group. If not provided, defaults to the group used to create the service.\n */\n getCurrentWorldForUser: function (userId, groupName) {\n var dtd = $.Deferred();\n var me = this;\n this.getWorldsForUser(userId, { group: groupName })\n .then(function (worlds) {\n // assume the most recent world as the 'active' world\n worlds.sort(function (a, b) { return new Date(b.lastModified) - new Date(a.lastModified); });\n var currentWorld = worlds[0];\n\n if (currentWorld) {\n serviceOptions.filter = currentWorld.id;\n }\n\n dtd.resolve(currentWorld, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Deletes the current run from the world.\n *\n * (Note that the world id remains part of the run record, indicating that the run was formerly an active run for the world.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.deleteRun('sample-world-id');\n *\n * **Parameters**\n * @param {string} `worldId` The `worldId` of the world from which the current run is being deleted.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n deleteRun: function (worldId, options) {\n options = options || {};\n\n if (worldId) {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Creates a new run for the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function (world) {\n * wa.newRunForWorld(world.id);\n * });\n *\n * **Parameters**\n * @param {string} `worldId` worldId in which we create the new run.\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n newRunForWorld: function (worldId, options) {\n var currentRunOptions = $.extend(true, {},\n options,\n { filter: worldId || serviceOptions.filter }\n );\n var _this = this;\n\n validateModelOrThrowError(currentRunOptions);\n\n return this.deleteRun(worldId, options)\n .then(function () {\n return _this.getCurrentRunId(currentRunOptions);\n });\n },\n\n /**\n * Assigns end users to worlds, creating new worlds as appropriate, automatically. Assigns all end users in the group, and creates new worlds as needed based on the project-level world configuration (roles, optional roles, and minimum end users per world).\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.autoAssign();\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n autoAssign: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(assignmentEndpoint) }\n );\n\n var params = {\n account: opt.account,\n project: opt.project,\n group: opt.group\n };\n\n if (opt.maxUsers) {\n params.maxUsers = opt.maxUsers;\n }\n\n return http.post(params, opt);\n },\n\n /**\n * Gets the project's world configuration.\n *\n * Typically, every interaction with your project uses the same configuration of each world. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both.\n *\n * (The [Multiplayer Project REST API](../../../rest_apis/multiplayer/multiplayer_project/) allows you to set these project-level world configurations. The World Adapter simply retrieves them, for example so they can be used in auto-assignment of end users to worlds.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getProjectSettings()\n * .then(function(settings) {\n * console.log(settings.roles);\n * console.log(settings.optionalRoles);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getProjectSettings: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(projectEndpoint) }\n );\n\n opt.url += [opt.account, opt.project].join('/');\n\n return http.get(null, opt);\n }\n\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n* ## User API Adapter\n*\n* The User API Adapter allows you to retrieve details about end users in your team (account). It is based on the querying capabilities of the underlying RESTful [User API](../../../rest_apis/user_management/user/).\n*\n* To use the User API Adapter, instantiate it and then call its methods.\n*\n* var ua = new F.service.User({\n* account: 'acme-simulations',\n* token: 'user-or-project-access-token'\n* });\n* ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n* ua.get({ userName: 'jsmith' });\n* ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n* '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n*\n* The constructor takes an optional `options` parameter in which you can specify the `account` and `token` if they are not already available in the current context.\n*/\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar qutil = require('../util/query-util');\n\nmodule.exports = function (config) {\n var defaults = {\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The access token to use when searching for end users. (See [more background on access tokens](../../../project_access/)).\n * @type {String}\n */\n token: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('user')\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Retrieve details about particular end users in your team, based on user name or user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.get({ userName: 'jsmith' });\n * ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n * '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n *\n * **Parameters**\n * @param {object} `filter` Object with field `userName` and value of the username. Alternatively, object with field `id` and value of an array of user ids.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n get: function (filter, options) {\n options = options || {};\n filter = filter || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options\n );\n\n var toQFilter = function (filter) {\n var res = {};\n\n // API only supports filtering by username for now\n if (filter.userName) {\n res.q = filter.userName;\n }\n\n return res;\n };\n\n var toIdFilters = function (id) {\n if (!id) {\n return '';\n }\n\n id = $.isArray(id) ? id : [id];\n return 'id=' + id.join('&id=');\n };\n\n var getFilters = [\n 'account=' + getOptions.account,\n toIdFilters(filter.id),\n qutil.toQueryFormat(toQFilter(filter))\n ].join('&');\n\n // special case for queries with large number of ids\n // make it as a post with GET semantics\n var threshold = 30;\n if (filter.id && $.isArray(filter.id) && filter.id.length >= threshold) {\n getOptions.url = urlConfig.getAPIPath('user') + '?_method=GET';\n return http.post({ id: filter.id }, getOptions);\n } else {\n return http.get(getFilters, getOptions);\n }\n },\n\n /**\n * Retrieve details about a single end user in your team, based on user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n *\n * **Parameters**\n * @param {string} `userId` The user id for the end user in your team.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n getById: function (userId, options) {\n return publicAPI.get({ id: userId }, options);\n }\n };\n\n $.extend(this, publicAPI);\n};\n\n\n\n\n","/**\n *\n * ## Member API Adapter\n *\n * The Member API Adapter provides methods to look up information about end users for your project and how they are divided across groups. It is based on query capabilities of the underlying RESTful [Member API](../../../rest_apis/user_management/member/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/). For example, if some of your end users are facilitators, or if your end users should be treated differently based on which group they are in, use the Member API to find that information.\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser({ userId: 'b6b313a3-ab84-479c-baea-206f6bff337' });\n * ma.getGroupDetails({ groupId: '00b53308-9833-47f2-b21e-1278c07d53b8' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'member/local';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Epicenter user id. Defaults to a blank string.\n * @type {string}\n */\n userId: undefined,\n\n /**\n * Epicenter group id. Defaults to a blank string. Note that this is the group *id*, not the group *name*.\n * @type {string}\n */\n groupId: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(transportOptions, serviceOptions);\n\n var getFinalParams = function (params) {\n if (typeof params === 'object') {\n return $.extend(true, serviceOptions, params);\n }\n return serviceOptions;\n };\n\n var patchUserActiveField = function (params, active, options) {\n var httpOptions = $.extend(true, serviceOptions, options, {\n url: urlConfig.getAPIPath(apiEndpoint) + params.groupId + '/' + params.userId\n });\n\n return http.patch({ active: active }, httpOptions);\n };\n\n var publicAPI = {\n\n /**\n * Retrieve details about all of the group memberships for one end user. The membership details are returned in an array, with one element (group record) for each group to which the end user belongs.\n *\n * In the membership array, each group record includes the group id, project id, account (team) id, and an array of members. However, only the user whose userId is included in the call is listed in the members array (regardless of whether there are other members in this group).\n *\n * **Example**\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser('42836d4b-5b61-4fe4-80eb-3136e956ee5c')\n * .then(function(memberships){\n * for (var i=0; i\n * // \n * // \n * // \n * // \n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar SessionManager = require('../store/session-manager');\n\nvar apiEndpoint = 'asset';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n /**\n * The group name. Defaults to session's `groupName`.\n * @type {String}\n */\n group: undefined,\n /**\n * The user id. Defaults to session's `userId`.\n * @type {String}\n */\n userId: undefined,\n /**\n * The scope for the asset. Valid values are: `user`, `group`, and `project`. See above for the required permissions to write to each scope. Defaults to `user`, meaning the current end user or a facilitator in the end user's group can edit the asset.\n * @type {String}\n */\n scope: 'user',\n /**\n * Determines if a request to list the assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`). Defaults to `true`.\n * @type {boolean}\n */\n fullUrl: true,\n /**\n * The transport object contains the options passed to the XHR request.\n * @type {object}\n */\n transport: {\n processData: false\n }\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var assetApiParams = ['encoding', 'data', 'contentType'];\n var scopeConfig = {\n user: ['scope', 'account', 'project', 'group', 'userId'],\n group: ['scope', 'account', 'project', 'group'],\n project: ['scope', 'account', 'project'],\n };\n\n var validateFilename = function (filename) {\n if (!filename) {\n throw new Error('filename is needed.');\n }\n };\n\n var validateUrlParams = function (options) {\n var partKeys = scopeConfig[options.scope];\n if (!partKeys) {\n throw new Error('scope parameter is needed.');\n }\n\n $.each(partKeys, function () {\n if (!options[this]) {\n throw new Error(this + ' parameter is needed.');\n }\n });\n };\n\n var buildUrl = function (filename, options) {\n validateUrlParams(options);\n var partKeys = scopeConfig[options.scope];\n var parts = $.map(partKeys, function (key) {\n return options[key];\n });\n if (filename) {\n // This prevents adding a trailing / in the URL as the Asset API\n // does not work correctly with it\n filename = '/' + filename;\n }\n return urlConfig.getAPIPath(apiEndpoint) + parts.join('/') + filename;\n };\n\n // Private function, all requests follow a more or less same approach to\n // use the Asset API and the difference is the HTTP verb\n //\n // @param {string} `method` (Required) HTTP verb\n // @param {string} `filename` (Required) Name of the file to delete/replace/create\n // @param {object} `params` (Optional) Body parameters to send to the Asset API\n // @param {object} `options` (Optional) Options object to override global options.\n var upload = function (method, filename, params, options) {\n validateFilename(filename);\n // make sure the parameter is clean\n method = method.toLowerCase();\n var contentType = params instanceof FormData === true ? false : 'application/json';\n if (contentType === 'application/json') {\n // whitelist the fields that we actually can send to the api\n params = _pick(params, assetApiParams);\n } else { // else we're sending form data which goes directly in request body\n // For multipart/form-data uploads the filename is not set in the URL,\n // it's getting picked by the FormData field filename.\n filename = method === 'post' || method === 'put' ? '' : filename;\n }\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var createOptions = $.extend(true, {}, urlOptions, { url: url, contentType: contentType });\n\n return http[method](params, createOptions);\n };\n\n var publicAPI = {\n /**\n * Creates a file in the Asset API. The server returns an error (status code `409`, conflict) if the file already exists, so\n * check first with a `list()` or a `get()`.\n *\n * **Example**\n *\n * var aa = new F.service.Asset({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * userId: ''\n * });\n *\n * // create a new asset using encoded text\n * aa.create('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHRlc3QgZmlsZS4=',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, create a new asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to create.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (filename, params, options) {\n return upload('post', filename, params, options);\n },\n\n /**\n * Gets a file from the Asset API, fetching the asset content. (To get a list\n * of the assets in a scope, use `list()`.)\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to retrieve.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n get: function (filename, options) {\n var getServiceOptions = _pick(serviceOptions, ['scope', 'account', 'project', 'group', 'userId']);\n var urlOptions = $.extend({}, getServiceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n\n return http.get({}, getOptions);\n },\n\n /**\n * Gets the list of the assets in a scope.\n *\n * **Example**\n *\n * aa.list({ fullUrl: true }).then(function(fileList){\n * console.log('array of files = ', fileList);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {string} `options.scope` (Optional) The scope (`user`, `group`, `project`).\n * @param {boolean} `options.fullUrl` (Optional) Determines if the list of assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`).\n *\n */\n list: function (options) {\n var dtd = $.Deferred();\n var me = this;\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl('', urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n var fullUrl = getOptions.fullUrl;\n\n if (!fullUrl) {\n return http.get({}, getOptions);\n }\n\n http.get({}, getOptions)\n .then(function (files) {\n var fullPathFiles = $.map(files, function (file) {\n return buildUrl(file, urlOptions);\n });\n dtd.resolve(fullPathFiles, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Replaces an existing file in the Asset API.\n *\n * **Example**\n *\n * // replace an asset using encoded text\n * aa.replace('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHNlY29uZCB0ZXN0IGZpbGUu',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, replace an asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#replace-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#replace-filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.replace(filename, data, { scope: 'user' });\n * });\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file being replaced.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n replace: function (filename, params, options) {\n return upload('put', filename, params, options);\n },\n\n /**\n * Deletes a file from the Asset API.\n *\n * **Example**\n *\n * aa.delete(sampleFileName);\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to delete.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n delete: function (filename, options) {\n return upload('delete', filename, {}, options);\n },\n\n assetUrl: function (filename, options) {\n var urlOptions = $.extend({}, serviceOptions, options);\n return buildUrl(filename, urlOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * @class Cookie Storage Service\n *\n * @example\n * var people = require('cookie-store')({ root: 'people' });\n people\n .save({lastName: 'smith' })\n\n */\n\n\n'use strict';\n\n// Thin document.cookie wrapper to allow unit testing\nvar Cookie = function () {\n this.get = function () {\n return document.cookie;\n };\n\n this.set = function (newCookie) {\n document.cookie = newCookie;\n };\n};\n\nmodule.exports = function (config) {\n var host = window.location.hostname;\n var defaults = {\n /**\n * Name of collection\n * @type { string}\n */\n root: '/',\n\n domain: '.' + host,\n cookie: new Cookie()\n };\n this.serviceOptions = $.extend({}, defaults, config);\n\n var publicAPI = {\n // * TBD\n // * Query collection; uses MongoDB syntax\n // * @see \n // *\n // * @param { string} qs Query Filter\n // * @param { string} limiters @see \n // *\n // * @example\n // * cs.query(\n // * { name: 'John', className: 'CSC101' },\n // * {limit: 10}\n // * )\n\n // query: function (qs, limiters) {\n\n // },\n\n /**\n * Save cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @param {Object} value (Optional)\n * @param {Object} options Overrides for service options\n *\n * @return {*} The saved value\n *\n * @example\n * cs.set('person', { firstName: 'john', lastName: 'smith' });\n * cs.set({ name:'smith', age:'32' });\n */\n set: function (key, value, options) {\n var setOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = setOptions.domain;\n var path = setOptions.root;\n var cookie = setOptions.cookie;\n\n cookie.set(encodeURIComponent(key) + '=' +\n encodeURIComponent(value) +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '')\n );\n\n return value;\n },\n\n /**\n * Load cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @return {*} The value stored\n *\n * @example\n * cs.get('person');\n */\n get: function (key) {\n var cookie = this.serviceOptions.cookie;\n var cookieReg = new RegExp('(?:^|;)\\\\s*' + encodeURIComponent(key).replace(/[\\-\\.\\+\\*]/g, '\\\\$&') + '\\\\s*\\\\=\\\\s*([^;]*).*$');\n var res = cookieReg.exec(cookie.get());\n var val = res ? decodeURIComponent(res[1]) : null;\n return val;\n },\n\n /**\n * Removes key from collection\n * @param { string} key key to remove\n * @return { string} key The key removed\n *\n * @example\n * cs.remove('person');\n */\n remove: function (key, options) {\n var remOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = remOptions.domain;\n var path = remOptions.root;\n var cookie = remOptions.cookie;\n\n cookie.set(encodeURIComponent(key) +\n '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '')\n );\n return key;\n },\n\n /**\n * Removes collection being referenced\n * @return { array} keys All the keys removed\n */\n destroy: function () {\n var cookie = this.serviceOptions.cookie;\n var aKeys = cookie.get().replace(/((?:^|\\s*;)[^\\=]+)(?=;|$)|^\\s*|\\s*(?:\\=[^;]*)?(?:\\1|$)/g, '').split(/\\s*(?:\\=[^;]*)?;\\s*/);\n for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {\n var cookieKey = decodeURIComponent(aKeys[nIdx]);\n this.remove(cookieKey);\n }\n return aKeys;\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n Decides type of store to provide\n*/\n\n'use strict';\n// var isNode = false; FIXME: Browserify/minifyify has issues with the next link\n// var store = (isNode) ? require('./session-store') : require('./cookie-store');\nvar store = require('./cookie-store');\n\nmodule.exports = store;\n","'use strict';\nvar RunService = require('../service/run-api-service');\n\nvar defaults = {\n validFilter: { saved: true }\n};\n\nfunction ScenarioManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n this.runService = this.options.run || new RunService(this.options);\n}\n\nScenarioManager.prototype = {\n getRuns: function (filter) {\n this.filter = $.extend(true, {}, this.options.validFilter, filter);\n return this.runService.query(this.filter);\n },\n\n loadVariables: function (vars) {\n return this.runService.query(this.filter, { include: vars });\n },\n\n save: function (run, meta) {\n return this._getService(run).save($.extend(true, {}, { saved: true }, meta));\n },\n\n archive: function (run) {\n return this._getService(run).save({ saved: false });\n },\n\n _getService: function (run) {\n if (typeof run === 'string') {\n return new RunService($.extend(true, {}, this.options, { filter: run }));\n }\n\n if (typeof run === 'object' && run instanceof RunService) {\n return run;\n }\n\n throw new Error('Save method requires a run service or a runId');\n },\n\n getRun: function (runId) {\n return new RunService($.extend(true, {}, this.options, { filter: runId }));\n }\n};\n\nmodule.exports = ScenarioManager;\n\n","/**\n* ## Run Manager\n*\n* The Run Manager gives you access to runs for your project. This allows you to read and update variables, call operations, etc. Additionally, the Run Manager gives you control over run creation depending on run states. Specifically, you can select [run creation strategies (rules)](../../strategy/) for which runs end users of your project work with when they log in to your project.\n*\n* There are many ways to create new runs, including the Epicenter.js [Run Service](../run-api-service/), the RESFTful [Run API](../../../rest_apis/aggregate_run_api) and the [Model Run API](../../../rest_apis/other_apis/model_apis/run/). However, for some projects it makes more sense to pick up where the user left off, using an existing run. And in some projects, whether to create a new run or use an existing one is conditional, for example based on characteristics of the existing run or your own knowledge about the model. The Run Manager provides this level of control: your call to `getRun()`, rather than always returning a new run, returns a run based on the strategy you've specified. (Note that many of the Epicenter sample projects use a Run Service directly, because generally the sample projects are played in one end user session and don't care about run states or run strategies.)\n*\n*\n* ### Using the Run Manager to create and access runs\n*\n* To use the Run Manager, instantiate it by passing in:\n*\n* * `run`: (required) Run object. Must contain:\n* * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n* * `project`: Epicenter project id.\n* * `model`: The name of your primary model file. (See more on [Writing your Model](../../../writing_your_model/).)\n* * `scope`: (optional) Scope object for the run, for example `scope.group` with value of the name of the group.\n* * `server`: (optional) An object with one field, `host`. The value of `host` is the string `api.forio.com`, the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n* * `files`: (optional) If and only if you are using a Vensim model and you have additional data to pass in to your model, you can pass a `files` object with the names of the files, for example: `\"files\": {\"data\": \"myExtraData.xls\"}`. (Note that you'll also need to add this same files object to your Vensim [configuration file](../../../model_code/vensim/).) See the [underlying Model Run API](../../../rest_apis/other_apis/model_apis/run/#post-creating-a-new-run-for-this-project) for additional information.\n*\n* * `strategy`: (optional) Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n*\n* * `sessionKey`: (optional) Name of browser cookie in which to store run information, including run id. Many conditional strategies, including the provided strategies, rely on this browser cookie to store the run id and help make the decision of whether to create a new run or use an existing one. The name of this cookie defaults to `epicenter-scenario` and can be set with the `sessionKey` parameter.\n*\n*\n* After instantiating a Run Manager, make a call to `getRun()` whenever you need to access a run for this end user. The `RunManager.run` contains the instantiated [Run Service](../run-api-service/). The Run Service allows you to access variables, call operations, etc.\n*\n* **Example**\n*\n* var rm = new F.manager.RunManager({\n* run: {\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* model: 'supply-chain-model.jl',\n* server: { host: 'api.forio.com' }\n* },\n* strategy: 'always-new',\n* sessionKey: 'epicenter-session'\n* });\n* rm.getRun()\n* .then(function(run) {\n* // the return value of getRun() is a run object\n* var thisRunId = run.id;\n* // the RunManager.run also contains the instantiated Run Service,\n* // so any Run Service method is valid here\n* rm.run.do('runModel');\n* })\n*\n*/\n\n'use strict';\nvar strategiesMap = require('./run-strategies/strategies-map');\nvar specialOperations = require('./special-operations');\nvar RunService = require('../service/run-api-service');\n\n\nfunction patchRunService(service, manager) {\n if (service.patched) {\n return service;\n }\n\n var orig = service.do;\n service.do = function (operation, params, options) {\n var reservedOps = Object.keys(specialOperations);\n if (reservedOps.indexOf(operation) === -1) {\n return orig.apply(service, arguments);\n } else {\n return specialOperations[operation].call(service, params, options, manager);\n }\n };\n\n service.patched = true;\n\n return service;\n}\n\n\n\nvar defaults = {\n /**\n * Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n * @type {String}\n */\n\n strategy: 'new-if-initialized'\n};\n\nfunction RunManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n if (this.options.run instanceof RunService) {\n this.run = this.options.run;\n } else {\n this.run = new RunService(this.options.run);\n }\n\n patchRunService(this.run, this);\n\n var StrategyCtor = typeof this.options.strategy === 'function' ? this.options.strategy : strategiesMap[this.options.strategy];\n\n if (!StrategyCtor) {\n throw new Error('Specified run creation strategy was invalid:', this.options.strategy);\n }\n\n this.strategy = new StrategyCtor(this.run, this.options);\n}\n\nRunManager.prototype = {\n /**\n * Returns the run object for a 'good' run.\n *\n * A good run is defined by the strategy. For example, if the strategy is `always-new`, the call\n * to `getRun()` always returns a newly created run; if the strategy is `new-if-persisted`,\n * `getRun()` creates a new run if the previous run is in a persisted state, otherwise\n * it returns the previous run. See [Run Manager Strategies](../../strategy/) for more on strategies.\n *\n * **Example**\n *\n * rm.getRun().then(function (run) {\n * // use the run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * @return {$promise} Promise to complete the call.\n */\n getRun: function () {\n return this.strategy\n .getRun();\n },\n\n /**\n * Returns the run object for a new run, regardless of strategy: force creation of a new run.\n *\n * **Example**\n *\n * rm.reset().then(function (run) {\n * // use the (new) run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * **Parameters**\n * @param {Object} `runServiceOptions` The options object to configure the Run Service. See [Run API Service](../run-api-service/) for more.\n */\n reset: function (runServiceOptions) {\n return this.strategy.reset(runServiceOptions);\n }\n};\n\nmodule.exports = RunManager;\n","/**\n* ## Authorization Manager\n*\n* The Authorization Manager provides an easy way to manage user authentication (logging in and out) and authorization (keeping track of tokens, sessions, and groups) for projects.\n*\n* The Authorization Manager is most useful for [team projects](../../../glossary/#team) with an access level of [Authenticated](../../../glossary/#access). These projects are accessed by [end users](../../../glossary/#users) who are members of one or more [groups](../../../glossary/#groups).\n*\n* #### Using the Authorization Manager\n*\n* To use the Authorization Manager, instantiate it. Then, make calls to any of the methods you need:\n*\n* var authMgr = new F.manager.AuthManager({\n* account: 'acme-simulations',\n* userName: 'enduser1',\n* password: 'passw0rd'\n* });\n* authMgr.login().then(function () {\n* authMgr.getCurrentUserSessionInfo();\n* });\n*\n*\n* The `options` object passed to the `F.manager.AuthManager()` call can include:\n*\n* * `account`: The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects).\n* * `userName`: Email or username to use for logging in.\n* * `password`: Password for specified `userName`.\n* * `project`: The **Project ID** for the project to log this user into. Optional.\n* * `groupId`: Id of the group to which `userName` belongs. Required for end users if the `project` is specified.\n*\n* If you prefer starting from a template, the Epicenter JS Libs [Login Component](../../#components) uses the Authorization Manager as well. This sample HTML page (and associated CSS and JS files) provides a login form for team members and end users of your project. It also includes a group selector for end users that are members of multiple groups.\n*/\n\n'use strict';\nvar AuthAdapter = require('../service/auth-api-service');\nvar MemberAdapter = require('../service/member-api-adapter');\nvar SessionManager = require('../store/session-manager');\nvar Buffer = require('buffer').Buffer;\nvar _pick = require('../util/object-util')._pick;\n\nvar defaults = {\n requiresGroup: true\n};\n\nfunction AuthManager(options) {\n options = $.extend(true, {}, defaults, options);\n this.sessionManager = new SessionManager(options);\n this.options = this.sessionManager.getMergedOptions();\n\n this.isLocal = this.options.isLocal;\n this.authAdapter = new AuthAdapter(this.options);\n}\n\nvar _findUserInGroup = function (members, id) {\n for (var j = 0; j 1) {\n if (groupId) {\n var filteredGroups = $.grep(memberInfo, function (resGroup) {\n return resGroup.groupId === groupId;\n });\n group = filteredGroups.length === 1 ? filteredGroups[0] : null;\n }\n }\n\n if (group) {\n var groupData = {\n 'groupId': group.groupId,\n 'groupName': group.name,\n 'isFac': _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator'\n };\n var sessionInfoWithGroup = $.extend({}, sessionInfo, groupData);\n sessionInfo.groups[project] = groupData;\n _this.sessionManager.saveSession(sessionInfoWithGroup, adapterOptions);\n outSuccess.apply(this, [data]);\n $d.resolve(data);\n } else {\n handleGroupError('This user is associated with more than one group. Please specify a group id to log into and try again', 403, data);\n }\n }).fail($d.reject);\n };\n\n adapterOptions.success = handleSuccess;\n adapterOptions.error = function (response) {\n if (adapterOptions.account) {\n // Try to login as a system user\n adapterOptions.account = null;\n adapterOptions.error = function () {\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n _this.authAdapter.login(adapterOptions);\n return;\n }\n\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n this.authAdapter.login(adapterOptions);\n return $d.promise();\n },\n\n /**\n * Logs user out by clearing all session information.\n *\n * **Example**\n *\n * authMgr.logout();\n *\n * **Parameters**\n *\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var _this = this;\n var adapterOptions = this.sessionManager.getMergedOptions(options);\n\n var removeCookieFn = function (response) {\n _this.sessionManager.removeSession();\n };\n\n return this.authAdapter.logout(adapterOptions).done(removeCookieFn);\n },\n\n /**\n * Returns the existing user access token if the user is already logged in. Otherwise, logs the user in, creating a new user access token, and returns the new token. (See [more background on access tokens](../../../project_access/)).\n *\n * **Example**\n *\n * authMgr.getToken()\n * .then(function (token) {\n * console.log('My token is ', token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getToken: function (options) {\n var httpOptions = this.sessionManager.getMergedOptions(options);\n\n var session = this.sessionManager.getSession();\n var $d = $.Deferred();\n //jshint camelcase: false\n //jscs:disable\n if (session.auth_token) {\n $d.resolve(session.auth_token);\n } else {\n this.login(httpOptions).then($d.resolve);\n }\n return $d.promise();\n },\n\n /**\n * Returns an array of group records, one for each group of which the current user is a member. Each group record includes the group `name`, `account`, `project`, and `groupId`.\n *\n * If some end users in your project are members of multiple groups, this is a useful method to call on your project's login page. When the user attempts to log in, you can use this to display the groups of which the user is member, and have the user select the correct group to log in to for this session.\n *\n * **Example**\n *\n * // get groups for current user\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n * authMgr.getUserGroups({ userId: sessionObj.userId, token: sessionObj.auth_token })\n * .then(function (groups) {\n * for (var i=0; i < groups.length; i++)\n * { console.log(groups[i].name); }\n * });\n *\n * // get groups for particular user\n * authMgr.getUserGroups({userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', token: savedProjAccessToken });\n *\n * **Parameters**\n * @param {Object} `params` Object with a userId and token properties.\n * @param {String} `params.userId` The userId. If looking up groups for the currently logged in user, this is in the session information. Otherwise, pass a string.\n * @param {String} `params.token` The authorization credentials (access token) to use for checking the groups for this user. If looking up groups for the currently logged in user, this is in the session information. A team member's token or a project access token can access all the groups for all end users in the team or project.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getUserGroups: function (params, options) {\n var adapterOptions = this.sessionManager.getMergedOptions({ success: $.noop }, options);\n var $d = $.Deferred();\n var outSuccess = adapterOptions.success;\n\n adapterOptions.success = function (memberInfo) {\n // The member API is at the account scope, we filter by project\n if (adapterOptions.project) {\n memberInfo = $.grep(memberInfo, function (group) {\n return group.project === adapterOptions.project;\n });\n }\n\n outSuccess.apply(this, [memberInfo]);\n $d.resolve(memberInfo);\n };\n\n var memberAdapter = new MemberAdapter({ token: params.token });\n memberAdapter.getGroupsForUser(params, adapterOptions).fail($d.reject);\n return $d.promise();\n },\n\n /**\n * Returns session information for the current user, including the `userId`, `account`, `project`, `groupId`, `groupName`, `isFac` (whether the end user is a facilitator of this group), and `auth_token` (user access token).\n *\n * *Important*: This method is synchronous. The session information is returned immediately in an object; no callbacks or promises are needed.\n *\n * Session information is stored in a cookie in the browser.\n *\n * **Example**\n *\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getCurrentUserSessionInfo: function (options) {\n return this.sessionManager.getSession(options);\n },\n\n // (replace with /* */ comment block, to make visible in docs, once EPICENTER-1939 is complete)\n //\n // Add one or more groups to the current session. \n //\n // This method assumes that the project and group exist and the user specified in the session is part of this project and group.\n //\n // Returns the new session object.\n //\n // **Example**\n //\n // authMgr.addGroups({ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' });\n // authMgr.addGroups([{ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' }, { project: ... }]);\n //\n // **Parameters**\n // @param {object|array} `groups` (Required) The group object must contain the `project` (**Project ID**) and `groupName` properties.\n // @param {string} `group.isFac` (optional) Defaults to `false`. Set to `true` if the user in the session should be a facilitator in this group.\n // @param {string} `group.groupId` (optional) Defaults to undefined. Needed mostly for the Members API.\n //\n addGroups: function (groups) {\n var session = this.getCurrentUserSessionInfo();\n var isArray = Array.isArray(groups);\n groups = isArray ? groups : [groups];\n\n $.each(groups, function (index, group) {\n var extendedGroup = $.extend({}, { isFac: false }, group);\n var project = extendedGroup.project;\n var validProps = ['groupName', 'groupId', 'isFac'];\n if (!project || !extendedGroup.groupName) {\n throw new Error('No project or groupName specified.');\n }\n // filter object\n extendedGroup = _pick(extendedGroup, validProps);\n session.groups[project] = extendedGroup;\n });\n this.sessionManager.saveSession(session);\n return session;\n }\n});\n\nmodule.exports = AuthManager;\n","/**\n* ## World Manager\n*\n* As discussed under the [World API Adapter](../world-api-adapter/), a [run](../../../glossary/#run) is a collection of end user interactions with a project and its model. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases.\n*\n* The World Manager provides an easy way to track and access the current world and run for particular end users. It is typically used in pages that end users will interact with. (The related [World API Adapter](../world-api-adapter/) handles creating multiplayer worlds, and adding and removing end users and runs from a world. Because of this, typically the World Adapter is used for facilitator pages in your project.)\n*\n* ### Using the World Manager\n*\n* To use the World Manager, instantiate it. Then, make calls to any of the methods you need.\n*\n* When you instantiate a World Manager, the world's account id, project id, and group are automatically taken from the session (thanks to the [Authentication Service](../auth-api-service)).\n*\n* Note that the World Manager does *not* create worlds automatically. (This is different than the [Run Manager](../run-manager).) However, you can pass in specific options to any runs created by the manager, using a `run` object.\n*\n* The parameters for creating a World Manager are:\n*\n* * `account`: The **Team ID** in the Epicenter user interface for this project.\n* * `project`: The **Project ID** for this project.\n* * `group`: The **Group Name** for this world.\n* * `run`: Options to use when creating new runs with the manager, e.g. `run: { files: ['data.xls'] }`.\n* * `run.model`: The name of the primary model file for this project. Required if you have not already passed it in as part of the `options` parameter for an enclosing call.\n*\n* For example:\n*\n* var wMgr = new F.manager.WorldManager({\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* run: { model: 'supply-chain.py' },\n* group: 'team1'\n* });\n*\n* wMgr.getCurrentRun();\n*/\n\n'use strict';\n\nvar WorldApi = require('../service/world-api-adapter');\nvar RunManager = require('./run-manager');\nvar AuthManager = require('./auth-manager');\nvar worldApi;\n\n// var defaults = {\n// account: '',\n// project: '',\n// group: '',\n// transport: {\n// }\n// };\n\n\nfunction buildStrategy(worldId, dtd) {\n\n return function Ctor(runService, options) {\n this.runService = runService;\n this.options = options;\n\n $.extend(this, {\n reset: function () {\n throw new Error('not implementd. Need api changes');\n },\n\n getRun: function () {\n var _this = this;\n //get or create!\n // Model is required in the options\n var model = this.options.run.model || this.options.model;\n return worldApi.getCurrentRunId({ model: model, filter: worldId })\n .then(function (runId) {\n return _this.runService.load(runId);\n })\n .then(function (run) {\n dtd.resolve.call(this, run, _this.runService);\n })\n .fail(dtd.reject);\n }\n }\n );\n };\n}\n\n\nmodule.exports = function (options) {\n this.options = options || { run: {}, world: {} };\n\n $.extend(true, this.options, this.options.run);\n $.extend(true, this.options, this.options.world);\n\n worldApi = new WorldApi(this.options);\n this._auth = new AuthManager();\n var _this = this;\n\n var api = {\n\n /**\n * Returns the current world (object) and an instance of the [World API Adapter](../world-api-adapter/).\n *\n * **Example**\n *\n * wMgr.getCurrentWorld()\n * .then(function(world, worldAdapter) {\n * console.log(world.id);\n * worldAdapter.getCurrentRunId();\n * });\n *\n * **Parameters**\n * @param {string} `userId` (Optional) The id of the user whose world is being accessed. Defaults to the user in the current session.\n * @param {string} `groupName` (Optional) The name of the group whose world is being accessed. Defaults to the group for the user in the current session.\n */\n getCurrentWorld: function (userId, groupName) {\n var session = this._auth.getCurrentUserSessionInfo();\n if (!userId) {\n userId = session.userId;\n }\n if (!groupName) {\n groupName = session.groupName;\n }\n return worldApi.getCurrentWorldForUser(userId, groupName);\n },\n\n /**\n * Returns the current run (object) and an instance of the [Run API Service](../run-api-service/).\n *\n * **Example**\n *\n * wMgr.getCurrentRun({model: 'myModel.py'})\n * .then(function(run, runService) {\n * console.log(run.id);\n * runService.do('startGame');\n * });\n *\n * **Parameters**\n * @param {string} `model` (Optional) The name of the model file. Required if not already passed in as `run.model` when the World Manager is created.\n */\n getCurrentRun: function (model) {\n var dtd = $.Deferred();\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n function getAndRestoreLatestRun(world) {\n if (!world) {\n return dtd.reject({ error: 'The user is not part of any world!' });\n }\n\n var currentWorldId = world.id;\n var runOpts = $.extend(true, _this.options, { model: model });\n var strategy = buildStrategy(currentWorldId, dtd);\n var opt = $.extend(true, {}, {\n strategy: strategy,\n run: runOpts\n });\n var rm = new RunManager(opt);\n\n return rm.getRun()\n .then(function (run) {\n dtd.resolve(run, rm.runService, rm);\n });\n }\n\n this.getCurrentWorld(curUserId, curGroupName)\n .then(getAndRestoreLatestRun);\n\n return dtd.promise();\n }\n };\n\n $.extend(this, api);\n};\n","'use strict';\n\n/**\n * ## Epicenter Channel Manager\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Epicenter Channel Manager is a wrapper around the (more generic) [Channel Manager](../channel-manager/), to instantiate it with Epicenter-specific defaults. If you are interested in including a notification or chat feature in your project, using an Epicenter Channel Manager is probably the easiest way to get started.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Epicenter Channel Manager. See [Including Epicenter.js](../../#include).\n *\n * To use the Epicenter Channel Manager: instantiate it, get the channel of the scope you want ([user](../../../glossary/#users), [world](../../../glossary/#world), or [group](../../../glossary/#groups)), then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.\n *\n * The parameters for instantiating an Epicenter Channel Manager include:\n *\n * * `options` Object with details about the Epicenter project for this Epicenter Channel Manager instance.\n * * `options.account` The Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `options.project` Epicenter project id.\n * * `options.userName` Epicenter userName used for authentication.\n * * `options.userId` Epicenter user id used for authentication. Optional; `options.userName` is preferred.\n * * `options.token` Epicenter token used for authentication. (You can retrieve this using `authManager.getToken()` from the [Authorization Manager](../auth-manager/).)\n * * `options.allowAllChannels` If not included or if set to `false`, all channel paths are validated; if your project requires [Push Channel Authorization](../../../updating_your_settings/), you should use this option. If you want to allow other channel paths, set to `true`; this is not common.\n */\n\nvar ChannelManager = require('./channel-manager');\nvar classFrom = require('../util/inherit');\nvar urlService = require('../service/url-config-service');\nvar SessionManager = require('../store/session-manager');\n\nvar AuthManager = require('./auth-manager');\n\nvar validTypes = {\n project: true,\n group: true,\n world: true,\n user: true,\n data: true,\n general: true,\n chat: true\n};\nvar session = new AuthManager();\nvar getFromSettingsOrSessionOrError = function (value, sessionKeyName, settings) {\n if (!value) {\n var userInfo = session.getCurrentUserSessionInfo();\n if (settings && settings[sessionKeyName]) {\n value = settings[sessionKeyName];\n } else if (userInfo[sessionKeyName]) {\n value = userInfo[sessionKeyName];\n } else {\n throw new Error(sessionKeyName + ' not found. Please log-in again, or specify ' + sessionKeyName + ' explicitly');\n }\n }\n return value;\n};\nvar __super = ChannelManager.prototype;\nvar EpicenterChannelManager = classFrom(ChannelManager, {\n constructor: function (options) {\n this.sessionManager = new SessionManager();\n var defaultCometOptions = this.sessionManager.getMergedOptions(options);\n\n var urlOpts = urlService(defaultCometOptions.server);\n if (!defaultCometOptions.url) {\n //Default epicenter cometd endpoint\n defaultCometOptions.url = urlOpts.protocol + '://' + urlOpts.host + '/channel/subscribe';\n }\n\n if (defaultCometOptions.handshake === undefined) {\n var userName = defaultCometOptions.userName;\n var userId = defaultCometOptions.userId;\n var token = defaultCometOptions.token;\n if ((userName || userId) && token) {\n var userProp = userName ? 'userName' : 'userId';\n var ext = {\n authorization: 'Bearer ' + token\n };\n ext[userProp] = userName ? userName : userId;\n\n defaultCometOptions.handshake = {\n ext: ext\n };\n }\n }\n\n this.options = defaultCometOptions;\n return __super.constructor.call(this, defaultCometOptions);\n },\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * This method enforces Epicenter-specific channel naming: all channels requested must be in the form `/{type}/{account id}/{project id}/{...}`, where `type` is one of `run`, `data`, `user`, `world`, or `chat`.\n *\n * **Example**\n *\n * var cm = new F.manager.EpicenterChannelManager();\n * var channel = cm.getChannel('/group/acme/supply-chain-game/');\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} `options` (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n */\n getChannel: function (options) {\n if (options && typeof options !== 'object') {\n options = {\n base: options\n };\n }\n var channelOpts = $.extend({}, this.options, options);\n var base = channelOpts.base;\n if (!base) {\n throw new Error('No base topic was provided');\n }\n\n if (!channelOpts.allowAllChannels) {\n var baseParts = base.split('/');\n var channelType = baseParts[1];\n if (baseParts.length < 4) {\n throw new Error('Invalid channel base name, it must be in the form /{type}/{account id}/{project id}/{...}');\n }\n if (!validTypes[channelType]) {\n throw new Error('Invalid channel type');\n }\n }\n return __super.getChannel.apply(this, arguments);\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [group](../../../glossary/#groups). The group must exist in the account (team) and project provided.\n *\n * There are no notifications from Epicenter on this channel; all messages are user-originated.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `groupName` (Optional) Group to broadcast to. If not provided, picks up group from current session if end user is logged in.\n */\n getGroupChannel: function (groupName) {\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/group', account, project, groupName].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var worldChannel = cm.getWorldChannel(worldObject);\n * worldChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` The world object or id.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getWorldChannel: function (world, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/world', account, project, groupName, worldid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the current [end user](../../../glossary/#users) in that user's current [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager). Note that this channel only gets notifications for worlds currently in memory. (See more background on [persistence](../../../run_persistence).)\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var userChannel = cm.getUserChannel(worldObject);\n * userChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `user` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getUserChannel: function (world, user, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n var userid = ($.isPlainObject(user) && user.id) ? user.id : user;\n userid = getFromSettingsOrSessionOrError(userid, 'userId', this.options);\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/user', account, project, groupName, worldid, userid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) that automatically tracks the presence of an [end user](../../../glossary/#users), that is, whether the end user is currently online in this group and world. Notifications are automatically sent when the end user comes online, and when the end user goes offline (not present for more than 2 minutes). Useful in multiplayer games for letting each end user know whether other users in their shared world are also online.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'model.eqn'\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldService) {\n * var presenceChannel = cm.getPresenceChannel(worldObject);\n * presenceChannel.on('presence', function (evt, notification) {\n * console.log(notification.online, notification.userId);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `userid` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getPresenceChannel: function (world, userid, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n userid = getFromSettingsOrSessionOrError(userid, 'userId', this.options);\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/user', account, project, groupName, worldid].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n var lastPingTime = { };\n\n var PING_INTERVAL = 6000;\n channel.subscribe('internal-ping-channel', function (notification) {\n var incomingUserId = notification.data.user;\n if (!lastPingTime[incomingUserId] && incomingUserId !== userid) {\n channel.trigger.call(channel, 'presence', { userId: incomingUserId, online: true });\n }\n lastPingTime[incomingUserId] = (new Date()).valueOf();\n });\n\n setInterval(function () {\n channel.publish('internal-ping-channel', { user: userid });\n\n $.each(lastPingTime, function (key, value) {\n var now = (new Date()).valueOf();\n if (value && value + (PING_INTERVAL * 2) < now) {\n lastPingTime[key] = null;\n channel.trigger.call(channel, 'presence', { userId: key, online: false });\n }\n });\n }, PING_INTERVAL);\n\n return channel;\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given collection. (The collection name is specified in the `root` argument when the [Data Service](../data-api-service/) is instantiated.) Must be one of the collections in this account (team) and project.\n *\n * There are automatic notifications from Epicenter on this channel when data is created, updated, or deleted in this collection. See more on [automatic messages to the data channel](../../../rest_apis/multiplayer/channel/#data-messages).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var dc = cm.getDataChannel('survey-responses');\n * dc.subscribe('', function(data, meta) {\n * console.log(data);\n *\n * // meta.date is time of change,\n * // meta.subType is the kind of change: new, update, or delete\n * // meta.path is the full path to the changed data\n * console.log(meta);\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `collection` Name of collection whose automatic notifications you want to receive.\n */\n getDataChannel: function (collection) {\n if (!collection) {\n throw new Error('Please specify a collection to listen on.');\n }\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n var baseTopic = ['/data', account, project, collection].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n //TODO: Fix after Epicenter bug is resolved\n var oldsubs = channel.subscribe;\n channel.subscribe = function (topic, callback, context, options) {\n var callbackWithCleanData = function (payload) {\n var meta = {\n path: payload.channel,\n subType: payload.data.subType,\n date: payload.data.date\n };\n var actualData = payload.data.data;\n if (actualData.data) { //Delete notifications are one data-level behind of course\n actualData = actualData.data;\n }\n\n callback.call(context, actualData, meta);\n };\n return oldsubs.call(channel, topic, callbackWithCleanData, context, options);\n };\n\n return channel;\n }\n});\n\nmodule.exports = EpicenterChannelManager;\n","'use strict';\n\n/**\n * ## Channel Service\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Service is a building block for this functionality. It creates a publish-subscribe object, allowing you to publish messages, subscribe to messages, or unsubscribe from messages for a given 'topic' on a `$.cometd` transport instance.\n *\n * Typically, you use the [Epicenter Channel Manager](../epicenter-channel-manager/) to create or retrieve channels, then use the Channel Service `subscribe()` and `publish()` methods to listen to or update data. (For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.)\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Service. See [Including Epicenter.js](../../#include).\n *\n * To use the Channel Service, instantiate it, then make calls to any of the methods you need.\n *\n * var cs = new F.service.Channel();\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * The parameters for instantiating a Channel Service include:\n *\n * * `options` The options object to configure the Channel Service.\n * * `options.base` The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * * `options.topicResolver` A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. Returns a String. By default, it just echoes the topic.\n * * `options.transport` The instance of `$.cometd` to hook onto. See http://docs.cometd.org/reference/javascript.html for additional background on cometd.\n */\nvar Channel = function (options) {\n var defaults = {\n\n /**\n * The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * @type {string}\n */\n base: '',\n\n /**\n * A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. By default, it just echoes the topic.\n *\n * **Parameters**\n *\n * * `topic` Topic to parse.\n *\n * **Return Value**\n *\n * * *String*: This function should return a string topic.\n *\n * @type {function}\n */\n topicResolver: function (topic) {\n return topic;\n },\n\n /**\n * The instance of `$.cometd` to hook onto.\n * @type {object}\n */\n transport: null\n };\n this.channelOptions = $.extend(true, {}, defaults, options);\n};\n\nvar makeName = function (channelName, topic) {\n //Replace trailing/double slashes\n var newName = (channelName ? (channelName + '/' + topic) : topic).replace(/\\/\\//g, '/').replace(/\\/$/,'');\n return newName;\n};\n\n\nChannel.prototype = $.extend(Channel.prototype, {\n\n // future functionality:\n // // Set the context for the callback\n // cs.subscribe('run', function () { this.innerHTML = 'Triggered'}, document.body);\n //\n // // Control the order of operations by setting the `priority`\n // cs.subscribe('run', cb, this, {priority: 9});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is 50\n // cs.subscribe('run/variables/price', cb, this, {priority: 30, value: 50});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is greater than 50\n // subscribe('run/variables/price', cb, this, {priority: 30, value: '>50'});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is even\n // subscribe('run/variables/price', cb, this, {priority: 30, value: function (val) {return val % 2 === 0}});\n\n\n /**\n * Subscribe to changes on a topic.\n *\n * The topic should include the full path of the account id (**Team ID** for team projects), project id, and group name. (In most cases, it is simpler to use the [Epicenter Channel Manager](../epicenter-channel-manager/) instead, in which case this is configured for you.)\n *\n * **Examples**\n *\n * var cb = function(val) { console.log(val.data); };\n *\n * // Subscribe to changes on a top-level 'run' topic\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run', cb);\n *\n * // Subscribe to changes on children of the 'run' topic. Note this will also be triggered for changes to run.x.y.z.\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/*', cb);\n *\n * // Subscribe to changes on both the top-level 'run' topic and its children\n * cs.subscribe(['/acme-simulations/supply-chain-game/fall-seminar/run',\n * '/acme-simulations/supply-chain-game/fall-seminar/run/*'], cb);\n *\n * // Subscribe to changes on a particular variable\n * subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/variables/price', cb);\n *\n *\n * **Return Value**\n *\n * * *String* Returns a token you can later use to unsubscribe.\n *\n * **Parameters**\n * @param {String|Array} `topic` List of topics to listen for changes on.\n * @param {Function} `callback` Callback function to execute. Callback is called with signature `(evt, payload, metadata)`.\n * @param {Object} `context` Context in which the `callback` is executed.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n * @param {Number} `options.priority` Used to control order of operations. Defaults to 0. Can be any +ve or -ve number.\n * @param {String|Number|Function} `options.value` The `callback` is only triggered if this condition matches. See examples for details.\n *\n */\n subscribe: function (topic, callback, context, options) {\n\n var topics = [].concat(topic);\n var me = this;\n var subscriptionIds = [];\n var opts = me.channelOptions;\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n subscriptionIds.push(opts.transport.subscribe(topic, callback));\n });\n });\n return (subscriptionIds[1] ? subscriptionIds : subscriptionIds[0]);\n },\n\n /**\n * Publish data to a topic.\n *\n * **Examples**\n *\n * // Send data to all subscribers of the 'run' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run', { completed: false });\n *\n * // Send data to all subscribers of the 'run/variables' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * **Parameters**\n *\n * @param {String} `topic` Topic to publish to.\n * @param {*} `data` Data to publish to topic.\n *\n */\n publish: function (topic, data) {\n var topics = [].concat(topic);\n var me = this;\n var returnObjs = [];\n var opts = me.channelOptions;\n\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n if (topic.charAt(topic.length - 1) === '*') {\n topic = topic.replace(/\\*+$/, '');\n console.warn('You can cannot publish to channels with wildcards. Publishing to ', topic, 'instead');\n }\n returnObjs.push(opts.transport.publish(topic, data));\n });\n });\n return (returnObjs[1] ? returnObjs : returnObjs[0]);\n },\n\n /**\n * Unsubscribe from changes to a topic.\n *\n * **Example**\n *\n * cs.unsubscribe('sampleToken');\n *\n * **Parameters**\n * @param {String} `token` The token for topic is returned when you initially subscribe. Pass it here to unsubscribe from that topic.\n */\n unsubscribe: function (token) {\n this.channelOptions.transport.unsubscribe(token);\n return token;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n\n});\n\nmodule.exports = Channel;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // always create a new run!\n return true;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar makeSeq = require('../../util/make-sequence');\nvar Base = require('./identity-strategy');\nvar SessionStore = require('../../store/store-factory');\nvar classFrom = require('../../util/inherit');\nvar UrlService = require('../../service/url-config-service');\nvar AuthManager = require('../auth-manager');\n\nvar sessionStore = new SessionStore({});\nvar urlService = new UrlService();\nvar keyNames = require('../key-names');\n\nvar defaults = {\n sessionKey: keyNames.STRATEGY_SESSION_KEY,\n path: ''\n};\n\nfunction setRunInSession(sessionKey, run, path) {\n if (!path) {\n if (!urlService.isLocalhost()) {\n path = '/' + [urlService.appPath, urlService.accountPath, urlService.projectPath].join('/');\n // make sure we don't get consecuteive '/' so we have a valid path for the session\n path = path.replace(/\\/{2,}/g,'/');\n } else {\n path = '';\n }\n }\n // set the seesionKey for the run\n sessionStore.set(sessionKey, JSON.stringify({ runId: run.id }), { root: path });\n}\n\n/**\n* Conditional Creation Strategy\n* This strategy will try to get the run stored in the cookie and\n* evaluate if needs to create a new run by calling the 'condition' function\n*/\n\n/* jshint eqnull: true */\nvar Strategy = classFrom(Base, {\n constructor: function Strategy(runService, condition, options) {\n\n if (condition == null) {\n throw new Error('Conditional strategy needs a condition to createte a run');\n }\n\n this._auth = new AuthManager();\n this.run = makeSeq(runService);\n this.condition = typeof condition !== 'function' ? function () { return condition; } : condition;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n },\n\n runOptionsWithScope: function () {\n var userSession = this._auth.getCurrentUserSessionInfo();\n return $.extend({\n scope: { group: userSession.groupName }\n }, this.runOptions);\n },\n\n reset: function (runServiceOptions) {\n var _this = this;\n var opt = this.runOptionsWithScope();\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run, _this.options.path);\n run.freshlyCreated = true;\n return run;\n })\n .start();\n },\n\n getRun: function () {\n var runSession = JSON.parse(sessionStore.get(this.options.sessionKey));\n\n if (runSession && runSession.runId) {\n return this._loadAndCheck(runSession);\n } else {\n return this.reset();\n }\n },\n\n _loadAndCheck: function (runSession) {\n var shouldCreate = false;\n var _this = this;\n\n return this.run\n .load(runSession.runId, null, {\n success: function (run, msg, headers) {\n shouldCreate = _this.condition.call(_this, run, headers);\n }\n })\n .then(function (run) {\n if (shouldCreate) {\n var opt = _this.runOptionsWithScope();\n // we need to do this, on the original runService (ie not sequencialized)\n // so we don't get in the middle of the queue\n return _this.run.original.create(opt)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run);\n run.freshlyCreated = true;\n return run;\n });\n }\n\n return run;\n })\n .start();\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar Base = {};\n\n// Interface that all strategies need to implement\nmodule.exports = classFrom(Base, {\n constructor: function (runService, options) {\n this.runService = runService;\n },\n\n reset: function () {\n // return a newly created run\n return $.Deferred().resolve().promise();\n },\n\n getRun: function () {\n // return a usable run\n return $.Deferred().resolve(this.runService).promise();\n }\n});\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\n/*\n* create a new run only if nothing is stored in the cookie\n* this is useful for baseRuns.\n*/\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // if we are here, it means that the run exists... so we don't need a new one\n return false;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent';\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent' || run.initialized;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nmodule.exports = {\n _pick: function (obj, props) {\n var res = {};\n for (var p in obj) {\n if (props.indexOf(p) !== -1) {\n res[p] = obj[p];\n }\n }\n\n return res;\n }\n};\n","/**\n *\n * ## Introspection API Service\n *\n * Used in conjunction with the [Run API Service](../run-api-service/) to access Native DMS 3 Introspection calls\n *\n * var rm = new F.manager.RunManager({\n * run: {\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'supply-chain-model.jl'\n * }\n * });\n * rm.getRun()\n * .then(function() {\n * var is = rm.run.introspection();\n * });\n *\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var defaults = {\n server: {\n versionPath: 'v3/'\n }\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n urlConfig.filter = ';';\n\n var httpOptions = {\n url: urlConfig.getAPIPath('model') + 'publish'\n };\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAPI = {\n /**\n * Get the available Functions and Variables\n *\n * **Example**\n *\n * vs.get()\n * .then(function(data) {\n * // data contains an object with available functions (used with operations API) and available variables (used with variables API)\n * console.log(data.functions);\n * console.log(data.variables);\n * });\n *\n * **Parameters**\n * @param {String} `runId` (Optional) Overrides the run id used when the service was created\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n get: function (runId, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n var params = {\n runId: runId || httpOptions.filter,\n commandWrapper: { command: { introspect: {} } },\n reanimate: false\n };\n return http.post(params, httpOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","'use strict';\n\nvar keyNames = require('../managers/key-names');\nvar StorageFactory = require('./store-factory');\nvar optionUtils = require('../util/option-utils');\n\nvar EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY;\nvar defaults = {\n /**\n * Where to store user access tokens for temporary access. Defaults to storing in a cookie in the browser.\n * @type {string}\n */\n store: { synchronous: true }\n};\n\nvar SessionManager = function (managerOptions) {\n managerOptions = managerOptions || {};\n function getBaseOptions(overrides) {\n overrides = overrides || {};\n var libOptions = optionUtils.getOptions();\n var finalOptions = $.extend(true, {}, defaults, libOptions, managerOptions, overrides);\n return finalOptions;\n }\n\n function getStore(overrides) {\n var baseOptions = getBaseOptions(overrides);\n var storeOpts = baseOptions.store || {};\n if (storeOpts.root === undefined && baseOptions.account && baseOptions.project && !baseOptions.isLocal) {\n storeOpts.root = '/app/' + baseOptions.account + '/' + baseOptions.project;\n }\n return new StorageFactory(storeOpts);\n }\n\n var publicAPI = {\n saveSession: function (userInfo, options) {\n var serialized = JSON.stringify(userInfo);\n getStore(options).set(EPI_SESSION_KEY, serialized);\n },\n getSession: function (options) {\n // var session = getStore(options).get(EPI_SESSION_KEY) || '{}';\n // return JSON.parse(session);\n var store = getStore(options);\n var finalOpts = store.serviceOptions;\n var serialized = store.get(EPI_SESSION_KEY) || '{}';\n var session = JSON.parse(serialized);\n // If the url contains the project and account\n // validate the account and project in the session\n // and override project, groupName, groupId and isFac\n // Otherwise (i.e. localhost) use the saved session values\n var account = finalOpts.account;\n var project = finalOpts.project;\n if (account && session.account !== account) {\n // This means that the token was not used to login to the same account\n return {};\n }\n if (session.groups && account && project) {\n var group = session.groups[project] || { groupId: '', groupName: '', isFac: false };\n $.extend(session, { project: project }, group);\n }\n return session;\n },\n removeSession: function (options) {\n return getStore(options).remove(EPI_SESSION_KEY);\n },\n getStore: function (options) {\n return getStore(options);\n },\n\n getMergedOptions: function () {\n var args = Array.prototype.slice.call(arguments);\n var overrides = $.extend.apply($, [true, {}].concat(args));\n var baseOptions = getBaseOptions(overrides);\n var session = this.getSession(overrides);\n\n var sessionDefaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n //jshint camelcase: false\n //jscs:disable\n token: session.auth_token,\n /**\n * The group name. If left undefined, taken from the cookie session.\n * @type {String}\n */\n group: session.groupName,\n /**\n * The group id. If left undefined, taken from the cookie session.\n * @type {String}\n */\n groupId: session.groupId,\n userId: session.userId\n };\n return $.extend(true, sessionDefaults, baseOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n\nmodule.exports = SessionManager;","'use strict';\n\n\nmodule.exports = {\n reset: function (params, options, manager) {\n return manager.reset(options);\n }\n};\n","module.exports = {\n 'new-if-initialized': require('./new-if-initialized-strategy'),\n 'new-if-persisted': require('./new-if-persisted-strategy'),\n 'new-if-missing': require('./new-if-missing-strategy'),\n 'always-new': require('./always-new-strategy'),\n 'multiplayer': require('./multiplayer-strategy'),\n 'persistent-single-player': require('./persistent-single-player-strategy'),\n 'none': require('./identity-strategy')\n};\n","/*!\n * The buffer module from node.js, for the browser.\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\n/* eslint-disable no-proto */\n\n'use strict'\n\nvar base64 = require('base64-js')\nvar ieee754 = require('ieee754')\nvar isArray = require('isarray')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n * === true Use Uint8Array implementation (fastest)\n * === false Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n * incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n ? global.TYPED_ARRAY_SUPPORT\n : typedArraySupport()\n\n/*\n * Export kMaxLength after typed array support is determined.\n */\nexports.kMaxLength = kMaxLength()\n\nfunction typedArraySupport () {\n try {\n var arr = new Uint8Array(1)\n arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}\n return arr.foo() === 42 && // typed array instances can be augmented\n typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n } catch (e) {\n return false\n }\n}\n\nfunction kMaxLength () {\n return Buffer.TYPED_ARRAY_SUPPORT\n ? 0x7fffffff\n : 0x3fffffff\n}\n\nfunction createBuffer (that, length) {\n if (kMaxLength() < length) {\n throw new RangeError('Invalid typed array length')\n }\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = new Uint8Array(length)\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n if (that === null) {\n that = new Buffer(length)\n }\n that.length = length\n }\n\n return that\n}\n\n/**\n * The Buffer constructor returns instances of `Uint8Array` that have their\n * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of\n * `Uint8Array`, so the returned instances will have all the node `Buffer` methods\n * and the `Uint8Array` methods. Square bracket notation works as expected -- it\n * returns a single octet.\n *\n * The `Uint8Array` prototype remains unmodified.\n */\n\nfunction Buffer (arg, encodingOrOffset, length) {\n if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {\n return new Buffer(arg, encodingOrOffset, length)\n }\n\n // Common case.\n if (typeof arg === 'number') {\n if (typeof encodingOrOffset === 'string') {\n throw new Error(\n 'If encoding is specified then the first argument must be a string'\n )\n }\n return allocUnsafe(this, arg)\n }\n return from(this, arg, encodingOrOffset, length)\n}\n\nBuffer.poolSize = 8192 // not used by this implementation\n\n// TODO: Legacy, not needed anymore. Remove in next major version.\nBuffer._augment = function (arr) {\n arr.__proto__ = Buffer.prototype\n return arr\n}\n\nfunction from (that, value, encodingOrOffset, length) {\n if (typeof value === 'number') {\n throw new TypeError('\"value\" argument must not be a number')\n }\n\n if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {\n return fromArrayBuffer(that, value, encodingOrOffset, length)\n }\n\n if (typeof value === 'string') {\n return fromString(that, value, encodingOrOffset)\n }\n\n return fromObject(that, value)\n}\n\n/**\n * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError\n * if value is a number.\n * Buffer.from(str[, encoding])\n * Buffer.from(array)\n * Buffer.from(buffer)\n * Buffer.from(arrayBuffer[, byteOffset[, length]])\n **/\nBuffer.from = function (value, encodingOrOffset, length) {\n return from(null, value, encodingOrOffset, length)\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n Buffer.prototype.__proto__ = Uint8Array.prototype\n Buffer.__proto__ = Uint8Array\n if (typeof Symbol !== 'undefined' && Symbol.species &&\n Buffer[Symbol.species] === Buffer) {\n // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97\n Object.defineProperty(Buffer, Symbol.species, {\n value: null,\n configurable: true\n })\n }\n}\n\nfunction assertSize (size) {\n if (typeof size !== 'number') {\n throw new TypeError('\"size\" argument must be a number')\n }\n}\n\nfunction alloc (that, size, fill, encoding) {\n assertSize(size)\n if (size <= 0) {\n return createBuffer(that, size)\n }\n if (fill !== undefined) {\n // Only pay attention to encoding if it's a string. This\n // prevents accidentally sending in a number that would\n // be interpretted as a start offset.\n return typeof encoding === 'string'\n ? createBuffer(that, size).fill(fill, encoding)\n : createBuffer(that, size).fill(fill)\n }\n return createBuffer(that, size)\n}\n\n/**\n * Creates a new filled Buffer instance.\n * alloc(size[, fill[, encoding]])\n **/\nBuffer.alloc = function (size, fill, encoding) {\n return alloc(null, size, fill, encoding)\n}\n\nfunction allocUnsafe (that, size) {\n assertSize(size)\n that = createBuffer(that, size < 0 ? 0 : checked(size) | 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) {\n for (var i = 0; i < size; ++i) {\n that[i] = 0\n }\n }\n return that\n}\n\n/**\n * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.\n * */\nBuffer.allocUnsafe = function (size) {\n return allocUnsafe(null, size)\n}\n/**\n * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.\n */\nBuffer.allocUnsafeSlow = function (size) {\n return allocUnsafe(null, size)\n}\n\nfunction fromString (that, string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') {\n encoding = 'utf8'\n }\n\n if (!Buffer.isEncoding(encoding)) {\n throw new TypeError('\"encoding\" must be a valid string encoding')\n }\n\n var length = byteLength(string, encoding) | 0\n that = createBuffer(that, length)\n\n that.write(string, encoding)\n return that\n}\n\nfunction fromArrayLike (that, array) {\n var length = checked(array.length) | 0\n that = createBuffer(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nfunction fromArrayBuffer (that, array, byteOffset, length) {\n array.byteLength // this throws if `array` is not a valid ArrayBuffer\n\n if (byteOffset < 0 || array.byteLength < byteOffset) {\n throw new RangeError('\\'offset\\' is out of bounds')\n }\n\n if (array.byteLength < byteOffset + (length || 0)) {\n throw new RangeError('\\'length\\' is out of bounds')\n }\n\n if (length === undefined) {\n array = new Uint8Array(array, byteOffset)\n } else {\n array = new Uint8Array(array, byteOffset, length)\n }\n\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = array\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n that = fromArrayLike(that, array)\n }\n return that\n}\n\nfunction fromObject (that, obj) {\n if (Buffer.isBuffer(obj)) {\n var len = checked(obj.length) | 0\n that = createBuffer(that, len)\n\n if (that.length === 0) {\n return that\n }\n\n obj.copy(that, 0, 0, len)\n return that\n }\n\n if (obj) {\n if ((typeof ArrayBuffer !== 'undefined' &&\n obj.buffer instanceof ArrayBuffer) || 'length' in obj) {\n if (typeof obj.length !== 'number' || isnan(obj.length)) {\n return createBuffer(that, 0)\n }\n return fromArrayLike(that, obj)\n }\n\n if (obj.type === 'Buffer' && isArray(obj.data)) {\n return fromArrayLike(that, obj.data)\n }\n }\n\n throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')\n}\n\nfunction checked (length) {\n // Note: cannot use `length < kMaxLength` here because that fails when\n // length is NaN (which is otherwise coerced to zero.)\n if (length >= kMaxLength()) {\n throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n 'size: 0x' + kMaxLength().toString(16) + ' bytes')\n }\n return length | 0\n}\n\nfunction SlowBuffer (length) {\n if (+length != length) { // eslint-disable-line eqeqeq\n length = 0\n }\n return Buffer.alloc(+length)\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n throw new TypeError('Arguments must be Buffers')\n }\n\n if (a === b) return 0\n\n var x = a.length\n var y = b.length\n\n for (var i = 0, len = Math.min(x, y); i < len; ++i) {\n if (a[i] !== b[i]) {\n x = a[i]\n y = b[i]\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n switch (String(encoding).toLowerCase()) {\n case 'hex':\n case 'utf8':\n case 'utf-8':\n case 'ascii':\n case 'binary':\n case 'base64':\n case 'raw':\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return true\n default:\n return false\n }\n}\n\nBuffer.concat = function concat (list, length) {\n if (!isArray(list)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n\n if (list.length === 0) {\n return Buffer.alloc(0)\n }\n\n var i\n if (length === undefined) {\n length = 0\n for (i = 0; i < list.length; ++i) {\n length += list[i].length\n }\n }\n\n var buffer = Buffer.allocUnsafe(length)\n var pos = 0\n for (i = 0; i < list.length; ++i) {\n var buf = list[i]\n if (!Buffer.isBuffer(buf)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n buf.copy(buffer, pos)\n pos += buf.length\n }\n return buffer\n}\n\nfunction byteLength (string, encoding) {\n if (Buffer.isBuffer(string)) {\n return string.length\n }\n if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&\n (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {\n return string.byteLength\n }\n if (typeof string !== 'string') {\n string = '' + string\n }\n\n var len = string.length\n if (len === 0) return 0\n\n // Use a for loop to avoid recursion\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'ascii':\n case 'binary':\n case 'raw':\n case 'raws':\n return len\n case 'utf8':\n case 'utf-8':\n case undefined:\n return utf8ToBytes(string).length\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return len * 2\n case 'hex':\n return len >>> 1\n case 'base64':\n return base64ToBytes(string).length\n default:\n if (loweredCase) return utf8ToBytes(string).length // assume utf8\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\nBuffer.byteLength = byteLength\n\nfunction slowToString (encoding, start, end) {\n var loweredCase = false\n\n // No need to verify that \"this.length <= MAX_UINT32\" since it's a read-only\n // property of a typed array.\n\n // This behaves neither like String nor Uint8Array in that we set start/end\n // to their upper/lower bounds if the value passed is out of range.\n // undefined is handled specially as per ECMA-262 6th Edition,\n // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.\n if (start === undefined || start < 0) {\n start = 0\n }\n // Return early if start > this.length. Done here to prevent potential uint32\n // coercion fail below.\n if (start > this.length) {\n return ''\n }\n\n if (end === undefined || end > this.length) {\n end = this.length\n }\n\n if (end <= 0) {\n return ''\n }\n\n // Force coersion to uint32. This will also coerce falsey/NaN values to 0.\n end >>>= 0\n start >>>= 0\n\n if (end <= start) {\n return ''\n }\n\n if (!encoding) encoding = 'utf8'\n\n while (true) {\n switch (encoding) {\n case 'hex':\n return hexSlice(this, start, end)\n\n case 'utf8':\n case 'utf-8':\n return utf8Slice(this, start, end)\n\n case 'ascii':\n return asciiSlice(this, start, end)\n\n case 'binary':\n return binarySlice(this, start, end)\n\n case 'base64':\n return base64Slice(this, start, end)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return utf16leSlice(this, start, end)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = (encoding + '').toLowerCase()\n loweredCase = true\n }\n }\n}\n\n// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect\n// Buffer instances.\nBuffer.prototype._isBuffer = true\n\nfunction swap (b, n, m) {\n var i = b[n]\n b[n] = b[m]\n b[m] = i\n}\n\nBuffer.prototype.swap16 = function swap16 () {\n var len = this.length\n if (len % 2 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 16-bits')\n }\n for (var i = 0; i < len; i += 2) {\n swap(this, i, i + 1)\n }\n return this\n}\n\nBuffer.prototype.swap32 = function swap32 () {\n var len = this.length\n if (len % 4 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 32-bits')\n }\n for (var i = 0; i < len; i += 4) {\n swap(this, i, i + 3)\n swap(this, i + 1, i + 2)\n }\n return this\n}\n\nBuffer.prototype.toString = function toString () {\n var length = this.length | 0\n if (length === 0) return ''\n if (arguments.length === 0) return utf8Slice(this, 0, length)\n return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.equals = function equals (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return true\n return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n var str = ''\n var max = exports.INSPECT_MAX_BYTES\n if (this.length > 0) {\n str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n if (this.length > max) str += ' ... '\n }\n return ''\n}\n\nBuffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {\n if (!Buffer.isBuffer(target)) {\n throw new TypeError('Argument must be a Buffer')\n }\n\n if (start === undefined) {\n start = 0\n }\n if (end === undefined) {\n end = target ? target.length : 0\n }\n if (thisStart === undefined) {\n thisStart = 0\n }\n if (thisEnd === undefined) {\n thisEnd = this.length\n }\n\n if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {\n throw new RangeError('out of range index')\n }\n\n if (thisStart >= thisEnd && start >= end) {\n return 0\n }\n if (thisStart >= thisEnd) {\n return -1\n }\n if (start >= end) {\n return 1\n }\n\n start >>>= 0\n end >>>= 0\n thisStart >>>= 0\n thisEnd >>>= 0\n\n if (this === target) return 0\n\n var x = thisEnd - thisStart\n var y = end - start\n var len = Math.min(x, y)\n\n var thisCopy = this.slice(thisStart, thisEnd)\n var targetCopy = target.slice(start, end)\n\n for (var i = 0; i < len; ++i) {\n if (thisCopy[i] !== targetCopy[i]) {\n x = thisCopy[i]\n y = targetCopy[i]\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nfunction arrayIndexOf (arr, val, byteOffset, encoding) {\n var indexSize = 1\n var arrLength = arr.length\n var valLength = val.length\n\n if (encoding !== undefined) {\n encoding = String(encoding).toLowerCase()\n if (encoding === 'ucs2' || encoding === 'ucs-2' ||\n encoding === 'utf16le' || encoding === 'utf-16le') {\n if (arr.length < 2 || val.length < 2) {\n return -1\n }\n indexSize = 2\n arrLength /= 2\n valLength /= 2\n byteOffset /= 2\n }\n }\n\n function read (buf, i) {\n if (indexSize === 1) {\n return buf[i]\n } else {\n return buf.readUInt16BE(i * indexSize)\n }\n }\n\n var foundIndex = -1\n for (var i = byteOffset; i < arrLength; ++i) {\n if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {\n if (foundIndex === -1) foundIndex = i\n if (i - foundIndex + 1 === valLength) return foundIndex * indexSize\n } else {\n if (foundIndex !== -1) i -= i - foundIndex\n foundIndex = -1\n }\n }\n\n return -1\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {\n if (typeof byteOffset === 'string') {\n encoding = byteOffset\n byteOffset = 0\n } else if (byteOffset > 0x7fffffff) {\n byteOffset = 0x7fffffff\n } else if (byteOffset < -0x80000000) {\n byteOffset = -0x80000000\n }\n byteOffset >>= 0\n\n if (this.length === 0) return -1\n if (byteOffset >= this.length) return -1\n\n // Negative offsets start from the end of the buffer\n if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)\n\n if (typeof val === 'string') {\n val = Buffer.from(val, encoding)\n }\n\n if (Buffer.isBuffer(val)) {\n // special case: looking for empty string/buffer always fails\n if (val.length === 0) {\n return -1\n }\n return arrayIndexOf(this, val, byteOffset, encoding)\n }\n if (typeof val === 'number') {\n if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {\n return Uint8Array.prototype.indexOf.call(this, val, byteOffset)\n }\n return arrayIndexOf(this, [ val ], byteOffset, encoding)\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\nBuffer.prototype.includes = function includes (val, byteOffset, encoding) {\n return this.indexOf(val, byteOffset, encoding) !== -1\n}\n\nfunction hexWrite (buf, string, offset, length) {\n offset = Number(offset) || 0\n var remaining = buf.length - offset\n if (!length) {\n length = remaining\n } else {\n length = Number(length)\n if (length > remaining) {\n length = remaining\n }\n }\n\n // must be an even number of digits\n var strLen = string.length\n if (strLen % 2 !== 0) throw new Error('Invalid hex string')\n\n if (length > strLen / 2) {\n length = strLen / 2\n }\n for (var i = 0; i < length; ++i) {\n var parsed = parseInt(string.substr(i * 2, 2), 16)\n if (isNaN(parsed)) return i\n buf[offset + i] = parsed\n }\n return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction binaryWrite (buf, string, offset, length) {\n return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n // Buffer#write(string)\n if (offset === undefined) {\n encoding = 'utf8'\n length = this.length\n offset = 0\n // Buffer#write(string, encoding)\n } else if (length === undefined && typeof offset === 'string') {\n encoding = offset\n length = this.length\n offset = 0\n // Buffer#write(string, offset[, length][, encoding])\n } else if (isFinite(offset)) {\n offset = offset | 0\n if (isFinite(length)) {\n length = length | 0\n if (encoding === undefined) encoding = 'utf8'\n } else {\n encoding = length\n length = undefined\n }\n // legacy write(string, encoding, offset, length) - remove in v0.13\n } else {\n throw new Error(\n 'Buffer.write(string, encoding, offset[, length]) is no longer supported'\n )\n }\n\n var remaining = this.length - offset\n if (length === undefined || length > remaining) length = remaining\n\n if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n throw new RangeError('Attempt to write outside buffer bounds')\n }\n\n if (!encoding) encoding = 'utf8'\n\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'hex':\n return hexWrite(this, string, offset, length)\n\n case 'utf8':\n case 'utf-8':\n return utf8Write(this, string, offset, length)\n\n case 'ascii':\n return asciiWrite(this, string, offset, length)\n\n case 'binary':\n return binaryWrite(this, string, offset, length)\n\n case 'base64':\n // Warning: maxLength not taken into account in base64Write\n return base64Write(this, string, offset, length)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return ucs2Write(this, string, offset, length)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n return {\n type: 'Buffer',\n data: Array.prototype.slice.call(this._arr || this, 0)\n }\n}\n\nfunction base64Slice (buf, start, end) {\n if (start === 0 && end === buf.length) {\n return base64.fromByteArray(buf)\n } else {\n return base64.fromByteArray(buf.slice(start, end))\n }\n}\n\nfunction utf8Slice (buf, start, end) {\n end = Math.min(buf.length, end)\n var res = []\n\n var i = start\n while (i < end) {\n var firstByte = buf[i]\n var codePoint = null\n var bytesPerSequence = (firstByte > 0xEF) ? 4\n : (firstByte > 0xDF) ? 3\n : (firstByte > 0xBF) ? 2\n : 1\n\n if (i + bytesPerSequence <= end) {\n var secondByte, thirdByte, fourthByte, tempCodePoint\n\n switch (bytesPerSequence) {\n case 1:\n if (firstByte < 0x80) {\n codePoint = firstByte\n }\n break\n case 2:\n secondByte = buf[i + 1]\n if ((secondByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n if (tempCodePoint > 0x7F) {\n codePoint = tempCodePoint\n }\n }\n break\n case 3:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n codePoint = tempCodePoint\n }\n }\n break\n case 4:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n fourthByte = buf[i + 3]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n codePoint = tempCodePoint\n }\n }\n }\n }\n\n if (codePoint === null) {\n // we did not generate a valid codePoint so insert a\n // replacement char (U+FFFD) and advance only 1 byte\n codePoint = 0xFFFD\n bytesPerSequence = 1\n } else if (codePoint > 0xFFFF) {\n // encode to utf16 (surrogate pair dance)\n codePoint -= 0x10000\n res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n codePoint = 0xDC00 | codePoint & 0x3FF\n }\n\n res.push(codePoint)\n i += bytesPerSequence\n }\n\n return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n var len = codePoints.length\n if (len <= MAX_ARGUMENTS_LENGTH) {\n return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n }\n\n // Decode in chunks to avoid \"call stack size exceeded\".\n var res = ''\n var i = 0\n while (i < len) {\n res += String.fromCharCode.apply(\n String,\n codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n )\n }\n return res\n}\n\nfunction asciiSlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i] & 0x7F)\n }\n return ret\n}\n\nfunction binarySlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i])\n }\n return ret\n}\n\nfunction hexSlice (buf, start, end) {\n var len = buf.length\n\n if (!start || start < 0) start = 0\n if (!end || end < 0 || end > len) end = len\n\n var out = ''\n for (var i = start; i < end; ++i) {\n out += toHex(buf[i])\n }\n return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n var bytes = buf.slice(start, end)\n var res = ''\n for (var i = 0; i < bytes.length; i += 2) {\n res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n }\n return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n var len = this.length\n start = ~~start\n end = end === undefined ? len : ~~end\n\n if (start < 0) {\n start += len\n if (start < 0) start = 0\n } else if (start > len) {\n start = len\n }\n\n if (end < 0) {\n end += len\n if (end < 0) end = 0\n } else if (end > len) {\n end = len\n }\n\n if (end < start) end = start\n\n var newBuf\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n newBuf = this.subarray(start, end)\n newBuf.__proto__ = Buffer.prototype\n } else {\n var sliceLen = end - start\n newBuf = new Buffer(sliceLen, undefined)\n for (var i = 0; i < sliceLen; ++i) {\n newBuf[i] = this[i + start]\n }\n }\n\n return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n checkOffset(offset, byteLength, this.length)\n }\n\n var val = this[offset + --byteLength]\n var mul = 1\n while (byteLength > 0 && (mul *= 0x100)) {\n val += this[offset + --byteLength] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return ((this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16)) +\n (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] * 0x1000000) +\n ((this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n this[offset + 3])\n}\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var i = byteLength\n var mul = 1\n var val = this[offset + --i]\n while (i > 0 && (mul *= 0x100)) {\n val += this[offset + --i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n if (!(this[offset] & 0x80)) return (this[offset])\n return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset] | (this[offset + 1] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset + 1] | (this[offset] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16) |\n (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] << 24) |\n (this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n if (!Buffer.isBuffer(buf)) throw new TypeError('\"buffer\" argument must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('\"value\" argument is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n var maxBytes = Math.pow(2, 8 * byteLength) - 1\n checkInt(this, value, offset, byteLength, maxBytes, 0)\n }\n\n var mul = 1\n var i = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n var maxBytes = Math.pow(2, 8 * byteLength) - 1\n checkInt(this, value, offset, byteLength, maxBytes, 0)\n }\n\n var i = byteLength - 1\n var mul = 1\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {\n buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n (littleEndian ? i : 1 - i) * 8\n }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffffffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {\n buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset + 3] = (value >>> 24)\n this[offset + 2] = (value >>> 16)\n this[offset + 1] = (value >>> 8)\n this[offset] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = 0\n var mul = 1\n var sub = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {\n sub = 1\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = byteLength - 1\n var mul = 1\n var sub = 0\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {\n sub = 1\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n if (value < 0) value = 0xff + value + 1\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n this[offset + 2] = (value >>> 16)\n this[offset + 3] = (value >>> 24)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (value < 0) value = 0xffffffff + value + 1\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n if (offset < 0) throw new RangeError('Index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n }\n ieee754.write(buf, value, offset, littleEndian, 23, 4)\n return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n }\n ieee754.write(buf, value, offset, littleEndian, 52, 8)\n return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n if (!start) start = 0\n if (!end && end !== 0) end = this.length\n if (targetStart >= target.length) targetStart = target.length\n if (!targetStart) targetStart = 0\n if (end > 0 && end < start) end = start\n\n // Copy 0 bytes; we're done\n if (end === start) return 0\n if (target.length === 0 || this.length === 0) return 0\n\n // Fatal error conditions\n if (targetStart < 0) {\n throw new RangeError('targetStart out of bounds')\n }\n if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n // Are we oob?\n if (end > this.length) end = this.length\n if (target.length - targetStart < end - start) {\n end = target.length - targetStart + start\n }\n\n var len = end - start\n var i\n\n if (this === target && start < targetStart && targetStart < end) {\n // descending copy from end\n for (i = len - 1; i >= 0; --i) {\n target[i + targetStart] = this[i + start]\n }\n } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n // ascending copy from start\n for (i = 0; i < len; ++i) {\n target[i + targetStart] = this[i + start]\n }\n } else {\n Uint8Array.prototype.set.call(\n target,\n this.subarray(start, start + len),\n targetStart\n )\n }\n\n return len\n}\n\n// Usage:\n// buffer.fill(number[, offset[, end]])\n// buffer.fill(buffer[, offset[, end]])\n// buffer.fill(string[, offset[, end]][, encoding])\nBuffer.prototype.fill = function fill (val, start, end, encoding) {\n // Handle string cases:\n if (typeof val === 'string') {\n if (typeof start === 'string') {\n encoding = start\n start = 0\n end = this.length\n } else if (typeof end === 'string') {\n encoding = end\n end = this.length\n }\n if (val.length === 1) {\n var code = val.charCodeAt(0)\n if (code < 256) {\n val = code\n }\n }\n if (encoding !== undefined && typeof encoding !== 'string') {\n throw new TypeError('encoding must be a string')\n }\n if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {\n throw new TypeError('Unknown encoding: ' + encoding)\n }\n } else if (typeof val === 'number') {\n val = val & 255\n }\n\n // Invalid ranges are not set to a default, so can range check early.\n if (start < 0 || this.length < start || this.length < end) {\n throw new RangeError('Out of range index')\n }\n\n if (end <= start) {\n return this\n }\n\n start = start >>> 0\n end = end === undefined ? this.length : end >>> 0\n\n if (!val) val = 0\n\n var i\n if (typeof val === 'number') {\n for (i = start; i < end; ++i) {\n this[i] = val\n }\n } else {\n var bytes = Buffer.isBuffer(val)\n ? val\n : utf8ToBytes(new Buffer(val, encoding).toString())\n var len = bytes.length\n for (i = 0; i < end - start; ++i) {\n this[i + start] = bytes[i % len]\n }\n }\n\n return this\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n str = stringtrim(str).replace(INVALID_BASE64_RE, '')\n // Node converts strings with length < 2 to ''\n if (str.length < 2) return ''\n // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n while (str.length % 4 !== 0) {\n str = str + '='\n }\n return str\n}\n\nfunction stringtrim (str) {\n if (str.trim) return str.trim()\n return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n if (n < 16) return '0' + n.toString(16)\n return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n units = units || Infinity\n var codePoint\n var length = string.length\n var leadSurrogate = null\n var bytes = []\n\n for (var i = 0; i < length; ++i) {\n codePoint = string.charCodeAt(i)\n\n // is surrogate component\n if (codePoint > 0xD7FF && codePoint < 0xE000) {\n // last char was a lead\n if (!leadSurrogate) {\n // no lead yet\n if (codePoint > 0xDBFF) {\n // unexpected trail\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n } else if (i + 1 === length) {\n // unpaired lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n }\n\n // valid lead\n leadSurrogate = codePoint\n\n continue\n }\n\n // 2 leads in a row\n if (codePoint < 0xDC00) {\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n leadSurrogate = codePoint\n continue\n }\n\n // valid surrogate pair\n codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n } else if (leadSurrogate) {\n // valid bmp char, but last char was a lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n }\n\n leadSurrogate = null\n\n // encode utf8\n if (codePoint < 0x80) {\n if ((units -= 1) < 0) break\n bytes.push(codePoint)\n } else if (codePoint < 0x800) {\n if ((units -= 2) < 0) break\n bytes.push(\n codePoint >> 0x6 | 0xC0,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x10000) {\n if ((units -= 3) < 0) break\n bytes.push(\n codePoint >> 0xC | 0xE0,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x110000) {\n if ((units -= 4) < 0) break\n bytes.push(\n codePoint >> 0x12 | 0xF0,\n codePoint >> 0xC & 0x3F | 0x80,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else {\n throw new Error('Invalid code point')\n }\n }\n\n return bytes\n}\n\nfunction asciiToBytes (str) {\n var byteArray = []\n for (var i = 0; i < str.length; ++i) {\n // Node's code seems to be doing this and not & 0x7F..\n byteArray.push(str.charCodeAt(i) & 0xFF)\n }\n return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n var c, hi, lo\n var byteArray = []\n for (var i = 0; i < str.length; ++i) {\n if ((units -= 2) < 0) break\n\n c = str.charCodeAt(i)\n hi = c >> 8\n lo = c % 256\n byteArray.push(lo)\n byteArray.push(hi)\n }\n\n return byteArray\n}\n\nfunction base64ToBytes (str) {\n return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n for (var i = 0; i < length; ++i) {\n if ((i + offset >= dst.length) || (i >= src.length)) break\n dst[i + offset] = src[i]\n }\n return i\n}\n\nfunction isnan (val) {\n return val !== val // eslint-disable-line no-self-compare\n}\n","'use strict';\n\nvar Channel = require('../service/channel-service');\nvar SessionManager = require('../store/session-manager');\n\n/**\n * ## Channel Manager\n *\n * There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Manager is a wrapper around the default [cometd JavaScript library](http://docs.cometd.org/2/reference/javascript.html), `$.cometd`. It provides a few nice features that `$.cometd` doesn't, including:\n *\n * * Automatic re-subscription to channels if you lose your connection\n * * Online / Offline notifications\n * * 'Events' for cometd notifications (instead of having to listen on specific meta channels)\n *\n * While you can work directly with the Channel Manager through Node.js (for example, `require('manager/channel-manager')`) -- or even work directly with `$.cometd` and Epicenter's underlying [Push Channel API](../../../rest_apis/multiplayer/channel/) -- most often it will be easiest to work with the [Epicenter Channel Manager](../epicenter-channel-manager/). The Epicenter Channel Manager is a wrapper that instantiates a Channel Manager with Epicenter-specific defaults.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Manager. (See [Including Epicenter.js](../../#include).)\n *\n * To use the Channel Manager in client-side JavaScript, instantiate the [Epicenter Channel Manager](../epicenter-channel-manager/), get the channel, then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * The parameters for instantiating a Channel Manager include:\n *\n * * `options` The options object to configure the Channel Manager. Besides the common options listed here, see http://docs.cometd.org/reference/javascript.html for other supported options.\n * * `options.url` The Cometd endpoint URL.\n * * `options.websocketEnabled` Whether websocket support is active (boolean).\n * * `options.channel` Other defaults to pass on to instances of the underlying Channel Service. See [Channel Service](../channel-service/) for details.\n *\n */\nvar ChannelManager = function (options) {\n if (!$.cometd) {\n throw new Error('Cometd library not found. Please include epicenter-multiplayer-dependencies.js');\n }\n if (!options || !options.url) {\n throw new Error('Please provide an url for the cometd server');\n }\n\n var defaults = {\n /**\n * The Cometd endpoint URL.\n * @type {string}\n */\n url: '',\n\n /**\n * The log level for the channel (logs to console).\n * @type {string}\n */\n logLevel: 'info',\n\n /**\n * Whether websocket support is active. Defaults to `false`; Epicenter doesn't currently support communication through websockets.\n * @type {boolean}\n */\n websocketEnabled: false,\n\n /**\n * If false each instance of Channel will have a separate cometd connection to server, which could be noisy. Set to true to re-use the same connection across instances.\n * @type {boolean}\n */\n shareConnection: false,\n\n /**\n * Other defaults to pass on to instances of the underlying [Channel Service](../channel-service/), which are created through `getChannel()`.\n * @type {object}\n */\n channel: {\n\n },\n\n /**\n * Options to pass to the channel handshake.\n *\n * For example, the [Epicenter Channel Manager](../epicenter-channel-manager/) passes `ext` and authorization information. More information on possible options is in the details of the underlying [Push Channel API](../../../rest_apis/multiplayer/channel/).\n *\n * @type {object}\n */\n handshake: undefined\n };\n this.sessionManager = new SessionManager();\n var defaultCometOptions = this.sessionManager.getMergedOptions(defaults, options);\n this.currentSubscriptions = [];\n this.options = defaultCometOptions;\n\n if (defaultCometOptions.shareConnection && ChannelManager.prototype._cometd) {\n this.cometd = ChannelManager.prototype._cometd;\n return this;\n }\n var cometd = new $.Cometd();\n ChannelManager.prototype._cometd = cometd;\n\n cometd.websocketEnabled = defaultCometOptions.websocketEnabled;\n\n this.isConnected = false;\n var connectionBroken = function (message) {\n $(this).trigger('disconnect', message);\n };\n var connectionSucceeded = function (message) {\n $(this).trigger('connect', message);\n };\n var me = this;\n\n cometd.configure(defaultCometOptions);\n\n cometd.addListener('/meta/connect', function (message) {\n var wasConnected = this.isConnected;\n this.isConnected = (message.successful === true);\n if (!wasConnected && this.isConnected) { //Connecting for the first time\n connectionSucceeded.call(this, message);\n } else if (wasConnected && !this.isConnected) { //Only throw disconnected message fro the first disconnect, not once per try\n connectionBroken.call(this, message);\n }\n }.bind(this));\n\n cometd.addListener('/meta/disconnect', connectionBroken);\n\n cometd.addListener('/meta/handshake', function (message) {\n if (message.successful) {\n //http://docs.cometd.org/reference/javascript_subscribe.html#javascript_subscribe_meta_channels\n // ^ \"dynamic subscriptions are cleared (like any other subscription) and the application needs to figure out which dynamic subscription must be performed again\"\n cometd.batch(function () {\n $(me.currentSubscriptions).each(function (index, subs) {\n cometd.resubscribe(subs);\n });\n });\n }\n });\n\n //Other interesting events for reference\n cometd.addListener('/meta/subscribe', function (message) {\n $(me).trigger('subscribe', message);\n });\n cometd.addListener('/meta/unsubscribe', function (message) {\n $(me).trigger('unsubscribe', message);\n });\n cometd.addListener('/meta/publish', function (message) {\n $(me).trigger('publish', message);\n });\n cometd.addListener('/meta/unsuccessful', function (message) {\n $(me).trigger('error', message);\n });\n\n cometd.handshake(defaultCometOptions.handshake);\n\n this.cometd = cometd;\n};\n\n\nChannelManager.prototype = $.extend(ChannelManager.prototype, {\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} `options` (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n */\n getChannel: function (options) {\n //If you just want to pass in a string\n if (options && !$.isPlainObject(options)) {\n options = {\n base: options\n };\n }\n var defaults = {\n transport: this.cometd\n };\n var channel = new Channel($.extend(true, {}, this.options.channel, defaults, options));\n\n\n //Wrap subs and unsubs so we can use it to re-attach handlers after being disconnected\n var subs = channel.subscribe;\n channel.subscribe = function () {\n var subid = subs.apply(channel, arguments);\n this.currentSubscriptions = this.currentSubscriptions.concat(subid);\n return subid;\n }.bind(this);\n\n\n var unsubs = channel.unsubscribe;\n channel.unsubscribe = function () {\n var removed = unsubs.apply(channel, arguments);\n for (var i = 0; i < this.currentSubscriptions.length; i++) {\n if (this.currentSubscriptions[i].id === removed.id) {\n this.currentSubscriptions.splice(i, 1);\n }\n }\n return removed;\n }.bind(this);\n\n return channel;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n});\n\nmodule.exports = ChannelManager;\n","'use strict';\n\nmodule.exports = {\n EPI_SESSION_KEY: 'epicenterjs.session',\n STRATEGY_SESSION_KEY: 'epicenter-scenario'\n};","'use strict';\n\nvar ConfigService = require('../service/configuration-service');\n\nvar urlConfig = new ConfigService().get('server');\nvar customDefaults = {};\nvar libDefaults = {\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: urlConfig.accountPath,\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: urlConfig.projectPath,\n isLocal: urlConfig.isLocalhost(),\n store: {}\n};\n\nvar optionUtils = {\n /**\n * Gets the final options by overriding the global options set with\n * optionUtils#setDefaults() and the lib defaults.\n * @param {object} `options` The final options object.\n */\n getOptions: function (options) {\n return $.extend(true, {}, libDefaults, customDefaults, options);\n },\n /**\n * Sets the global defaults for the optionUtils#getOptions() method.\n * @param {object} `defaults` The defaults object.\n */\n setDefaults: function (defaults) {\n customDefaults = defaults;\n }\n};\nmodule.exports = optionUtils;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\n\nvar IdentityStrategy = require('./identity-strategy');\nvar WorldApiAdapter = require('../../service/world-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n\n constructor: function (runService, options) {\n this.runService = runService;\n this.options = $.extend(true, {}, defaults, options);\n this._auth = new AuthManager();\n this._loadRun = this._loadRun.bind(this);\n this.worldApi = new WorldApiAdapter(this.options.run);\n },\n\n reset: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n return this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(function (world) {\n return this.worldApi.newRunForWorld(world.id);\n }.bind(this));\n },\n\n getRun: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n var worldApi = this.worldApi;\n var model = this.options.model;\n var _this = this;\n var dtd = $.Deferred();\n\n if (!curUserId) {\n return dtd.reject({ statusCode: 400, error: 'We need an authenticated user to join a multiplayer world. (ERR: no userId in session)' }, session).promise();\n }\n\n var loadRunFromWorld = function (world) {\n if (!world) {\n return dtd.reject({ statusCode: 404, error: 'The user is not in any world.' }, { options: this.options, session: session });\n }\n\n return worldApi.getCurrentRunId({ model: model, filter: world.id })\n .then(_this._loadRun)\n .then(dtd.resolve)\n .fail(dtd.reject);\n };\n\n var serverError = function (error) {\n // is this possible?\n dtd.reject(error, session, this.options);\n };\n\n this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(loadRunFromWorld)\n .fail(serverError);\n\n return dtd.promise();\n },\n\n _loadRun: function (id, options) {\n return this.runService.load(id, null, options);\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar IdentityStrategy = require('./identity-strategy');\nvar StorageFactory = require('../../store/store-factory');\nvar StateApi = require('../../service/state-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar keyNames = require('../key-names');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n constructor: function Strategy(runService, options) {\n this.run = runService;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n this._store = new StorageFactory(this.options.store);\n this.stateApi = new StateApi();\n this._auth = new AuthManager();\n\n this._loadAndCheck = this._loadAndCheck.bind(this);\n this._restoreRun = this._restoreRun.bind(this);\n this._getAllRuns = this._getAllRuns.bind(this);\n this._loadRun = this._loadRun.bind(this);\n },\n\n reset: function (runServiceOptions) {\n var session = this._auth.getCurrentUserSessionInfo();\n var opt = $.extend({\n scope: { group: session.groupName }\n }, this.runOptions);\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n run.freshlyCreated = true;\n return run;\n });\n },\n\n getRun: function () {\n return this._getAllRuns()\n .then(this._loadAndCheck);\n },\n\n _getAllRuns: function () {\n var session = JSON.parse(this._store.get(keyNames.EPI_SESSION_KEY) || '{}');\n return this.run.query({\n 'user.id': session.userId || '0000',\n 'scope.group': session.groupName\n });\n },\n\n _loadAndCheck: function (runs) {\n if (!runs || !runs.length) {\n return this.reset();\n }\n\n var dateComp = function (a, b) { return new Date(b.date) - new Date(a.date); };\n var latestRun = runs.sort(dateComp)[0];\n var _this = this;\n var shouldReplay = false;\n\n return this.run.load(latestRun.id, null, {\n success: function (run, msg, headers) {\n shouldReplay = headers.getResponseHeader('pragma') === 'persistent';\n }\n }).then(function (run) {\n return shouldReplay ? _this._restoreRun(run.id) : run;\n });\n },\n\n _restoreRun: function (runId) {\n var _this = this;\n return this.stateApi.replay({ runId: runId })\n .then(function (resp) {\n return _this._loadRun(resp.run);\n });\n },\n\n _loadRun: function (id, options) {\n return this.run.load(id, null, options);\n }\n\n});\n\nmodule.exports = Strategy;\n","var toString = {}.toString;\n\nmodule.exports = Array.isArray || function (arr) {\n return toString.call(arr) == '[object Array]';\n};\n","exports.read = function (buffer, offset, isLE, mLen, nBytes) {\n var e, m\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var nBits = -7\n var i = isLE ? (nBytes - 1) : 0\n var d = isLE ? -1 : 1\n var s = buffer[offset + i]\n\n i += d\n\n e = s & ((1 << (-nBits)) - 1)\n s >>= (-nBits)\n nBits += eLen\n for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n m = e & ((1 << (-nBits)) - 1)\n e >>= (-nBits)\n nBits += mLen\n for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n if (e === 0) {\n e = 1 - eBias\n } else if (e === eMax) {\n return m ? NaN : ((s ? -1 : 1) * Infinity)\n } else {\n m = m + Math.pow(2, mLen)\n e = e - eBias\n }\n return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n var e, m, c\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)\n var i = isLE ? 0 : (nBytes - 1)\n var d = isLE ? 1 : -1\n var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0\n\n value = Math.abs(value)\n\n if (isNaN(value) || value === Infinity) {\n m = isNaN(value) ? 1 : 0\n e = eMax\n } else {\n e = Math.floor(Math.log(value) / Math.LN2)\n if (value * (c = Math.pow(2, -e)) < 1) {\n e--\n c *= 2\n }\n if (e + eBias >= 1) {\n value += rt / c\n } else {\n value += rt * Math.pow(2, 1 - eBias)\n }\n if (value * c >= 2) {\n e++\n c /= 2\n }\n\n if (e + eBias >= eMax) {\n m = 0\n e = eMax\n } else if (e + eBias >= 1) {\n m = (value * c - 1) * Math.pow(2, mLen)\n e = e + eBias\n } else {\n m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)\n e = 0\n }\n }\n\n for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n e = (e << mLen) | m\n eLen += mLen\n for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n buffer[offset + i - d] |= s * 128\n}\n","'use strict'\n\nexports.toByteArray = toByteArray\nexports.fromByteArray = fromByteArray\n\nvar lookup = []\nvar revLookup = []\nvar Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array\n\nfunction init () {\n var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\n for (var i = 0, len = code.length; i < len; ++i) {\n lookup[i] = code[i]\n revLookup[code.charCodeAt(i)] = i\n }\n\n revLookup['-'.charCodeAt(0)] = 62\n revLookup['_'.charCodeAt(0)] = 63\n}\n\ninit()\n\nfunction toByteArray (b64) {\n var i, j, l, tmp, placeHolders, arr\n var len = b64.length\n\n if (len % 4 > 0) {\n throw new Error('Invalid string. Length must be a multiple of 4')\n }\n\n // the number of equal signs (place holders)\n // if there are two placeholders, than the two characters before it\n // represent one byte\n // if there is only one, then the three characters before it represent 2 bytes\n // this is just a cheap hack to not do indexOf twice\n placeHolders = b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0\n\n // base64 is 4/3 + up to two characters of the original data\n arr = new Arr(len * 3 / 4 - placeHolders)\n\n // if there are placeholders, only get up to the last complete 4 chars\n l = placeHolders > 0 ? len - 4 : len\n\n var L = 0\n\n for (i = 0, j = 0; i < l; i += 4, j += 3) {\n tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]\n arr[L++] = (tmp >> 16) & 0xFF\n arr[L++] = (tmp >> 8) & 0xFF\n arr[L++] = tmp & 0xFF\n }\n\n if (placeHolders === 2) {\n tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)\n arr[L++] = tmp & 0xFF\n } else if (placeHolders === 1) {\n tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)\n arr[L++] = (tmp >> 8) & 0xFF\n arr[L++] = tmp & 0xFF\n }\n\n return arr\n}\n\nfunction tripletToBase64 (num) {\n return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]\n}\n\nfunction encodeChunk (uint8, start, end) {\n var tmp\n var output = []\n for (var i = start; i < end; i += 3) {\n tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])\n output.push(tripletToBase64(tmp))\n }\n return output.join('')\n}\n\nfunction fromByteArray (uint8) {\n var tmp\n var len = uint8.length\n var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes\n var output = ''\n var parts = []\n var maxChunkLength = 16383 // must be multiple of 3\n\n // go through the array every three bytes, we'll deal with trailing stuff later\n for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))\n }\n\n // pad the end with zeros, but make sure to not forget the extra bytes\n if (extraBytes === 1) {\n tmp = uint8[len - 1]\n output += lookup[tmp >> 2]\n output += lookup[(tmp << 4) & 0x3F]\n output += '=='\n } else if (extraBytes === 2) {\n tmp = (uint8[len - 2] << 8) + (uint8[len - 1])\n output += lookup[tmp >> 10]\n output += lookup[(tmp >> 4) & 0x3F]\n output += lookup[(tmp << 2) & 0x3F]\n output += '='\n }\n\n parts.push(output)\n\n return parts.join('')\n}\n"]} \ No newline at end of file +<<<<<<< HEAD +{"version":3,"sources":["node_modules/browser-pack/_prelude.js","src/api-version.json","src/app.js","src/env-load.js","src/util/query-util.js","src/util/make-sequence.js","src/util/run-util.js","src/util/inherit.js","src/transport/http-transport-factory.js","src/transport/ajax-http-transport.js","src/service/url-config-service.js","src/service/configuration-service.js","src/service/run-api-service.js","src/service/admin-file-service.js","src/service/variables-api-service.js","src/service/data-api-service.js","src/service/auth-api-service.js","src/service/state-api-adapter.js","src/service/world-api-adapter.js","src/service/user-api-adapter.js","src/service/member-api-adapter.js","src/service/asset-api-adapter.js","src/service/group-api-service.js","src/store/cookie-store.js","src/store/store-factory.js","src/managers/scenario-manager.js","src/managers/run-manager.js","src/managers/auth-manager.js","src/managers/world-manager.js","src/managers/run-strategies/always-new-strategy.js","src/managers/run-strategies/conditional-creation-strategy.js","src/managers/run-strategies/identity-strategy.js","src/managers/run-strategies/new-if-missing-strategy.js","src/managers/run-strategies/new-if-persisted-strategy.js","src/managers/run-strategies/new-if-initialized-strategy.js","src/service/channel-service.js","src/managers/epicenter-channel-manager.js","src/util/object-util.js","src/store/session-manager.js","src/service/service-utils.js","src/managers/run-strategies/strategies-map.js","src/managers/special-operations.js","src/managers/channel-manager.js","src/managers/key-names.js","node_modules/buffer/index.js","src/util/option-utils.js","src/managers/run-strategies/persistent-single-player-strategy.js","src/managers/run-strategies/multiplayer-strategy.js","node_modules/object-assign/index.js","node_modules/base64-js/lib/b64.js","node_modules/ieee754/index.js","node_modules/isarray/index.js"],"names":["F","util","factory","transport","store","service","manager","strategy","load","require","query","makeSequence","run","classFrom","Transport","Ajax","URL","Config","Run","File","Variables","Data","Auth","World","State","User","Member","Asset","Group","Cookie","Store","ScenarioManager","RunManager","AuthManager","WorldManager","identity","ChannelManager","Channel","version","api","global","module","exports","urlConfigService","envLoad","callback","envPromise","host","urlService","envPath","isLocalhost","infoUrl","$","ajax","url","async","done","res","extend","fail","protocol","toMatrixFormat","qs","undefined","String","returnArray","OPERATORS","each","key","value","inArray","trim","charAt","push","mtrx","join","toQueryFormat","isArray","isPlainObject","JSON","stringify","result","qsToObject","qsArray","split","returnObj","index","qKey","qVal","indexOf","mergeQS","qs1","qs2","obj1","this","obj2","addTrailingSlash","length","_w","val","then","p","Deferred","resolve","promise","seq","next","cur","list","splice","Array","prototype","slice","apply","arguments","seed","MakeSeq","obj","__calls","original","fn","start","_this","funcMaker","bind","args","Function","concat","prop","qutil","MAX_URL_LENGTH","normalizeOperations","operations","returnList","ops","_concat","arr","_normalizePlainObjects","opn","arg","_normalizeStructuredObjects","operation","name","params","_normalizeObject","_normalizeLiterals","_normalizeArrays","splitGetFactory","httpOptions","options","http","getValue","getFinalUrl","data","replace","queryParams","questionIdx","include","encodeURI","dtd","paramsCopy","urlNoIncludes","diff","oldSuccess","success","noop","oldError","error","currIncludes","includeOpts","currLength","encodeURIComponent","variable","pop","varLenght","reqs","map","reqParams","get","when","isValid","reject","firstResponse","isObject","isRunAPI","variables","aggregateRun","idx","aggregatedRuns","runs","idxRun","id","aggregatedVariables","vars","inherit","C","P","__super","constructor","dest","call","current","j","base","props","staticProps","parent","child","hasOwnProperty","qutils","config","defaults","contentType","headers","statusCode","404","parameterParser","xhrFields","withCredentials","transportOptions","d","isFunction","connect","method","connectOptions","type","ALLOWED_TO_BE_FUNCTIONS","logLevel","console","log","oldSuccessFn","response","ajaxStatus","ajaxReq","beforeSend","xhr","settings","requestUrl","publicAPI","ajaxOptions","splitGet","post","patch","put","delete","delimiter","head","epiVersion","window","location","pathname","UrlConfigService","path","API_PROTOCOL","HOST_API_MAPPING","forio.com","foriodev.com","publicExports","appPath","accountPath","accnt","projectPath","prj","versionPath","getAPIPath","PROJECT_APIS","apiPath","envConf","serviceOptions","server","setEnv","env","property","set","ConfigService","rutil","_pick","TransportFactory","VariablesService","SessionManager","token","account","project","filter","autoRestore","sessionManager","getMergedOptions","urlConfig","getFilterURL","addAutoRestoreHeader","isFilterRunId","autorestoreOpts","X-AutoRestore","Authorization","setFilterOrThrowError","Error","publicAsyncAPI","create","createOptions","runApiParams","model","outputModifier","runID","filters","save","attributes","do","opsArgs","postOptions","prms","serial","opParams","me","$d","doSingleOp","op","shift","parallel","queue","i","publicSyncAPI","getCurrentConfig","vs","runService","folderType","getContents","filePath","writeToFile","contents","fileName","boundary","body","remove","rename","newName","getURL","attrs","root","q","saveAs","keys","userName","password","login","resp","status","statusMessage","postParams","logout","apiEndpoint","parseRunIdOrError","runId","replay","replayOptions","action","clone","apiBase","assignmentEndpoint","projectEndpoint","group","setIdFilterOrThrowError","validateModelOrThrowError","worldApiParams","validParams","update","whitelist","updateOptions","deleteOptions","updateConfig","getOptions","getWorldsForUser","userId","worldId","addUsers","users","u","updateUser","user","patchOptions","removeUser","getCurrentRunId","getCurrentWorldForUser","groupName","worlds","sort","a","b","Date","lastModified","currentWorld","deleteRun","newRunForWorld","currentRunOptions","autoAssign","opt","maxUsers","getProjectSettings","toQFilter","toIdFilters","getFilters","threshold","getById","groupId","getFinalParams","patchUserActiveField","active","getGroupsForUser","isString","objParams","getParms","getGroupDetails","makeUserActive","makeUserInactive","scope","fullUrl","processData","assetApiParams","scopeConfig","validateFilename","filename","validateUrlParams","partKeys","buildUrl","parts","upload","toLowerCase","FormData","urlOptions","getServiceOptions","files","fullPathFiles","file","assetUrl","serviceUtils","objectAssign","GroupService","getDefaultOptions","getGroups","finalOpts","finalParams","getApiUrl","document","cookie","newCookie","hostname","validHost","domain","setOptions","cookieReg","RegExp","exec","decodeURIComponent","remOptions","destroy","aKeys","nIdx","cookieKey","RunService","validFilter","saved","getRuns","loadVariables","meta","_getService","archive","getRun","patchRunService","patched","orig","reservedOps","Object","specialOperations","StrategyCtor","strategiesMap","reset","runServiceOptions","isLocal","authAdapter","AuthAdapter","MemberAdapter","Buffer","requiresGroup","_findUserInGroup","members","adapterOptions","outSuccess","outError","decodeToken","encoded","decode","atob","toString","parse","handleGroupError","message","statusText","handleSuccess","access_token","userInfo","oldGroups","getSession","groups","userGroupOpts","auth","isTeamMember","parent_account_id","sessionInfo","auth_token","user_id","saveSession","handleGroupList","groupList","userGroups","filteredGroups","grep","resGroup","isFac","role","groupData","sessionInfoWithGroup","opts","groupService","forEach","getUserGroups","removeCookieFn","removeSession","getToken","session","memberInfo","memberAdapter","getCurrentUserSessionInfo","addGroups","extendedGroup","validProps","buildStrategy","worldApi","WorldApi","world","_auth","getCurrentWorld","getCurrentRun","getAndRestoreLatestRun","currentWorldId","runOpts","rm","curUserId","curGroupName","ConditionalStrategy","Strategy","createIf","setRunInSession","sessionKey","getStore","makeSeq","Base","keyNames","STRATEGY_SESSION_KEY","condition","runOptions","runOptionsWithScope","userSession","freshlyCreated","sessionStore","runSession","_loadAndCheck","shouldCreate","msg","getResponseHeader","initialized","topicResolver","topic","channelOptions","makeName","channelName","subscribe","context","topics","subscriptionIds","batch","publish","returnObjs","warn","unsubscribe","on","event","off","trigger","validTypes","general","chat","getFromSettingsOrSessionOrError","sessionKeyName","EpicenterChannelManager","defaultCometOptions","urlOpts","handshake","userProp","ext","authorization","getChannel","channelOpts","allowAllChannels","baseParts","channelType","getGroupChannel","baseTopic","getWorldChannel","worldid","getUserChannel","userid","getPresenceChannel","channel","lastPingTime","PING_INTERVAL","notification","incomingUserId","online","valueOf","setInterval","now","getDataChannel","collection","oldsubs","callbackWithCleanData","payload","subType","date","actualData","StorageFactory","optionUtils","EPI_SESSION_KEY","synchronous","managerOptions","getBaseOptions","overrides","libOptions","finalOptions","baseOptions","storeOpts","serialized","cookieName","sessionDefaults","rest","new-if-initialized","new-if-persisted","new-if-missing","always-new","multiplayer","persistent-single-player","none","cometd","websocketEnabled","shareConnection","currentSubscriptions","_cometd","Cometd","isConnected","connectionBroken","connectionSucceeded","configure","addListener","wasConnected","successful","subs","resubscribe","subid","unsubs","removed","typedArraySupport","Uint8Array","__proto__","foo","subarray","byteLength","e","kMaxLength","TYPED_ARRAY_SUPPORT","createBuffer","that","RangeError","encodingOrOffset","allocUnsafe","from","TypeError","ArrayBuffer","fromArrayBuffer","fromString","fromObject","assertSize","size","alloc","fill","encoding","checked","string","isEncoding","write","fromArrayLike","array","byteOffset","isBuffer","len","copy","buffer","isnan","SlowBuffer","isView","loweredCase","utf8ToBytes","base64ToBytes","slowToString","end","hexSlice","utf8Slice","asciiSlice","binarySlice","base64Slice","utf16leSlice","swap","n","m","arrayIndexOf","read","buf","indexSize","readUInt16BE","arrLength","valLength","foundIndex","hexWrite","offset","Number","remaining","strLen","parsed","parseInt","substr","isNaN","utf8Write","blitBuffer","asciiWrite","asciiToBytes","binaryWrite","base64Write","ucs2Write","utf16leToBytes","base64","fromByteArray","Math","min","firstByte","codePoint","bytesPerSequence","secondByte","thirdByte","fourthByte","tempCodePoint","decodeCodePointsArray","codePoints","MAX_ARGUMENTS_LENGTH","fromCharCode","ret","out","toHex","bytes","checkOffset","checkInt","max","objectWriteUInt16","littleEndian","objectWriteUInt32","checkIEEE754","writeFloat","noAssert","ieee754","writeDouble","base64clean","str","stringtrim","INVALID_BASE64_RE","units","Infinity","leadSurrogate","charCodeAt","byteArray","c","hi","lo","toByteArray","src","dst","INSPECT_MAX_BYTES","poolSize","_augment","Symbol","species","defineProperty","configurable","allocUnsafeSlow","_isBuffer","compare","x","y","pos","swap16","swap32","equals","inspect","match","target","thisStart","thisEnd","thisCopy","targetCopy","includes","isFinite","toJSON","_arr","newBuf","sliceLen","readUIntLE","mul","readUIntBE","readUInt8","readUInt16LE","readUInt32LE","readUInt32BE","readIntLE","pow","readIntBE","readInt8","readInt16LE","readInt16BE","readInt32LE","readInt32BE","readFloatLE","readFloatBE","readDoubleLE","readDoubleBE","writeUIntLE","maxBytes","writeUIntBE","writeUInt8","floor","writeUInt16LE","writeUInt16BE","writeUInt32LE","writeUInt32BE","writeIntLE","limit","sub","writeIntBE","writeInt8","writeInt16LE","writeInt16BE","writeInt32LE","writeInt32BE","writeFloatLE","writeFloatBE","writeDoubleLE","writeDoubleBE","targetStart","code","customDefaults","libDefaults","setDefaults","IdentityStrategy","StateApi","_store","stateApi","_restoreRun","_getAllRuns","_loadRun","user.id","scope.group","dateComp","latestRun","shouldReplay","WorldApiAdapter","loadRunFromWorld","serverError","toObject","shouldUseNative","assign","test1","getOwnPropertyNames","test2","order2","test3","letter","propIsEnumerable","propertyIsEnumerable","source","to","symbols","s","getOwnPropertySymbols","init","lookup","revLookup","b64","l","tmp","placeHolders","Arr","L","tripletToBase64","num","encodeChunk","uint8","output","extraBytes","maxChunkLength","len2","isLE","mLen","nBytes","eLen","eMax","eBias","nBits","NaN","rt","abs","LN2"],"mappings":"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","file":"bundle.js","sourcesContent":["(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o\n * https://github.com/forio/epicenter-js-libs\n */\n\nvar F = {\n util: {},\n factory: {},\n transport: {},\n store: {},\n service: {},\n manager: {\n strategy: {}\n },\n\n};\n\nF.load = require('./env-load');\nF.load();\n\nF.util.query = require('./util/query-util');\nF.util.makeSequence = require('./util/make-sequence');\nF.util.run = require('./util/run-util');\nF.util.classFrom = require('./util/inherit');\n\nF.factory.Transport = require('./transport/http-transport-factory');\nF.transport.Ajax = require('./transport/ajax-http-transport');\n\nF.service.URL = require('./service/url-config-service');\nF.service.Config = require('./service/configuration-service');\nF.service.Run = require('./service/run-api-service');\nF.service.File = require('./service/admin-file-service');\nF.service.Variables = require('./service/variables-api-service');\nF.service.Data = require('./service/data-api-service');\nF.service.Auth = require('./service/auth-api-service');\nF.service.World = require('./service/world-api-adapter');\nF.service.State = require('./service/state-api-adapter');\nF.service.User = require('./service/user-api-adapter');\nF.service.Member = require('./service/member-api-adapter');\nF.service.Asset = require('./service/asset-api-adapter');\nF.service.Group = require('./service/group-api-service');\n\nF.store.Cookie = require('./store/cookie-store');\nF.factory.Store = require('./store/store-factory');\n\nF.manager.ScenarioManager = require('./managers/scenario-manager');\nF.manager.RunManager = require('./managers/run-manager');\nF.manager.AuthManager = require('./managers/auth-manager');\nF.manager.WorldManager = require('./managers/world-manager');\n\nF.manager.strategy['always-new'] = require('./managers/run-strategies/always-new-strategy');\nF.manager.strategy['conditional-creation'] = require('./managers/run-strategies/conditional-creation-strategy');\nF.manager.strategy.identity = require('./managers/run-strategies/identity-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-persisted'] = require('./managers/run-strategies/new-if-persisted-strategy');\nF.manager.strategy['new-if-initialized'] = require('./managers/run-strategies/new-if-initialized-strategy');\n\nF.manager.ChannelManager = require('./managers/epicenter-channel-manager');\nF.service.Channel = require('./service/channel-service');\n\nF.version = '<%= version %>';\nF.api = require('./api-version.json');\n\nglobal.F = F;\nmodule.exports = F;\n","'use strict';\n\nvar urlConfigService = require('./service/url-config-service');\n\nvar envLoad = function (callback) {\n var envPromise;\n var host;\n var urlService = urlConfigService();\n var envPath = '/epicenter/v1/config';\n if (urlService.isLocalhost()) {\n host = 'https://forio.com';\n } else {\n host = '';\n }\n var infoUrl = host + envPath;\n envPromise = $.ajax({ url: infoUrl, async: false });\n envPromise.done(function (res) {\n var api = res.api;\n $.extend(urlConfigService, api);\n }).fail(function (res) {\n // Epicenter/webserver not properly configured\n // fallback to api.forio.com\n $.extend(urlConfigService, { protocol: 'https', host: 'api.forio.com' });\n });\n return envPromise.done(callback).fail(callback);\n};\n\nmodule.exports = envLoad;\n","/**\n * Utilities for working with query strings\n*/\n'use strict';\n\nmodule.exports = (function () {\n\n return {\n /**\n * Converts to matrix format\n * @param {Object} qs Object to convert to query string\n * @return { string} Matrix-format query parameters\n */\n toMatrixFormat: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return ';';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n var OPERATORS = ['<', '>', '!'];\n $.each(qs, function (key, value) {\n if (typeof value !== 'string' || $.inArray($.trim(value).charAt(0), OPERATORS) === -1) {\n value = '=' + value;\n }\n returnArray.push(key + value);\n });\n\n var mtrx = ';' + returnArray.join(';');\n return mtrx;\n },\n\n /**\n * Converts strings/arrays/objects to type 'a=b&b=c'\n * @param { string|Array|Object} qs\n * @return { string}\n */\n toQueryFormat: function (qs) {\n if (qs === null || qs === undefined) {\n return '';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n $.each(qs, function (key, value) {\n if ($.isArray(value)) {\n value = value.join(',');\n }\n if ($.isPlainObject(value)) {\n //Mostly for data api\n value = JSON.stringify(value);\n }\n returnArray.push(key + '=' + value);\n });\n\n var result = returnArray.join('&');\n return result;\n },\n\n /**\n * Converts strings of type 'a=b&b=c' to { a:b, b:c}\n * @param { string} qs\n * @return {object}\n */\n qsToObject: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return {};\n }\n\n var qsArray = qs.split('&');\n var returnObj = {};\n $.each(qsArray, function (index, value) {\n var qKey = value.split('=')[0];\n var qVal = value.split('=')[1];\n\n if (qVal.indexOf(',') !== -1) {\n qVal = qVal.split(',');\n }\n\n returnObj[qKey] = qVal;\n });\n\n return returnObj;\n },\n\n /**\n * Normalizes and merges strings of type 'a=b', { b:c} to { a:b, b:c}\n * @param { string|Array|Object} qs1\n * @param { string|Array|Object} qs2\n * @return {Object}\n */\n mergeQS: function (qs1, qs2) {\n var obj1 = this.qsToObject(this.toQueryFormat(qs1));\n var obj2 = this.qsToObject(this.toQueryFormat(qs2));\n return $.extend(true, {}, obj1, obj2);\n },\n\n addTrailingSlash: function (url) {\n if (!url) {\n return '';\n }\n return (url.charAt(url.length - 1) === '/') ? url : (url + '/');\n }\n };\n}());\n\n\n\n","'use strict';\n/*jshint loopfunc:false */\n\nfunction _w(val) {\n if (val && val.then) {\n return val;\n }\n var p = $.Deferred();\n p.resolve(val);\n\n return p.promise();\n}\n\nfunction seq() {\n var list = Array.prototype.slice.apply(arguments);\n\n function next(p) {\n var cur = list.splice(0,1)[0];\n\n if (!cur) {\n return p;\n }\n\n return _w(cur(p)).then(next);\n }\n\n return function (seed) {\n return next(seed).fail(seq.fail);\n };\n}\n\nfunction MakeSeq(obj) {\n var res = {\n __calls: [],\n\n original: obj,\n\n then: function (fn) {\n this.__calls.push(fn);\n return this;\n },\n\n start: function () {\n var _this = this;\n\n // clean up\n this.then(function (run) {\n _this.__calls.length = 0;\n return run;\n });\n\n return seq.apply(null, this.__calls)();\n },\n\n fail: function (fn) {\n seq.fail = fn;\n return this;\n }\n };\n\n var funcMaker = function (p, obj) {\n var fn = obj[p].bind(obj);\n return function () {\n var args = Array.prototype.slice.apply(arguments);\n this.__calls.push(Function.bind.apply(fn, [null].concat(args)));\n return this;\n };\n };\n\n for (var prop in obj) {\n if (typeof obj[prop] === 'function') {\n res[prop] = funcMaker(prop, obj);\n } else {\n res[prop] = obj[prop];\n }\n }\n\n return res;\n}\n\nmodule.exports = MakeSeq;\n","/**\n * Utilities for working with the run service\n*/\n'use strict';\nvar qutil = require('./query-util');\nvar MAX_URL_LENGTH = 2048;\n\nmodule.exports = (function () {\n return {\n /**\n * returns operations of the form `[[op1,op2], [arg1, arg2]]`\n * @param {Object|Array|String} `operations` operations to perform\n * @param {Array} `args` arguments for operation\n * @return {String} Matrix-format query parameters\n */\n normalizeOperations: function (operations, args) {\n if (!args) {\n args = [];\n }\n var returnList = {\n ops: [],\n args: []\n };\n\n var _concat = function (arr) {\n return (arr !== null && arr !== undefined) ? [].concat(arr) : [];\n };\n\n //{ add: [1,2], subtract: [2,4] }\n var _normalizePlainObjects = function (operations, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (opn, arg) {\n returnList.ops.push(opn);\n returnList.args.push(_concat(arg));\n });\n return returnList;\n };\n //{ name: 'add', params: [1] }\n var _normalizeStructuredObjects = function (operation, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation.name);\n returnList.args.push(_concat(operation.params));\n return returnList;\n };\n\n var _normalizeObject = function (operation, returnList) {\n return ((operation.name) ? _normalizeStructuredObjects : _normalizePlainObjects)(operation, returnList);\n };\n\n var _normalizeLiterals = function (operation, args, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation);\n returnList.args.push(_concat(args));\n return returnList;\n };\n\n\n var _normalizeArrays = function (operations, arg, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (index, opn) {\n if ($.isPlainObject(opn)) {\n _normalizeObject(opn, returnList);\n } else {\n _normalizeLiterals(opn, args[index], returnList);\n }\n });\n return returnList;\n };\n\n if ($.isPlainObject(operations)) {\n _normalizeObject(operations, returnList);\n } else if ($.isArray(operations)) {\n _normalizeArrays(operations, args, returnList);\n } else {\n _normalizeLiterals(operations, args, returnList);\n }\n\n return returnList;\n },\n\n splitGetFactory: function (httpOptions) {\n return function (params, options) {\n var http = this;\n var getValue = function (name) {\n var value = options[name] || httpOptions[name];\n if (typeof value === 'function') {\n value = value();\n }\n return value;\n };\n var getFinalUrl = function (params) {\n var url = getValue('url', options);\n var data = params;\n // There is easy (or known) way to get the final URL jquery is going to send so\n // we're replicating it. The process might change at some point but it probably will not.\n // 1. Remove hash\n url = url.replace(/#.*$/, '');\n // 1. Append query string\n var queryParams = qutil.toQueryFormat(data);\n var questionIdx = url.indexOf('?');\n if (queryParams && questionIdx > -1) {\n return url + '&' + queryParams;\n } else if (queryParams) {\n return url + '?' + queryParams;\n }\n return url;\n };\n var url = getFinalUrl(params);\n // We must split the GET in multiple short URL's\n // The only property allowed to be split is \"include\"\n if (params && params.include && encodeURI(url).length > MAX_URL_LENGTH) {\n var dtd = $.Deferred();\n var paramsCopy = $.extend(true, {}, params);\n delete paramsCopy.include;\n var urlNoIncludes = getFinalUrl(paramsCopy);\n var diff = MAX_URL_LENGTH - urlNoIncludes.length;\n var oldSuccess = options.success || httpOptions.success || $.noop;\n var oldError = options.error || httpOptions.error || $.noop;\n // remove the original success and error callbacks\n options.success = $.noop;\n options.error = $.noop;\n\n var include = params.include;\n var currIncludes = [];\n var includeOpts = [currIncludes];\n var currLength = encodeURIComponent('?include=').length;\n var variable = include.pop();\n while (variable) {\n var varLenght = encodeURIComponent(variable).length;\n // Use a greedy approach for now, can be optimized to be solved in a more\n // efficient way\n // + 1 is the comma\n if (currLength + varLenght + 1 < diff) {\n currIncludes.push(variable);\n currLength += varLenght + 1;\n } else {\n currIncludes = [variable];\n includeOpts.push(currIncludes);\n currLength = '?include='.length + varLenght;\n }\n variable = include.pop();\n }\n var reqs = $.map(includeOpts, function (include) {\n var reqParams = $.extend({}, params, { include: include });\n return http.get(reqParams, options);\n });\n $.when.apply($, reqs).then(function () {\n // Each argument are arrays of the arguments of each done request\n // So the first argument of the first array of arguments is the data\n var isValid = arguments[0] && arguments[0][0];\n if (!isValid) {\n // Should never happen...\n oldError();\n return dtd.reject();\n }\n var firstResponse = arguments[0][0];\n var isObject = $.isPlainObject(firstResponse);\n var isRunAPI = (isObject && $.isPlainObject(firstResponse.variables)) || !isObject;\n if (isRunAPI) {\n if (isObject) {\n // aggregate the variables property only\n var aggregateRun = arguments[0][0];\n $.each(arguments, function (idx, args) {\n var run = args[0];\n $.extend(true, aggregateRun.variables, run.variables);\n });\n oldSuccess(aggregateRun, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregateRun, arguments[0][1], arguments[0][2]);\n } else {\n // array of runs\n // Agregate variables in each run\n var aggregatedRuns = {};\n $.each(arguments, function (idx, args) {\n var runs = args[0];\n if (!$.isArray(runs)) {\n return;\n }\n $.each(runs, function (idxRun, run) {\n if (run.id && !aggregatedRuns[run.id]) {\n run.variables = run.variables || {};\n aggregatedRuns[run.id] = run;\n } else if (run.id) {\n $.extend(true, aggregatedRuns[run.id].variables, run.variables);\n }\n });\n });\n // turn it into an array\n aggregatedRuns = $.map(aggregatedRuns, function (run) { return run; });\n oldSuccess(aggregatedRuns, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedRuns, arguments[0][1], arguments[0][2]);\n }\n } else {\n // is variables API\n // aggregate the response\n var aggregatedVariables = {};\n $.each(arguments, function (idx, args) {\n var vars = args[0];\n $.extend(true, aggregatedVariables, vars);\n });\n oldSuccess(aggregatedVariables, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedVariables, arguments[0][1], arguments[0][2]);\n }\n }, function () {\n oldError.apply(http, arguments);\n dtd.reject.apply(dtd, arguments);\n });\n return dtd.promise();\n } else {\n return http.get(params, options);\n }\n };\n }\n };\n}());\n","/**\n/* Inherit from a class (using prototype borrowing)\n*/\n'use strict';\n\nfunction inherit(C, P) {\n var F = function () {};\n F.prototype = P.prototype;\n C.prototype = new F();\n C.__super = P.prototype;\n C.prototype.constructor = C;\n}\n\n/**\n* Shallow copy of an object\n*/\nvar extend = function (dest /*, var_args*/) {\n var obj = Array.prototype.slice.call(arguments, 1);\n var current;\n for (var j = 0; j 1,\n * // where variables.price has been persisted (recorded)\n * // in the model.\n * rs.query({\n * 'saved': 'true',\n * '.price': '>1'\n * },\n * {\n * startrecord: 2,\n * endrecord: 5\n * });\n *\n * **Parameters**\n * @param {Object} `qs` Query object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Querying for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n query: function (qs, outputModifier, options) {\n serviceOptions.filter = qs; //shouldn't be able to over-ride\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Returns particular runs, based on conditions specified in the `qs` object.\n *\n * Similar to `.query()`.\n *\n * **Parameters**\n * @param {Object} `filter` Filter object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Filtering for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n filter: function (filter, outputModifier, options) {\n if ($.isPlainObject(serviceOptions.filter)) {\n $.extend(serviceOptions.filter, filter);\n } else {\n serviceOptions.filter = filter;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Get data for a specific run. This includes standard run data such as the account, model, project, and created and last modified dates. To request specific model variables, pass them as part of the `filters` parameter.\n *\n * Note that if the run is [in memory](../../../run_persistence/#runs-in-memory), any model variables are available; if the run is [in the database](../../../run_persistence/#runs-in-db), only model variables that have been persisted — that is, `record`ed in your Julia model — are available.\n *\n * **Example**\n *\n * rs.load('bb589677-d476-4971-a68e-0c58d191e450', { include: ['.price', '.sales'] });\n *\n * **Parameters**\n * @param {String} `runID` The run id.\n * @param {Object} `filters` (Optional) Object containing filters and operation modifiers. Use key `include` to list model variables that you want to include in the response. Other available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (runID, filters, options) {\n if (runID) {\n serviceOptions.filter = runID; //shouldn't be able to over-ride\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.get(filters, httpOptions);\n },\n\n\n /**\n * Save attributes (data, model variables) of the run.\n *\n * **Examples**\n *\n * // add 'completed' field to run record\n * rs.save({ completed: true });\n *\n * // update 'saved' field of run record, and update values of model variables for this run\n * rs.save({ saved: true, variables: { a: 23, b: 23 } });\n *\n * **Parameters**\n * @param {Object} `attributes` The run data and variables to save.\n * @param {Object} `attributes.variables` Model variables must be included in a `variables` field within the `attributes` object. (Otherwise they are treated as run data and added to the run record directly.)\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (attributes, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n setFilterOrThrowError(httpOptions);\n return http.patch(attributes, httpOptions);\n },\n\n /**\n * Call a method from the model.\n *\n * Depending on the language in which you have written your model, the method may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * The `params` argument is normally an array of arguments to the `operation`. In the special case where `operation` only takes one argument, you are not required to put that argument into an array.\n *\n * Note that you can combine the `operation` and `params` arguments into a single object if you prefer, as in the last example.\n *\n * **Examples**\n *\n * // method \"solve\" takes no arguments\n * rs.do('solve');\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', ['hello']);\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', 'hello');\n * // method \"sumArray\" takes one argument, an array\n * rs.do('sumArray', [[4,2,1]]);\n * // method \"add\" takes two arguments, both integers\n * rs.do({ name:'add', params:[2,4] });\n *\n * **Parameters**\n * @param {String} `operation` Name of method.\n * @param {Array} `params` (Optional) Any parameters the operation takes, passed as an array. In the special case where `operation` only takes one argument, you are not required to put that argument into an array, and can just pass it directly.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n do: function (operation, params, options) {\n // console.log('do', operation, params);\n var opsArgs;\n var postOptions;\n if (options) {\n opsArgs = params;\n postOptions = options;\n } else {\n if ($.isPlainObject(params)) {\n opsArgs = null;\n postOptions = params;\n } else {\n opsArgs = params;\n }\n }\n var result = rutil.normalizeOperations(operation, opsArgs);\n var httpOptions = $.extend(true, {}, serviceOptions, postOptions);\n\n setFilterOrThrowError(httpOptions);\n\n var prms = (result.args[0].length && (result.args[0] !== null && result.args[0] !== undefined)) ? result.args[0] : [];\n return http.post({ arguments: prms }, $.extend(true, {}, httpOptions, {\n url: urlConfig.getFilterURL() + 'operations/' + result.ops[0] + '/'\n }));\n },\n\n /**\n * Call several methods from the model, sequentially.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Examples**\n *\n * // methods \"initialize\" and \"solve\" do not take any arguments\n * rs.serial(['initialize', 'solve']);\n * // methods \"init\" and \"reset\" take two arguments each\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'reset', params: [2,3] }]);\n * // method \"init\" takes two arguments,\n * // method \"runmodel\" takes none\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'runmodel', params: [] }]);\n *\n * **Parameters**\n * @param {Array} `operations` If none of the methods take parameters, pass an array of the method names (strings). If any of the methods do take parameters, pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n serial: function (operations, params, options) {\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var me = this;\n\n var $d = $.Deferred();\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var doSingleOp = function () {\n var op = ops.shift();\n var arg = args.shift();\n\n me.do(op, arg, {\n success: function () {\n if (ops.length) {\n doSingleOp();\n } else {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this, arguments);\n }\n },\n error: function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this, arguments);\n }\n });\n };\n\n doSingleOp();\n\n return $d.promise();\n },\n\n /**\n * Call several methods from the model, executing them in parallel.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Example**\n *\n * // methods \"solve\" and \"reset\" do not take any arguments\n * rs.parallel(['solve', 'reset']);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel([ { name: 'add', params: [1,2] },\n * { name: 'subtract', params:[2,3] }]);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel({ add: [1,2], subtract: [2,4] });\n *\n * **Parameters**\n * @param {Array|Object} `operations` If none of the methods take parameters, pass an array of the method names (as strings). If any of the methods do take parameters, you have two options. You can pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters. Alternatively, you can pass a single object with the method name and a (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n parallel: function (operations, params, options) {\n var $d = $.Deferred();\n\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var queue = [];\n for (var i = 0; i< ops.length; i++) {\n queue.push(\n this.do(ops[i], args[i])\n );\n }\n $.when.apply(this, queue)\n .done(function () {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this.arguments);\n })\n .fail(function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this.arguments);\n });\n\n return $d.promise();\n }\n };\n\n var publicSyncAPI = {\n getCurrentConfig: function () {\n return serviceOptions;\n },\n /**\n * Returns a Variables Service instance. Use the variables instance to load, save, and query for specific model variables. See the [Variable API Service](../variables-api-service/) for more information.\n *\n * **Example**\n *\n * var vs = rs.variables();\n * vs.save({ sample_int: 4 });\n *\n * **Parameters**\n * @param {Object} `config` (Optional) Overrides for configuration options.\n */\n variables: function (config) {\n var vs = new VariablesService($.extend(true, {}, serviceOptions, config, {\n runService: this\n }));\n return vs;\n }\n };\n\n $.extend(this, publicAsyncAPI);\n $.extend(this, publicSyncAPI);\n};\n","/**\n * ## File API Service\n *\n * This is used to upload/download files directly onto Epicenter, analogous to using the File Manager UI in Epicenter directly or SFTPing files in. The Asset API is typically used for all project use-cases, and it's unlikely this File Service will be used directly except by Admin tools (e.g. Flow Inspector).\n *\n * Partially implemented.\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The project id. Defaults to empty string.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The folder type. One of Model|Static|Node\n * @type {String}\n */\n folderType: 'static',\n\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('file')\n });\n\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAsyncAPI = {\n /**\n * Get a directory listing, or contents of a file\n * @param {String} `filePath` Path to the file\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getContents: function (filePath, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.get('', httpOptions);\n },\n\n /**\n * Writes to the given file path; replaces the existing file if it exists\n * @param {String} `filePath` Path to the file\n * @param {String} `contents` Contents to write to file\n * @param {Object} `options` (Optional) Overrides for configuration options\n */\n writeToFile: function (filePath, contents, options) {\n filePath = filePath.split('/');\n var fileName = filePath.pop();\n filePath = filePath.join('/');\n var path = serviceOptions.folderType + '/' + filePath;\n var boundary = '---------------------------7da24f2e50046';\n\n var body = '--' + boundary + '\\r\\n' +\n 'Content-Disposition: form-data; name=\"file\";' +\n 'filename=\"' + fileName + '\"\\r\\n' +\n 'Content-type: text/html\\r\\n\\r\\n' +\n contents + '\\r\\n' +\n '--' + boundary + '--';\n\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path,\n data: body,\n contentType: 'multipart/form-data; boundary=' + boundary\n });\n\n return http.put(body, httpOptions);\n },\n\n /**\n * Removes the file\n * @param {String} `filePath` Path to the file\n * @param {Object} `options` (Optional) Overrides for configuration options\n */\n remove: function (filePath, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.delete(null, httpOptions);\n },\n\n /**\n * Rename the file\n * @param {String} filePath Path to the file\n * @param {Stirng} newName New name of file\n * @param {Object} options (Optional) Overrides for configuration options\n */\n rename: function (filePath, newName, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.patch({ 'name': newName }, httpOptions);\n }\n };\n\n $.extend(this, publicAsyncAPI);\n};\n","/**\n *\n * ## Variables API Service\n *\n * Used in conjunction with the [Run API Service](../run-api-service/) to read, write, and search for specific model variables.\n *\n * var rm = new F.manager.RunManager({\n * run: {\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'supply-chain-model.jl'\n * }\n * });\n * rm.getRun()\n * .then(function() {\n * var vs = rm.run.variables();\n * vs.save({sample_int: 4});\n * });\n *\n */\n\n\n 'use strict';\n\n var TransportFactory = require('../transport/http-transport-factory');\n var rutil = require('../util/run-util');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * The runs object to which the variable filters apply. Defaults to null.\n * @type {runService}\n */\n runService: null\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var getURL = function () {\n return serviceOptions.runService.urlConfig.getFilterURL() + 'variables/';\n };\n\n var addAutoRestoreHeader = function (options) {\n return serviceOptions.runService.urlConfig.addAutoRestoreHeader(options);\n };\n\n var httpOptions = {\n url: getURL\n };\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n http.splitGet = rutil.splitGetFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Get values for a variable.\n *\n * **Example**\n *\n * vs.load('sample_int')\n * .then(function(val){\n * // val contains the value of sample_int\n * });\n *\n * **Parameters**\n * @param {String} `variable` Name of variable to load.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (variable, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n return http.get(outputModifier, $.extend({}, httpOptions, {\n url: getURL() + variable + '/'\n }));\n },\n\n /**\n * Returns particular variables, based on conditions specified in the `query` object.\n *\n * **Example**\n *\n * vs.query(['price', 'sales'])\n * .then(function(val) {\n * // val is an object with the values of the requested variables: val.price, val.sales\n * });\n *\n * vs.query({ include:['price', 'sales'] });\n *\n * **Parameters**\n * @param {Object|Array} `query` The names of the variables requested.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (query, outputModifier, options) {\n //Query and outputModifier are both querystrings in the url; only calling them out separately here to be consistent with the other calls\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n\n if ($.isArray(query)) {\n query = { include: query };\n }\n $.extend(query, outputModifier);\n return http.splitGet(query, httpOptions);\n },\n\n /**\n * Save values to model variables. Overwrites existing values. Note that you can only update model variables if the run is [in memory](../../../run_persistence/#runs-in-memory). (An alternate way to update model variables is to call a method from the model and make sure that the method persists the variables. See `do`, `serial`, and `parallel` in the [Run API Service](../run-api-service/) for calling methods from the model.)\n *\n * **Example**\n *\n * vs.save('price', 4);\n * vs.save({ price: 4, quantity: 5, products: [2,3,4] });\n *\n * **Parameters**\n * @param {Object|String} `variable` An object composed of the model variables and the values to save. Alternatively, a string with the name of the variable.\n * @param {Object} `val` (Optional) If passing a string for `variable`, use this argument for the value to save.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (variable, val, options) {\n var attrs;\n if (typeof variable === 'object') {\n attrs = variable;\n options = val;\n } else {\n (attrs = {})[variable] = val;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n return http.patch.call(this, attrs, httpOptions);\n }\n\n // Not Available until underlying API supports PUT. Otherwise save would be PUT and merge would be PATCH\n // *\n // * Save values to the api. Merges arrays, but otherwise same as save\n // * @param {Object|String} variable Object with attributes, or string key\n // * @param {Object} val Optional if prev parameter was a string, set value here\n // * @param {Object} options Overrides for configuration options\n // *\n // * @example\n // * vs.merge({ price: 4, quantity: 5, products: [2,3,4] })\n // * vs.merge('price', 4);\n\n // merge: function (variable, val, options) {\n // var attrs;\n // if (typeof variable === 'object') {\n // attrs = variable;\n // options = val;\n // } else {\n // (attrs = {})[variable] = val;\n // }\n // var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n // return http.patch.call(this, attrs, httpOptions);\n // }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * ## Data API Service\n *\n * The Data API Service allows you to create, access, and manipulate data related to any of your projects. Data are organized in collections. Each collection contains a document; each element of this top-level document is a JSON object. (See additional information on the underlying [Data API](../../../rest_apis/data_api/).)\n *\n * All API calls take in an \"options\" object as the last parameter. The options can be used to extend/override the Data API Service defaults. In particular, there are three required parameters when you instantiate the Data Service:\n *\n * * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `project`: Epicenter project id.\n * * `root`: The the name of the collection. If you have multiple collections within each of your projects, you can also pass the collection name as an option for each call.\n *\n * var ds = new F.service.Data({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * root: 'survey-responses',\n * server: { host: 'api.forio.com' }\n * });\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('user2',\n * { 'question1': 3, 'question2': 8,\n * 'question3': true, 'question4': 'always' } );\n * ds.query('',{ 'question2': { '$gt': 9} });\n *\n * Note that in addition to the `account`, `project`, and `root`, the Data Service parameters optionally include a `server` object, whose `host` field contains the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Name of collection. Defaults to `/`, that is, the root level of your project at `forio.com/app/your-account-id/your-project-id/`. Required.\n * @type {String}\n */\n root: '/',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The project id. Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * For operations that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n //Options to pass on to the underlying transport layer\n transport: {}\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var getURL = function (key, root) {\n if (!root) {\n root = serviceOptions.root;\n }\n var url = urlConfig.getAPIPath('data') + qutil.addTrailingSlash(root);\n if (key) {\n url+= qutil.addTrailingSlash(key);\n }\n return url;\n };\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: getURL\n });\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Search for data within a collection.\n *\n * Searching using comparison or logical operators (as opposed to exact matches) requires MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional details.\n *\n * **Examples**\n *\n * // request all data associated with document 'user1'\n * ds.query('user1');\n *\n * // exact matching:\n * // request all documents in collection where 'question2' is 9\n * ds.query('', { 'question2': 9});\n *\n * // comparison operators:\n * // request all documents in collection\n * // where 'question2' is greater than 9\n * ds.query('', { 'question2': { '$gt': 9} });\n *\n * // logical operators:\n * // request all documents in collection\n * // where 'question2' is less than 10, and 'question3' is false\n * ds.query('', { '$and': [ { 'question2': { '$lt':10} }, { 'question3': false }] });\n *\n * // regular expresssions: use any Perl-compatible regular expressions\n * // request all documents in collection\n * // where 'question5' contains the string '.*day'\n * ds.query('', { 'question5': { '$regex': '.*day' } });\n *\n * **Parameters**\n * @param {String} `key` The name of the document to search. Pass the empty string ('') to search the entire collection.\n * @param {Object} `query` The query object. For exact matching, this object contains the field name and field value to match. For matching based on comparison, this object contains the field name and the comparison expression. For matching based on logical operators, this object contains an expression using MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional examples.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (key, query, outputModifier, options) {\n var params = $.extend(true, { q: query }, outputModifier);\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(params, httpOptions);\n },\n\n /**\n * Save data to an anonymous document within the collection.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.save('question1', 'yes');\n * ds.save({question1:'yes', question2: 32 });\n * ds.save({ name:'John', className: 'CS101' }, { root: 'students' });\n *\n * **Parameters**\n *\n * @param {String|Object} `key` If `key` is a string, it is the id of the element to save (create) in this document. If `key` is an object, the object is the data to save (create) in this document. In both cases, the id for the document is generated automatically.\n * @param {Object} `value` (Optional) The data to save. If `key` is a string, this is the value to save. If `key` is an object, the value(s) to save are already part of `key` and this argument is not required.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (key, value, options) {\n var attrs;\n if (typeof key === 'object') {\n attrs = key;\n options = value;\n } else {\n (attrs = {})[key] = value;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL('', httpOptions.root);\n\n return http.post(attrs, httpOptions);\n },\n\n /**\n * Save data to a named document or element within the collection. The `root` of the collection must be specified separately in configuration options, either as part of the call or as part of the initialization of ds.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('student1',\n * { firstName: 'john', lastName: 'smith' },\n * { root: 'students' });\n * ds.saveAs('mgmt100/groupB',\n * { scenarioYear: '2015' },\n * { root: 'myclasses' });\n *\n * **Parameters**\n *\n * @param {String} `key` Id of the document.\n * @param {Object} `value` (Optional) The data to save, in key:value pairs.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n saveAs: function (key, value, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n\n return http.put(value, httpOptions);\n },\n\n /**\n * Get data for a specific document or field.\n *\n * **Example**\n *\n * ds.load('user1');\n * ds.load('user1/question3');\n *\n * **Parameters**\n * @param {String|Object} `key` The id of the data to return. Can be the id of a document, or a path to data within that document.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` Overrides for configuration options.\n */\n load: function (key, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(outputModifier, httpOptions);\n },\n\n /**\n * Removes data from collection. Only documents (top-level elements in each collection) can be deleted.\n *\n * **Example**\n *\n * ds.remove('user1');\n *\n *\n * **Parameters**\n *\n * @param {String|Array} `keys` The id of the document to remove from this collection, or an array of such ids.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n remove: function (keys, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n var params;\n if ($.isArray(keys)) {\n params = { id: keys };\n } else {\n params = '';\n httpOptions.url = getURL(keys, httpOptions.root);\n }\n return http.delete(params, httpOptions);\n }\n\n // Epicenter doesn't allow nuking collections\n // /**\n // * Removes collection being referenced\n // * @return null\n // */\n // destroy: function (options) {\n // return this.remove('', options);\n // }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ## Authentication API Service\n *\n * The Authentication API Service provides a method for logging in, which creates and returns a user access token.\n *\n * User access tokens are required for each call to Epicenter. (See [Project Access](../../../project_access/) for more information.)\n *\n * If you need additional functionality -- such as tracking session information, easily retrieving the user token, or getting the groups to which an end user belongs -- consider using the [Authorization Manager](../auth-manager/) instead.\n *\n * var auth = new F.service.Auth();\n * auth.login({ userName: 'jsmith@acmesimulations.com',\n * password: 'passw0rd' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Email or username to use for logging in. Defaults to empty string.\n * @type {String}\n */\n userName: '',\n\n /**\n * Password for specified `userName`. Defaults to empty string.\n * @type {String}\n */\n password: '',\n\n /**\n * The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects). Required if the `userName` is for an [end user](../../../glossary/#users). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('authentication')\n });\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Logs user in, returning the user access token.\n *\n * If no `userName` or `password` were provided in the initial configuration options, they are required in the `options` here. If no `account` was provided in the initial configuration options and the `userName` is for an [end user](../../../glossary/#users), the `account` is required as well.\n *\n * **Example**\n *\n * auth.login({\n * userName: 'jsmith',\n * password: 'passw0rd',\n * account: 'acme-simulations' })\n * .then(function (token) {\n * console.log(\"user access token is: \", token.access_token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n login: function (options) {\n var httpOptions = $.extend(true, { success: $.noop }, serviceOptions, options);\n if (!httpOptions.userName || !httpOptions.password) {\n var resp = { status: 401, statusMessage: 'No username or password specified.' };\n if (options.error) {\n options.error.call(this, resp);\n }\n\n return $.Deferred().reject(resp).promise();\n }\n\n var postParams = {\n userName: httpOptions.userName,\n password: httpOptions.password,\n };\n if (httpOptions.account) {\n //pass in null for account under options if you don't want it to be sent\n postParams.account = httpOptions.account;\n }\n\n return http.post(postParams, httpOptions);\n },\n\n // (replace with /* */ comment block, to make visible in docs, once this is more than a noop)\n //\n // Logs user out from specified accounts.\n //\n // Epicenter logout is not implemented yet, so for now this is a dummy promise that gets automatically resolved.\n //\n // **Example**\n //\n // auth.logout();\n //\n // **Parameters**\n // @param {Object} `options` (Optional) Overrides for configuration options.\n //\n logout: function (options) {\n var dtd = $.Deferred();\n dtd.resolve();\n return dtd.promise();\n }\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n * ## State API Adapter\n *\n * The State API Adapter allows you to replay or clone runs. It brings existing, persisted run data from the database back into memory, using the same run id (`replay`) or a new run id (`clone`). Runs must be in memory in order for you to update variables or call operations on them.\n *\n * Specifically, the State API Adapter works by \"re-running\" the run (user interactions) from the creation of the run up to the time it was last persisted in the database. This process uses the current version of the run's model. Therefore, if the model has changed since the original run was created, the retrieved run will use the new model — and may end up having different values or behavior as a result. Use with care!\n *\n * To use the State API Adapter, instantiate it and then call its methods:\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f'});\n *\n * The constructor takes an optional `options` parameter in which you can specify the `account` and `project` if they are not already available in the current context.\n *\n */\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar SessionManager = require('../store/session-manager');\nvar apiEndpoint = 'model/state';\n\nmodule.exports = function (config) {\n\n var defaults = {\n\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n var parseRunIdOrError = function (params) {\n if ($.isPlainObject(params) && params.runId) {\n return params.runId;\n } else {\n throw new Error('Please pass in a run id');\n }\n };\n\n var publicAPI = {\n /**\n * Replay a run. After this call, the run, with its original run id, is now available [in memory](../../../run_persistence/#runs-in-memory). (It continues to be persisted into the Epicenter database at regular intervals.)\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore'});\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to bring back to memory.\n * @param {string} `params.stopBefore` (Optional) The run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n replay: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'replay' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n },\n\n /**\n * Clone a given run and return a new run in the same state as the given run.\n *\n * The new run id is now available [in memory](../../../run_persistence/#runs-in-memory). The new run includes a copy of all of the data from the original run, EXCEPT:\n *\n * * The `saved` field in the new run record is not copied from the original run record. It defaults to `false`.\n * * The `initialized` field in the new run record is not copied from the original run record. It defaults to `false` but may change to `true` as the new run is advanced. For example, if there has been a call to the `step` function (for Vensim models), the `initialized` field is set to `true`.\n * * The `created` field in the new run record is the date and time at which the clone was created (not the time that the original run was created.)\n *\n * The original run remains only [in the database](../../../run_persistence/#runs-in-db).\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.clone({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore', exclude: ['interimCalculation'] });\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to clone from memory.\n * @param {string} `params.stopBefore` (Optional) The newly cloned run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the newly cloned run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n clone: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'clone' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * ## World API Adapter\n *\n * A [run](../../../glossary/#run) is a collection of end user interactions with a project and its model -- including setting variables, making decisions, and calling operations. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases. Only [team projects](../../../glossary/#team) can be multiplayer.\n *\n * The World API Adapter allows you to create, access, and manipulate multiplayer worlds within your Epicenter project. You can use this to add and remove end users from the world, and to create, access, and remove their runs. Because of this, typically the World Adapter is used for facilitator pages in your project. (The related [World Manager](../world-manager/) provides an easy way to access runs and worlds for particular end users, so is typically used in pages that end users will interact with.)\n *\n * As with all the other [API Adapters](../../), all methods take in an \"options\" object as the last parameter. The options can be used to extend/override the World API Service defaults.\n *\n * To use the World Adapter, instantiate it and then access the methods provided. Instantiating requires the account id (**Team ID** in the Epicenter user interface), project id (**Project ID**), and group (**Group Name**).\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // call methods, e.g. wa.addUsers()\n * });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar _pick = require('../util/object-util')._pick;\n\nvar apiBase = 'multiplayer/';\nvar assignmentEndpoint = apiBase + 'assign';\nvar apiEndpoint = apiBase + 'world';\nvar projectEndpoint = apiBase + 'project';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The group name. Defaults to undefined.\n * @type {String}\n */\n group: undefined,\n\n /**\n * The model file to use to create runs in this world. Defaults to undefined.\n * @type {String}\n */\n model: undefined,\n\n /**\n * Criteria by which to filter world. Currently only supports world-ids as filters.\n * @type {String}\n */\n filter: '',\n\n /**\n * Convenience alias for filter\n * @type {String}\n */\n id: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {},\n\n /**\n * Called when the call completes successfully. Defaults to `$.noop`.\n * @type {function}\n */\n success: $.noop,\n\n /**\n * Called when the call fails. Defaults to `$.noop`.\n * @type {function}\n */\n error: $.noop\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n if (serviceOptions.id) {\n serviceOptions.filter = serviceOptions.id;\n }\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var setIdFilterOrThrowError = function (options) {\n if (options.id) {\n serviceOptions.filter = options.id;\n }\n if (options.filter) {\n serviceOptions.filter = options.filter;\n }\n if (!serviceOptions.filter) {\n throw new Error('No world id specified to apply operations against. This could happen if the user is not assigned to a world and is trying to work with runs from that world.');\n }\n };\n\n var validateModelOrThrowError = function (options) {\n if (!options.model) {\n throw new Error('No model specified to get the current run');\n }\n };\n\n var publicAPI = {\n\n /**\n * Creates a new World.\n *\n * Using this method is rare. It is more common to create worlds automatically while you `autoAssign()` end users to worlds. (In this case, configuration data for the world, such as the roles, are read from the project-level world configuration information, for example by `getProjectSettings()`.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create({\n * roles: ['VP Marketing', 'VP Sales', 'VP Engineering']\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to create the world.\n * @param {string} `params.group` (Optional) The **Group Name** to create this world under. Only end users in this group are eligible to join the world. Optional here; required when instantiating the service (`new F.service.World()`).\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (params, options) {\n var createOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) });\n var worldApiParams = ['scope', 'files', 'roles', 'optionalRoles', 'minUsers', 'group', 'name'];\n var validParams = _pick(serviceOptions, ['account', 'project', 'group']);\n // whitelist the fields that we actually can send to the api\n params = _pick(params, worldApiParams);\n\n // account and project go in the body, not in the url\n params = $.extend({}, validParams, params);\n\n var oldSuccess = createOptions.success;\n createOptions.success = function (response) {\n serviceOptions.filter = response.id; //all future chained calls to operate on this id\n return oldSuccess.apply(this, arguments);\n };\n\n return http.post(params, createOptions);\n },\n\n /**\n * Updates a World, for example to replace the roles in the world.\n *\n * Typically, you complete world configuration at the project level, rather than at the world level. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both. However, this method is available if you need to update the configuration of a particular world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.update({ roles: ['VP Marketing', 'VP Sales', 'VP Engineering'] });\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to update the world.\n * @param {string} `params.name` A string identifier for the linked end users, for example, \"name\": \"Our Team\".\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n update: function (params, options) {\n var whitelist = ['roles', 'optionalRoles', 'minUsers'];\n options = options || {};\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n params = _pick(params || {}, whitelist);\n\n return http.patch(params, updateOptions);\n },\n\n /**\n * Deletes an existing world.\n *\n * This function optionally takes one argument. If the argument is a string, it is the id of the world to delete. If the argument is an object, it is the override for global options.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.delete();\n * });\n *\n * **Parameters**\n * @param {String|Object} `options` (Optional) The id of the world to delete, or options object to override global options.\n *\n */\n delete: function (options) {\n options = (options && (typeof options === 'string')) ? { filter: options } : {};\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Updates the configuration for the current instance of the World API Adapter (including all subsequent function calls, until the configuration is updated again).\n *\n * **Example**\n *\n * var wa = new F.service.World({...}).updateConfig({ filter: '123' }).addUser({ userId: '123' });\n *\n * **Parameters**\n * @param {object} `config` The configuration object to use in updating existing configuration.\n */\n updateConfig: function (config) {\n $.extend(serviceOptions, config);\n\n return this;\n },\n\n /**\n * Lists all worlds for a given account, project, and group. All three are required, and if not specified as parameters, are read from the service.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // lists all worlds in group \"team1\"\n * wa.list();\n *\n * // lists all worlds in group \"other-group-name\"\n * wa.list({ group: 'other-group-name' });\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n list: function (options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = _pick(getOptions, ['account', 'project', 'group']);\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Gets all worlds that an end user belongs to for a given account (team), project, and group.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getWorldsForUser('b1c19dda-2d2e-4777-ad5d-3929f17e86d3')\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose worlds are being retrieved.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getWorldsForUser: function (userId, options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = $.extend(\n _pick(getOptions, ['account', 'project', 'group']),\n { userId: userId }\n );\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Load information for a specific world. All further calls to the world service will use the id provided.\n *\n * **Parameters**\n * @param {String} `worldId` The id of the world to load.\n * @param {Object} `options` (Optional) Options object to override global options.\n */\n load: function (worldId, options) {\n if (worldId) {\n serviceOptions.filter = worldId;\n }\n if (!serviceOptions.filter) {\n throw new Error('Please provide a worldid to load');\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/' });\n return http.get('', httpOptions);\n },\n\n /**\n * Adds an end user or list of end users to a given world. The end user must be a member of the `group` that is associated with this world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // add one user\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.addUsers(['b1c19dda-2d2e-4777-ad5d-3929f17e86d3']);\n * wa.addUsers({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'VP Sales' });\n *\n * // add several users\n * wa.addUsers([\n * { userId: 'a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44',\n * role: 'VP Marketing' },\n * { userId: '8f2604cf-96cd-449f-82fa-e331530734ee',\n * role: 'VP Engineering' }\n * ]);\n *\n * // add one user to a specific world\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', world.id);\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', { filter: world.id });\n * });\n *\n * ** Parameters **\n * @param {string|object|array} `users` User id, array of user ids, object, or array of objects of the users to add to this world.\n * @param {string} `users.role` The `role` the user should have in the world. It is up to the caller to ensure, if needed, that the `role` passed in is one of the `roles` or `optionalRoles` of this world.\n * @param {string} `worldId` The world to which the users should be added. If not specified, the filter parameter of the `options` object is used.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n addUsers: function (users, worldId, options) {\n\n if (!users) {\n throw new Error('Please provide a list of users to add to the world');\n }\n\n // normalize the list of users to an array of user objects\n users = $.map([].concat(users), function (u) {\n var isObject = $.isPlainObject(u);\n\n if (typeof u !== 'string' && !isObject) {\n throw new Error('Some of the users in the list are not in the valid format: ' + u);\n }\n\n return isObject ? u : { userId: u };\n });\n\n // check if options were passed as the second parameter\n if ($.isPlainObject(worldId) && !options) {\n options = worldId;\n worldId = null;\n }\n\n options = options || {};\n\n // we must have options by now\n if (typeof worldId === 'string') {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users' }\n );\n\n return http.post(users, updateOptions);\n },\n\n /**\n * Updates the role of an end user in a given world. (You can only update one end user at a time.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.create().then(function(world) {\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.updateUser({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'leader' });\n * });\n *\n * **Parameters**\n * @param {object} `user` User object with `userId` and the new `role`.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n updateUser: function (user, options) {\n options = options || {};\n\n if (!user || !user.userId) {\n throw new Error('You need to pass a userId to update from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var patchOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.patch(_pick(user, 'role'), patchOptions);\n },\n\n /**\n * Removes an end user from a given world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.addUsers(['a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44', '8f2604cf-96cd-449f-82fa-e331530734ee']);\n * wa.removeUser('a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44');\n * wa.removeUser({ userId: '8f2604cf-96cd-449f-82fa-e331530734ee' });\n * });\n *\n * ** Parameters **\n * @param {object|string} `user` The `userId` of the user to remove from the world, or an object containing the `userId` field.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n removeUser: function (user, options) {\n options = options || {};\n\n if (typeof user === 'string') {\n user = { userId: user };\n }\n\n if (!user.userId) {\n throw new Error('You need to pass a userId to remove from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.delete(null, getOptions);\n },\n\n /**\n * Gets the run id of current run for the given world. If the world does not have a run, creates a new one and returns the run id.\n *\n * Remember that a [run](../../glossary/#run) is a collection of interactions with a project and its model. In the case of multiplayer projects, the run is shared by all end users in the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getCurrentRunId({ model: 'model.py' });\n * });\n *\n * ** Parameters **\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n getCurrentRunId: function (options) {\n options = options || {};\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n validateModelOrThrowError(getOptions);\n return http.post(_pick(getOptions, 'model'), getOptions);\n },\n\n /**\n * Gets the current (most recent) world for the given end user in the given group. Brings this most recent world into memory if needed.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function(world) {\n * // use data from world\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose current (most recent) world is being retrieved.\n * @param {string} `groupName` (Optional) The name of the group. If not provided, defaults to the group used to create the service.\n */\n getCurrentWorldForUser: function (userId, groupName) {\n var dtd = $.Deferred();\n var me = this;\n this.getWorldsForUser(userId, { group: groupName })\n .then(function (worlds) {\n // assume the most recent world as the 'active' world\n worlds.sort(function (a, b) { return new Date(b.lastModified) - new Date(a.lastModified); });\n var currentWorld = worlds[0];\n\n if (currentWorld) {\n serviceOptions.filter = currentWorld.id;\n }\n\n dtd.resolve(currentWorld, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Deletes the current run from the world.\n *\n * (Note that the world id remains part of the run record, indicating that the run was formerly an active run for the world.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.deleteRun('sample-world-id');\n *\n * **Parameters**\n * @param {string} `worldId` The `worldId` of the world from which the current run is being deleted.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n deleteRun: function (worldId, options) {\n options = options || {};\n\n if (worldId) {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Creates a new run for the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function (world) {\n * wa.newRunForWorld(world.id);\n * });\n *\n * **Parameters**\n * @param {string} `worldId` worldId in which we create the new run.\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n newRunForWorld: function (worldId, options) {\n var currentRunOptions = $.extend(true, {},\n options,\n { filter: worldId || serviceOptions.filter }\n );\n var _this = this;\n\n validateModelOrThrowError(currentRunOptions);\n\n return this.deleteRun(worldId, options)\n .then(function () {\n return _this.getCurrentRunId(currentRunOptions);\n });\n },\n\n /**\n * Assigns end users to worlds, creating new worlds as appropriate, automatically. Assigns all end users in the group, and creates new worlds as needed based on the project-level world configuration (roles, optional roles, and minimum end users per world).\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.autoAssign();\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n autoAssign: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(assignmentEndpoint) }\n );\n\n var params = {\n account: opt.account,\n project: opt.project,\n group: opt.group\n };\n\n if (opt.maxUsers) {\n params.maxUsers = opt.maxUsers;\n }\n\n return http.post(params, opt);\n },\n\n /**\n * Gets the project's world configuration.\n *\n * Typically, every interaction with your project uses the same configuration of each world. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both.\n *\n * (The [Multiplayer Project REST API](../../../rest_apis/multiplayer/multiplayer_project/) allows you to set these project-level world configurations. The World Adapter simply retrieves them, for example so they can be used in auto-assignment of end users to worlds.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getProjectSettings()\n * .then(function(settings) {\n * console.log(settings.roles);\n * console.log(settings.optionalRoles);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getProjectSettings: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(projectEndpoint) }\n );\n\n opt.url += [opt.account, opt.project].join('/');\n\n return http.get(null, opt);\n }\n\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n* ## User API Adapter\n*\n* The User API Adapter allows you to retrieve details about end users in your team (account). It is based on the querying capabilities of the underlying RESTful [User API](../../../rest_apis/user_management/user/).\n*\n* To use the User API Adapter, instantiate it and then call its methods.\n*\n* var ua = new F.service.User({\n* account: 'acme-simulations',\n* token: 'user-or-project-access-token'\n* });\n* ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n* ua.get({ userName: 'jsmith' });\n* ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n* '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n*\n* The constructor takes an optional `options` parameter in which you can specify the `account` and `token` if they are not already available in the current context.\n*/\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar qutil = require('../util/query-util');\n\nmodule.exports = function (config) {\n var defaults = {\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The access token to use when searching for end users. (See [more background on access tokens](../../../project_access/)).\n * @type {String}\n */\n token: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('user')\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Retrieve details about particular end users in your team, based on user name or user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.get({ userName: 'jsmith' });\n * ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n * '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n *\n * **Parameters**\n * @param {object} `filter` Object with field `userName` and value of the username. Alternatively, object with field `id` and value of an array of user ids.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n get: function (filter, options) {\n options = options || {};\n filter = filter || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options\n );\n\n var toQFilter = function (filter) {\n var res = {};\n\n // API only supports filtering by username for now\n if (filter.userName) {\n res.q = filter.userName;\n }\n\n return res;\n };\n\n var toIdFilters = function (id) {\n if (!id) {\n return '';\n }\n\n id = $.isArray(id) ? id : [id];\n return 'id=' + id.join('&id=');\n };\n\n var getFilters = [\n 'account=' + getOptions.account,\n toIdFilters(filter.id),\n qutil.toQueryFormat(toQFilter(filter))\n ].join('&');\n\n // special case for queries with large number of ids\n // make it as a post with GET semantics\n var threshold = 30;\n if (filter.id && $.isArray(filter.id) && filter.id.length >= threshold) {\n getOptions.url = urlConfig.getAPIPath('user') + '?_method=GET';\n return http.post({ id: filter.id }, getOptions);\n } else {\n return http.get(getFilters, getOptions);\n }\n },\n\n /**\n * Retrieve details about a single end user in your team, based on user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n *\n * **Parameters**\n * @param {string} `userId` The user id for the end user in your team.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n getById: function (userId, options) {\n return publicAPI.get({ id: userId }, options);\n }\n };\n\n $.extend(this, publicAPI);\n};\n\n\n\n\n","/**\n *\n * ## Member API Adapter\n *\n * The Member API Adapter provides methods to look up information about end users for your project and how they are divided across groups. It is based on query capabilities of the underlying RESTful [Member API](../../../rest_apis/user_management/member/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/). For example, if some of your end users are facilitators, or if your end users should be treated differently based on which group they are in, use the Member API to find that information.\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser({ userId: 'b6b313a3-ab84-479c-baea-206f6bff337' });\n * ma.getGroupDetails({ groupId: '00b53308-9833-47f2-b21e-1278c07d53b8' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'member/local';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Epicenter user id. Defaults to a blank string.\n * @type {string}\n */\n userId: undefined,\n\n /**\n * Epicenter group id. Defaults to a blank string. Note that this is the group *id*, not the group *name*.\n * @type {string}\n */\n groupId: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(transportOptions, serviceOptions);\n\n var getFinalParams = function (params) {\n if (typeof params === 'object') {\n return $.extend(true, serviceOptions, params);\n }\n return serviceOptions;\n };\n\n var patchUserActiveField = function (params, active, options) {\n var httpOptions = $.extend(true, serviceOptions, options, {\n url: urlConfig.getAPIPath(apiEndpoint) + params.groupId + '/' + params.userId\n });\n\n return http.patch({ active: active }, httpOptions);\n };\n\n var publicAPI = {\n\n /**\n * Retrieve details about all of the group memberships for one end user. The membership details are returned in an array, with one element (group record) for each group to which the end user belongs.\n *\n * In the membership array, each group record includes the group id, project id, account (team) id, and an array of members. However, only the user whose userId is included in the call is listed in the members array (regardless of whether there are other members in this group).\n *\n * **Example**\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser('42836d4b-5b61-4fe4-80eb-3136e956ee5c')\n * .then(function(memberships){\n * for (var i=0; i\n * // \n * // \n * // \n * // \n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar SessionManager = require('../store/session-manager');\n\nvar apiEndpoint = 'asset';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n /**\n * The group name. Defaults to session's `groupName`.\n * @type {String}\n */\n group: undefined,\n /**\n * The user id. Defaults to session's `userId`.\n * @type {String}\n */\n userId: undefined,\n /**\n * The scope for the asset. Valid values are: `user`, `group`, and `project`. See above for the required permissions to write to each scope. Defaults to `user`, meaning the current end user or a facilitator in the end user's group can edit the asset.\n * @type {String}\n */\n scope: 'user',\n /**\n * Determines if a request to list the assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`). Defaults to `true`.\n * @type {boolean}\n */\n fullUrl: true,\n /**\n * The transport object contains the options passed to the XHR request.\n * @type {object}\n */\n transport: {\n processData: false\n }\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var assetApiParams = ['encoding', 'data', 'contentType'];\n var scopeConfig = {\n user: ['scope', 'account', 'project', 'group', 'userId'],\n group: ['scope', 'account', 'project', 'group'],\n project: ['scope', 'account', 'project'],\n };\n\n var validateFilename = function (filename) {\n if (!filename) {\n throw new Error('filename is needed.');\n }\n };\n\n var validateUrlParams = function (options) {\n var partKeys = scopeConfig[options.scope];\n if (!partKeys) {\n throw new Error('scope parameter is needed.');\n }\n\n $.each(partKeys, function () {\n if (!options[this]) {\n throw new Error(this + ' parameter is needed.');\n }\n });\n };\n\n var buildUrl = function (filename, options) {\n validateUrlParams(options);\n var partKeys = scopeConfig[options.scope];\n var parts = $.map(partKeys, function (key) {\n return options[key];\n });\n if (filename) {\n // This prevents adding a trailing / in the URL as the Asset API\n // does not work correctly with it\n filename = '/' + filename;\n }\n return urlConfig.getAPIPath(apiEndpoint) + parts.join('/') + filename;\n };\n\n // Private function, all requests follow a more or less same approach to\n // use the Asset API and the difference is the HTTP verb\n //\n // @param {string} `method` (Required) HTTP verb\n // @param {string} `filename` (Required) Name of the file to delete/replace/create\n // @param {object} `params` (Optional) Body parameters to send to the Asset API\n // @param {object} `options` (Optional) Options object to override global options.\n var upload = function (method, filename, params, options) {\n validateFilename(filename);\n // make sure the parameter is clean\n method = method.toLowerCase();\n var contentType = params instanceof FormData === true ? false : 'application/json';\n if (contentType === 'application/json') {\n // whitelist the fields that we actually can send to the api\n params = _pick(params, assetApiParams);\n } else { // else we're sending form data which goes directly in request body\n // For multipart/form-data uploads the filename is not set in the URL,\n // it's getting picked by the FormData field filename.\n filename = method === 'post' || method === 'put' ? '' : filename;\n }\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var createOptions = $.extend(true, {}, urlOptions, { url: url, contentType: contentType });\n\n return http[method](params, createOptions);\n };\n\n var publicAPI = {\n /**\n * Creates a file in the Asset API. The server returns an error (status code `409`, conflict) if the file already exists, so\n * check first with a `list()` or a `get()`.\n *\n * **Example**\n *\n * var aa = new F.service.Asset({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * userId: ''\n * });\n *\n * // create a new asset using encoded text\n * aa.create('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHRlc3QgZmlsZS4=',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, create a new asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to create.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (filename, params, options) {\n return upload('post', filename, params, options);\n },\n\n /**\n * Gets a file from the Asset API, fetching the asset content. (To get a list\n * of the assets in a scope, use `list()`.)\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to retrieve.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n get: function (filename, options) {\n var getServiceOptions = _pick(serviceOptions, ['scope', 'account', 'project', 'group', 'userId']);\n var urlOptions = $.extend({}, getServiceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n\n return http.get({}, getOptions);\n },\n\n /**\n * Gets the list of the assets in a scope.\n *\n * **Example**\n *\n * aa.list({ fullUrl: true }).then(function(fileList){\n * console.log('array of files = ', fileList);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {string} `options.scope` (Optional) The scope (`user`, `group`, `project`).\n * @param {boolean} `options.fullUrl` (Optional) Determines if the list of assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`).\n *\n */\n list: function (options) {\n var dtd = $.Deferred();\n var me = this;\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl('', urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n var fullUrl = getOptions.fullUrl;\n\n if (!fullUrl) {\n return http.get({}, getOptions);\n }\n\n http.get({}, getOptions)\n .then(function (files) {\n var fullPathFiles = $.map(files, function (file) {\n return buildUrl(file, urlOptions);\n });\n dtd.resolve(fullPathFiles, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Replaces an existing file in the Asset API.\n *\n * **Example**\n *\n * // replace an asset using encoded text\n * aa.replace('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHNlY29uZCB0ZXN0IGZpbGUu',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, replace an asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#replace-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#replace-filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.replace(filename, data, { scope: 'user' });\n * });\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file being replaced.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n replace: function (filename, params, options) {\n return upload('put', filename, params, options);\n },\n\n /**\n * Deletes a file from the Asset API.\n *\n * **Example**\n *\n * aa.delete(sampleFileName);\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to delete.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n delete: function (filename, options) {\n return upload('delete', filename, {}, options);\n },\n\n assetUrl: function (filename, options) {\n var urlOptions = $.extend({}, serviceOptions, options);\n return buildUrl(filename, urlOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ## Group API Adapter\n *\n * The Group API Adapter provides methods to look up, create, change or remove information about groups in a project. It is based on query capabilities of the underlying RESTful [Group API](../../../rest_apis/user_management/group/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/).\n *\n * var ma = new F.service.Group({ token: 'user-or-project-access-token' });\n * ma.getGroupsForProject({ account: 'acme', project: 'sample' });\n */\n\n'use strict';\n\nvar serviceUtils = require('./service-utils');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar objectAssign = require('object-assign');\n\nvar apiEndpoint = 'group/local';\n\nvar GroupService = function (config) {\n var defaults = {\n /**\n * Epicenter account name. Defaults to undefined.\n * @type {string}\n */\n account: undefined,\n\n /**\n * Epicenter project name. Defaults to undefined.\n * @type {string}\n */\n project: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n var serviceOptions = serviceUtils.getDefaultOptions(defaults, config, { apiEndpoint: apiEndpoint });\n var transportOptions = serviceOptions.transport;\n delete serviceOptions.transport;\n var http = new TransportFactory(transportOptions, serviceOptions);\n var publicAPI = {\n /*\n * Gets information for a group or multiple groups.\n * @param {string} `params` the groupId of the target group\n * @param {Object} `params` object with query parameters\n * @patam {string} `params.q` partial match for name, organization or event.\n * @patam {string} `params.account` Epicenter's Team ID\n * @patam {string} `params.project` Epicenter's Project ID\n * @patam {string} `params.name` Epicenter's Group Name\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getGroups: function (params, options) {\n //groupID is part of the URL\n //q, account and project are part of the query string\n var finalOpts = objectAssign({}, serviceOptions, options);\n var finalParams;\n if (typeof params === 'string') {\n finalOpts.url = serviceUtils.getApiUrl(apiEndpoint + '/' + params, finalOpts);\n } else {\n finalParams = params;\n }\n return http.get(finalParams, finalOpts);\n }\n };\n objectAssign(this, publicAPI);\n};\n\nmodule.exports = GroupService;\n","/**\n * @class Cookie Storage Service\n *\n * @example\n * var people = require('cookie-store')({ root: 'people' });\n people\n .save({lastName: 'smith' })\n\n */\n\n\n'use strict';\n\n// Thin document.cookie wrapper to allow unit testing\nvar Cookie = function () {\n this.get = function () {\n return document.cookie;\n };\n\n this.set = function (newCookie) {\n document.cookie = newCookie;\n };\n};\n\nmodule.exports = function (config) {\n var host = window.location.hostname;\n var validHost = host.split('.').length > 1;\n var domain = validHost ? '.' + host : null;\n\n var defaults = {\n /**\n * Name of collection\n * @type { string}\n */\n root: '/',\n\n domain: domain,\n cookie: new Cookie()\n };\n this.serviceOptions = $.extend({}, defaults, config);\n\n var publicAPI = {\n // * TBD\n // * Query collection; uses MongoDB syntax\n // * @see \n // *\n // * @param { string} qs Query Filter\n // * @param { string} limiters @see \n // *\n // * @example\n // * cs.query(\n // * { name: 'John', className: 'CSC101' },\n // * {limit: 10}\n // * )\n\n // query: function (qs, limiters) {\n\n // },\n\n /**\n * Save cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @param {Object} value (Optional)\n * @param {Object} options Overrides for service options\n *\n * @return {*} The saved value\n *\n * @example\n * cs.set('person', { firstName: 'john', lastName: 'smith' });\n * cs.set({ name:'smith', age:'32' });\n */\n set: function (key, value, options) {\n var setOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = setOptions.domain;\n var path = setOptions.root;\n var cookie = setOptions.cookie;\n\n cookie.set(encodeURIComponent(key) + '=' +\n encodeURIComponent(value) +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '')\n );\n\n return value;\n },\n\n /**\n * Load cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @return {*} The value stored\n *\n * @example\n * cs.get('person');\n */\n get: function (key) {\n var cookie = this.serviceOptions.cookie;\n var cookieReg = new RegExp('(?:^|;)\\\\s*' + encodeURIComponent(key).replace(/[\\-\\.\\+\\*]/g, '\\\\$&') + '\\\\s*\\\\=\\\\s*([^;]*).*$');\n var res = cookieReg.exec(cookie.get());\n var val = res ? decodeURIComponent(res[1]) : null;\n return val;\n },\n\n /**\n * Removes key from collection\n * @param { string} key key to remove\n * @return { string} key The key removed\n *\n * @example\n * cs.remove('person');\n */\n remove: function (key, options) {\n var remOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = remOptions.domain;\n var path = remOptions.root;\n var cookie = remOptions.cookie;\n\n cookie.set(encodeURIComponent(key) +\n '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '')\n );\n return key;\n },\n\n /**\n * Removes collection being referenced\n * @return { array} keys All the keys removed\n */\n destroy: function () {\n var cookie = this.serviceOptions.cookie;\n var aKeys = cookie.get().replace(/((?:^|\\s*;)[^\\=]+)(?=;|$)|^\\s*|\\s*(?:\\=[^;]*)?(?:\\1|$)/g, '').split(/\\s*(?:\\=[^;]*)?;\\s*/);\n for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {\n var cookieKey = decodeURIComponent(aKeys[nIdx]);\n this.remove(cookieKey);\n }\n return aKeys;\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n Decides type of store to provide\n*/\n\n'use strict';\n// var isNode = false; FIXME: Browserify/minifyify has issues with the next link\n// var store = (isNode) ? require('./session-store') : require('./cookie-store');\nvar store = require('./cookie-store');\n\nmodule.exports = store;\n","'use strict';\nvar RunService = require('../service/run-api-service');\n\nvar defaults = {\n validFilter: { saved: true }\n};\n\nfunction ScenarioManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n this.runService = this.options.run || new RunService(this.options);\n}\n\nScenarioManager.prototype = {\n getRuns: function (filter) {\n this.filter = $.extend(true, {}, this.options.validFilter, filter);\n return this.runService.query(this.filter);\n },\n\n loadVariables: function (vars) {\n return this.runService.query(this.filter, { include: vars });\n },\n\n save: function (run, meta) {\n return this._getService(run).save($.extend(true, {}, { saved: true }, meta));\n },\n\n archive: function (run) {\n return this._getService(run).save({ saved: false });\n },\n\n _getService: function (run) {\n if (typeof run === 'string') {\n return new RunService($.extend(true, {}, this.options, { filter: run }));\n }\n\n if (typeof run === 'object' && run instanceof RunService) {\n return run;\n }\n\n throw new Error('Save method requires a run service or a runId');\n },\n\n getRun: function (runId) {\n return new RunService($.extend(true, {}, this.options, { filter: runId }));\n }\n};\n\nmodule.exports = ScenarioManager;\n\n","/**\n* ## Run Manager\n*\n* The Run Manager gives you access to runs for your project. This allows you to read and update variables, call operations, etc. Additionally, the Run Manager gives you control over run creation depending on run states. Specifically, you can select [run creation strategies (rules)](../../strategy/) for which runs end users of your project work with when they log in to your project.\n*\n* There are many ways to create new runs, including the Epicenter.js [Run Service](../run-api-service/), the RESFTful [Run API](../../../rest_apis/aggregate_run_api) and the [Model Run API](../../../rest_apis/other_apis/model_apis/run/). However, for some projects it makes more sense to pick up where the user left off, using an existing run. And in some projects, whether to create a new run or use an existing one is conditional, for example based on characteristics of the existing run or your own knowledge about the model. The Run Manager provides this level of control: your call to `getRun()`, rather than always returning a new run, returns a run based on the strategy you've specified. (Note that many of the Epicenter sample projects use a Run Service directly, because generally the sample projects are played in one end user session and don't care about run states or run strategies.)\n*\n*\n* ### Using the Run Manager to create and access runs\n*\n* To use the Run Manager, instantiate it by passing in:\n*\n* * `run`: (required) Run object. Must contain:\n* * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n* * `project`: Epicenter project id.\n* * `model`: The name of your primary model file. (See more on [Writing your Model](../../../writing_your_model/).)\n* * `scope`: (optional) Scope object for the run, for example `scope.group` with value of the name of the group.\n* * `server`: (optional) An object with one field, `host`. The value of `host` is the string `api.forio.com`, the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n* * `files`: (optional) If and only if you are using a Vensim model and you have additional data to pass in to your model, you can pass a `files` object with the names of the files, for example: `\"files\": {\"data\": \"myExtraData.xls\"}`. (Note that you'll also need to add this same files object to your Vensim [configuration file](../../../model_code/vensim/).) See the [underlying Model Run API](../../../rest_apis/other_apis/model_apis/run/#post-creating-a-new-run-for-this-project) for additional information.\n*\n* * `strategy`: (optional) Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n*\n* * `sessionKey`: (optional) Name of browser cookie in which to store run information, including run id. Many conditional strategies, including the provided strategies, rely on this browser cookie to store the run id and help make the decision of whether to create a new run or use an existing one. The name of this cookie defaults to `epicenter-scenario` and can be set with the `sessionKey` parameter.\n*\n*\n* After instantiating a Run Manager, make a call to `getRun()` whenever you need to access a run for this end user. The `RunManager.run` contains the instantiated [Run Service](../run-api-service/). The Run Service allows you to access variables, call operations, etc.\n*\n* **Example**\n*\n* var rm = new F.manager.RunManager({\n* run: {\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* model: 'supply-chain-model.jl',\n* server: { host: 'api.forio.com' }\n* },\n* strategy: 'always-new',\n* sessionKey: 'epicenter-session'\n* });\n* rm.getRun()\n* .then(function(run) {\n* // the return value of getRun() is a run object\n* var thisRunId = run.id;\n* // the RunManager.run also contains the instantiated Run Service,\n* // so any Run Service method is valid here\n* rm.run.do('runModel');\n* })\n*\n*/\n\n'use strict';\nvar strategiesMap = require('./run-strategies/strategies-map');\nvar specialOperations = require('./special-operations');\nvar RunService = require('../service/run-api-service');\n\n\nfunction patchRunService(service, manager) {\n if (service.patched) {\n return service;\n }\n\n var orig = service.do;\n service.do = function (operation, params, options) {\n var reservedOps = Object.keys(specialOperations);\n if (reservedOps.indexOf(operation) === -1) {\n return orig.apply(service, arguments);\n } else {\n return specialOperations[operation].call(service, params, options, manager);\n }\n };\n\n service.patched = true;\n\n return service;\n}\n\n\n\nvar defaults = {\n /**\n * Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n * @type {String}\n */\n\n strategy: 'new-if-initialized'\n};\n\nfunction RunManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n if (this.options.run instanceof RunService) {\n this.run = this.options.run;\n } else {\n this.run = new RunService(this.options.run);\n }\n\n patchRunService(this.run, this);\n\n var StrategyCtor = typeof this.options.strategy === 'function' ? this.options.strategy : strategiesMap[this.options.strategy];\n\n if (!StrategyCtor) {\n throw new Error('Specified run creation strategy was invalid:', this.options.strategy);\n }\n\n this.strategy = new StrategyCtor(this.run, this.options);\n}\n\nRunManager.prototype = {\n /**\n * Returns the run object for a 'good' run.\n *\n * A good run is defined by the strategy. For example, if the strategy is `always-new`, the call\n * to `getRun()` always returns a newly created run; if the strategy is `new-if-persisted`,\n * `getRun()` creates a new run if the previous run is in a persisted state, otherwise\n * it returns the previous run. See [Run Manager Strategies](../../strategy/) for more on strategies.\n *\n * **Example**\n *\n * rm.getRun().then(function (run) {\n * // use the run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * @return {$promise} Promise to complete the call.\n */\n getRun: function () {\n return this.strategy\n .getRun();\n },\n\n /**\n * Returns the run object for a new run, regardless of strategy: force creation of a new run.\n *\n * **Example**\n *\n * rm.reset().then(function (run) {\n * // use the (new) run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * **Parameters**\n * @param {Object} `runServiceOptions` The options object to configure the Run Service. See [Run API Service](../run-api-service/) for more.\n */\n reset: function (runServiceOptions) {\n return this.strategy.reset(runServiceOptions);\n }\n};\n\nmodule.exports = RunManager;\n","/**\n* ## Authorization Manager\n*\n* The Authorization Manager provides an easy way to manage user authentication (logging in and out) and authorization (keeping track of tokens, sessions, and groups) for projects.\n*\n* The Authorization Manager is most useful for [team projects](../../../glossary/#team) with an access level of [Authenticated](../../../glossary/#access). These projects are accessed by [end users](../../../glossary/#users) who are members of one or more [groups](../../../glossary/#groups).\n*\n* #### Using the Authorization Manager\n*\n* To use the Authorization Manager, instantiate it. Then, make calls to any of the methods you need:\n*\n* var authMgr = new F.manager.AuthManager({\n* account: 'acme-simulations',\n* userName: 'enduser1',\n* password: 'passw0rd'\n* });\n* authMgr.login().then(function () {\n* authMgr.getCurrentUserSessionInfo();\n* });\n*\n*\n* The `options` object passed to the `F.manager.AuthManager()` call can include:\n*\n* * `account`: The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects).\n* * `userName`: Email or username to use for logging in.\n* * `password`: Password for specified `userName`.\n* * `project`: The **Project ID** for the project to log this user into. Optional.\n* * `groupId`: Id of the group to which `userName` belongs. Required for end users if the `project` is specified.\n*\n* If you prefer starting from a template, the Epicenter JS Libs [Login Component](../../#components) uses the Authorization Manager as well. This sample HTML page (and associated CSS and JS files) provides a login form for team members and end users of your project. It also includes a group selector for end users that are members of multiple groups.\n*/\n\n'use strict';\nvar AuthAdapter = require('../service/auth-api-service');\nvar MemberAdapter = require('../service/member-api-adapter');\nvar GroupService = require('../service/group-api-service');\nvar SessionManager = require('../store/session-manager');\nvar Buffer = require('buffer').Buffer;\nvar _pick = require('../util/object-util')._pick;\nvar objectAssign = require('object-assign');\n\nvar defaults = {\n requiresGroup: true\n};\n\nfunction AuthManager(options) {\n options = $.extend(true, {}, defaults, options);\n this.sessionManager = new SessionManager(options);\n this.options = this.sessionManager.getMergedOptions();\n\n this.isLocal = this.options.isLocal;\n this.authAdapter = new AuthAdapter(this.options);\n}\n\nvar _findUserInGroup = function (members, id) {\n for (var j = 0; j 1) {\n if (groupId) {\n var filteredGroups = $.grep(groupList, function (resGroup) {\n return resGroup.groupId === groupId;\n });\n group = filteredGroups.length === 1 ? filteredGroups[0] : null;\n }\n }\n\n if (group) {\n // A team member does not get the group members because is calling the Group API\n // but it's automatically a fac user\n var isFac = isTeamMember ? true : _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator';\n var groupData = {\n groupId: group.groupId,\n groupName: group.name,\n isFac: isFac\n };\n var sessionInfoWithGroup = objectAssign({}, sessionInfo, groupData);\n sessionInfo.groups[project] = groupData;\n _this.sessionManager.saveSession(sessionInfoWithGroup, adapterOptions);\n outSuccess.apply(this, [data]);\n $d.resolve(data);\n } else {\n handleGroupError('This user is associated with more than one group. Please specify a group id to log into and try again', 403, data);\n }\n };\n\n if (!isTeamMember) {\n _this.getUserGroups({ userId: userInfo.user_id, token: token }, userGroupOpts)\n .then(handleGroupList, $d.reject);\n } else {\n var opts = objectAssign({}, userGroupOpts, { token: token });\n var groupService = new GroupService(opts);\n groupService.getGroups({ account: adapterOptions.account, project: project })\n .then(function (groups) {\n // Group API returns id instead of groupId\n groups.forEach(function (group) {\n group.groupId = group.id;\n });\n handleGroupList(groups);\n }, $d.reject);\n }\n };\n\n adapterOptions.success = handleSuccess;\n adapterOptions.error = function (response) {\n if (adapterOptions.account) {\n // Try to login as a system user\n adapterOptions.account = null;\n adapterOptions.error = function () {\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n _this.authAdapter.login(adapterOptions);\n return;\n }\n\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n this.authAdapter.login(adapterOptions);\n return $d.promise();\n },\n\n /**\n * Logs user out by clearing all session information.\n *\n * **Example**\n *\n * authMgr.logout();\n *\n * **Parameters**\n *\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var _this = this;\n var adapterOptions = this.sessionManager.getMergedOptions(options);\n\n var removeCookieFn = function (response) {\n _this.sessionManager.removeSession();\n };\n\n return this.authAdapter.logout(adapterOptions).done(removeCookieFn);\n },\n\n /**\n * Returns the existing user access token if the user is already logged in. Otherwise, logs the user in, creating a new user access token, and returns the new token. (See [more background on access tokens](../../../project_access/)).\n *\n * **Example**\n *\n * authMgr.getToken()\n * .then(function (token) {\n * console.log('My token is ', token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getToken: function (options) {\n var httpOptions = this.sessionManager.getMergedOptions(options);\n\n var session = this.sessionManager.getSession();\n var $d = $.Deferred();\n //jshint camelcase: false\n //jscs:disable\n if (session.auth_token) {\n $d.resolve(session.auth_token);\n } else {\n this.login(httpOptions).then($d.resolve);\n }\n return $d.promise();\n },\n\n /**\n * Returns an array of group records, one for each group of which the current user is a member. Each group record includes the group `name`, `account`, `project`, and `groupId`.\n *\n * If some end users in your project are members of multiple groups, this is a useful method to call on your project's login page. When the user attempts to log in, you can use this to display the groups of which the user is member, and have the user select the correct group to log in to for this session.\n *\n * **Example**\n *\n * // get groups for current user\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n * authMgr.getUserGroups({ userId: sessionObj.userId, token: sessionObj.auth_token })\n * .then(function (groups) {\n * for (var i=0; i < groups.length; i++)\n * { console.log(groups[i].name); }\n * });\n *\n * // get groups for particular user\n * authMgr.getUserGroups({userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', token: savedProjAccessToken });\n *\n * **Parameters**\n * @param {Object} `params` Object with a userId and token properties.\n * @param {String} `params.userId` The userId. If looking up groups for the currently logged in user, this is in the session information. Otherwise, pass a string.\n * @param {String} `params.token` The authorization credentials (access token) to use for checking the groups for this user. If looking up groups for the currently logged in user, this is in the session information. A team member's token or a project access token can access all the groups for all end users in the team or project.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getUserGroups: function (params, options) {\n var adapterOptions = this.sessionManager.getMergedOptions({ success: $.noop }, options);\n var $d = $.Deferred();\n var outSuccess = adapterOptions.success;\n\n adapterOptions.success = function (memberInfo) {\n // The member API is at the account scope, we filter by project\n if (adapterOptions.project) {\n memberInfo = $.grep(memberInfo, function (group) {\n return group.project === adapterOptions.project;\n });\n }\n\n outSuccess.apply(this, [memberInfo]);\n $d.resolve(memberInfo);\n };\n\n var memberAdapter = new MemberAdapter({ token: params.token });\n memberAdapter.getGroupsForUser(params, adapterOptions).fail($d.reject);\n return $d.promise();\n },\n\n /**\n * Returns session information for the current user, including the `userId`, `account`, `project`, `groupId`, `groupName`, `isFac` (whether the end user is a facilitator of this group), and `auth_token` (user access token).\n *\n * *Important*: This method is synchronous. The session information is returned immediately in an object; no callbacks or promises are needed.\n *\n * Session information is stored in a cookie in the browser.\n *\n * **Example**\n *\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getCurrentUserSessionInfo: function (options) {\n return this.sessionManager.getSession(options);\n },\n\n /*\n * Adds one or more groups to the current session. \n *\n * This method assumes that the project and group exist and the user specified in the session is part of this project and group.\n *\n * Returns the new session object.\n *\n * **Example**\n *\n * authMgr.addGroups({ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' });\n * authMgr.addGroups([{ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' }, { project: 'hello-world', groupName: '...' }]);\n *\n * **Parameters**\n * @param {object|array} `groups` (Required) The group object must contain the `project` (**Project ID**) and `groupName` properties. If passing an array of such objects, all of the objects must contain *different* `project` (**Project ID**) values: although end users may be logged in to multiple projects at once, they may only be logged in to one group per project at a time.\n * @param {string} `group.isFac` (optional) Defaults to `false`. Set to `true` if the user in the session should be a facilitator in this group.\n * @param {string} `group.groupId` (optional) Defaults to undefined. Needed mostly for the Members API.\n */\n addGroups: function (groups) {\n var session = this.getCurrentUserSessionInfo();\n var isArray = Array.isArray(groups);\n groups = isArray ? groups : [groups];\n\n $.each(groups, function (index, group) {\n var extendedGroup = $.extend({}, { isFac: false }, group);\n var project = extendedGroup.project;\n var validProps = ['groupName', 'groupId', 'isFac'];\n if (!project || !extendedGroup.groupName) {\n throw new Error('No project or groupName specified.');\n }\n // filter object\n extendedGroup = _pick(extendedGroup, validProps);\n session.groups[project] = extendedGroup;\n });\n this.sessionManager.saveSession(session);\n return session;\n }\n});\n\nmodule.exports = AuthManager;\n","/**\n* ## World Manager\n*\n* As discussed under the [World API Adapter](../world-api-adapter/), a [run](../../../glossary/#run) is a collection of end user interactions with a project and its model. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases.\n*\n* The World Manager provides an easy way to track and access the current world and run for particular end users. It is typically used in pages that end users will interact with. (The related [World API Adapter](../world-api-adapter/) handles creating multiplayer worlds, and adding and removing end users and runs from a world. Because of this, typically the World Adapter is used for facilitator pages in your project.)\n*\n* ### Using the World Manager\n*\n* To use the World Manager, instantiate it. Then, make calls to any of the methods you need.\n*\n* When you instantiate a World Manager, the world's account id, project id, and group are automatically taken from the session (thanks to the [Authentication Service](../auth-api-service)).\n*\n* Note that the World Manager does *not* create worlds automatically. (This is different than the [Run Manager](../run-manager).) However, you can pass in specific options to any runs created by the manager, using a `run` object.\n*\n* The parameters for creating a World Manager are:\n*\n* * `account`: The **Team ID** in the Epicenter user interface for this project.\n* * `project`: The **Project ID** for this project.\n* * `group`: The **Group Name** for this world.\n* * `run`: Options to use when creating new runs with the manager, e.g. `run: { files: ['data.xls'] }`.\n* * `run.model`: The name of the primary model file for this project. Required if you have not already passed it in as part of the `options` parameter for an enclosing call.\n*\n* For example:\n*\n* var wMgr = new F.manager.WorldManager({\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* run: { model: 'supply-chain.py' },\n* group: 'team1'\n* });\n*\n* wMgr.getCurrentRun();\n*/\n\n'use strict';\n\nvar WorldApi = require('../service/world-api-adapter');\nvar RunManager = require('./run-manager');\nvar AuthManager = require('./auth-manager');\nvar worldApi;\n\n// var defaults = {\n// account: '',\n// project: '',\n// group: '',\n// transport: {\n// }\n// };\n\n\nfunction buildStrategy(worldId, dtd) {\n\n return function Ctor(runService, options) {\n this.runService = runService;\n this.options = options;\n\n $.extend(this, {\n reset: function () {\n throw new Error('not implementd. Need api changes');\n },\n\n getRun: function () {\n var _this = this;\n //get or create!\n // Model is required in the options\n var model = this.options.run.model || this.options.model;\n return worldApi.getCurrentRunId({ model: model, filter: worldId })\n .then(function (runId) {\n return _this.runService.load(runId);\n })\n .then(function (run) {\n dtd.resolve.call(this, run, _this.runService);\n })\n .fail(dtd.reject);\n }\n }\n );\n };\n}\n\n\nmodule.exports = function (options) {\n this.options = options || { run: {}, world: {} };\n\n $.extend(true, this.options, this.options.run);\n $.extend(true, this.options, this.options.world);\n\n worldApi = new WorldApi(this.options);\n this._auth = new AuthManager();\n var _this = this;\n\n var api = {\n\n /**\n * Returns the current world (object) and an instance of the [World API Adapter](../world-api-adapter/).\n *\n * **Example**\n *\n * wMgr.getCurrentWorld()\n * .then(function(world, worldAdapter) {\n * console.log(world.id);\n * worldAdapter.getCurrentRunId();\n * });\n *\n * **Parameters**\n * @param {string} `userId` (Optional) The id of the user whose world is being accessed. Defaults to the user in the current session.\n * @param {string} `groupName` (Optional) The name of the group whose world is being accessed. Defaults to the group for the user in the current session.\n */\n getCurrentWorld: function (userId, groupName) {\n var session = this._auth.getCurrentUserSessionInfo();\n if (!userId) {\n userId = session.userId;\n }\n if (!groupName) {\n groupName = session.groupName;\n }\n return worldApi.getCurrentWorldForUser(userId, groupName);\n },\n\n /**\n * Returns the current run (object) and an instance of the [Run API Service](../run-api-service/).\n *\n * **Example**\n *\n * wMgr.getCurrentRun({model: 'myModel.py'})\n * .then(function(run, runService) {\n * console.log(run.id);\n * runService.do('startGame');\n * });\n *\n * **Parameters**\n * @param {string} `model` (Optional) The name of the model file. Required if not already passed in as `run.model` when the World Manager is created.\n */\n getCurrentRun: function (model) {\n var dtd = $.Deferred();\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n function getAndRestoreLatestRun(world) {\n if (!world) {\n return dtd.reject({ error: 'The user is not part of any world!' });\n }\n\n var currentWorldId = world.id;\n var runOpts = $.extend(true, _this.options, { model: model });\n var strategy = buildStrategy(currentWorldId, dtd);\n var opt = $.extend(true, {}, {\n strategy: strategy,\n run: runOpts\n });\n var rm = new RunManager(opt);\n\n return rm.getRun()\n .then(function (run) {\n dtd.resolve(run, rm.runService, rm);\n });\n }\n\n this.getCurrentWorld(curUserId, curGroupName)\n .then(getAndRestoreLatestRun);\n\n return dtd.promise();\n }\n };\n\n $.extend(this, api);\n};\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // always create a new run!\n return true;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar makeSeq = require('../../util/make-sequence');\nvar Base = require('./identity-strategy');\nvar SessionManager = require('../../store/session-manager');\nvar classFrom = require('../../util/inherit');\nvar AuthManager = require('../auth-manager');\n\nvar keyNames = require('../key-names');\n\nvar defaults = {\n sessionKey: keyNames.STRATEGY_SESSION_KEY,\n path: ''\n};\n\nfunction setRunInSession(sessionKey, run, sessionManager) {\n sessionManager.getStore().set(sessionKey, JSON.stringify({ runId: run.id }));\n}\n\n/**\n* Conditional Creation Strategy\n* This strategy will try to get the run stored in the cookie and\n* evaluate if needs to create a new run by calling the 'condition' function\n*/\n\n/* jshint eqnull: true */\nvar Strategy = classFrom(Base, {\n constructor: function Strategy(runService, condition, options) {\n\n if (condition == null) {\n throw new Error('Conditional strategy needs a condition to createte a run');\n }\n\n this._auth = new AuthManager();\n this.run = makeSeq(runService);\n this.condition = typeof condition !== 'function' ? function () { return condition; } : condition;\n this.options = $.extend(true, {}, defaults, options);\n this.sessionManager = new SessionManager(options);\n this.runOptions = this.options.run;\n },\n\n runOptionsWithScope: function () {\n var userSession = this._auth.getCurrentUserSessionInfo();\n return $.extend({\n scope: { group: userSession.groupName }\n }, this.runOptions);\n },\n\n reset: function (runServiceOptions) {\n var _this = this;\n var opt = this.runOptionsWithScope();\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run, _this.sessionManager);\n run.freshlyCreated = true;\n return run;\n })\n .start();\n },\n\n getRun: function () {\n var sessionStore = this.sessionManager.getStore();\n var runSession = JSON.parse(sessionStore.get(this.options.sessionKey));\n\n if (runSession && runSession.runId) {\n return this._loadAndCheck(runSession).fail(function () {\n return this.reset(); //if it got the wrong cookie for e.g.\n }.bind(this));\n } else {\n return this.reset();\n }\n },\n\n _loadAndCheck: function (runSession) {\n var shouldCreate = false;\n var _this = this;\n\n return this.run\n .load(runSession.runId, null, {\n success: function (run, msg, headers) {\n shouldCreate = _this.condition.call(_this, run, headers);\n }\n })\n .then(function (run) {\n if (shouldCreate) {\n var opt = _this.runOptionsWithScope();\n // we need to do this, on the original runService (ie not sequencialized)\n // so we don't get in the middle of the queue\n return _this.run.original.create(opt)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run, _this.sessionManager);\n run.freshlyCreated = true;\n return run;\n });\n }\n\n return run;\n })\n .start();\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar Base = {};\n\n// Interface that all strategies need to implement\nmodule.exports = classFrom(Base, {\n constructor: function (runService, options) {\n this.runService = runService;\n },\n\n reset: function () {\n // return a newly created run\n return $.Deferred().resolve().promise();\n },\n\n getRun: function () {\n // return a usable run\n return $.Deferred().resolve(this.runService).promise();\n }\n});\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\n/*\n* create a new run only if nothing is stored in the cookie\n* this is useful for baseRuns.\n*/\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // if we are here, it means that the run exists... so we don't need a new one\n return false;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent';\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent' || run.initialized;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\n/**\n * ## Channel Service\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Service is a building block for this functionality. It creates a publish-subscribe object, allowing you to publish messages, subscribe to messages, or unsubscribe from messages for a given 'topic' on a `$.cometd` transport instance.\n *\n * Typically, you use the [Epicenter Channel Manager](../epicenter-channel-manager/) to create or retrieve channels, then use the Channel Service `subscribe()` and `publish()` methods to listen to or update data. (For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.)\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Service. See [Including Epicenter.js](../../#include).\n *\n * To use the Channel Service, instantiate it, then make calls to any of the methods you need.\n *\n * var cs = new F.service.Channel();\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * The parameters for instantiating a Channel Service include:\n *\n * * `options` The options object to configure the Channel Service.\n * * `options.base` The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * * `options.topicResolver` A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. Returns a String. By default, it just echoes the topic.\n * * `options.transport` The instance of `$.cometd` to hook onto. See http://docs.cometd.org/reference/javascript.html for additional background on cometd.\n */\nvar Channel = function (options) {\n var defaults = {\n\n /**\n * The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * @type {string}\n */\n base: '',\n\n /**\n * A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. By default, it just echoes the topic.\n *\n * **Parameters**\n *\n * * `topic` Topic to parse.\n *\n * **Return Value**\n *\n * * *String*: This function should return a string topic.\n *\n * @type {function}\n */\n topicResolver: function (topic) {\n return topic;\n },\n\n /**\n * The instance of `$.cometd` to hook onto.\n * @type {object}\n */\n transport: null\n };\n this.channelOptions = $.extend(true, {}, defaults, options);\n};\n\nvar makeName = function (channelName, topic) {\n //Replace trailing/double slashes\n var newName = (channelName ? (channelName + '/' + topic) : topic).replace(/\\/\\//g, '/').replace(/\\/$/,'');\n return newName;\n};\n\n\nChannel.prototype = $.extend(Channel.prototype, {\n\n // future functionality:\n // // Set the context for the callback\n // cs.subscribe('run', function () { this.innerHTML = 'Triggered'}, document.body);\n //\n // // Control the order of operations by setting the `priority`\n // cs.subscribe('run', cb, this, {priority: 9});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is 50\n // cs.subscribe('run/variables/price', cb, this, {priority: 30, value: 50});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is greater than 50\n // subscribe('run/variables/price', cb, this, {priority: 30, value: '>50'});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is even\n // subscribe('run/variables/price', cb, this, {priority: 30, value: function (val) {return val % 2 === 0}});\n\n\n /**\n * Subscribe to changes on a topic.\n *\n * The topic should include the full path of the account id (**Team ID** for team projects), project id, and group name. (In most cases, it is simpler to use the [Epicenter Channel Manager](../epicenter-channel-manager/) instead, in which case this is configured for you.)\n *\n * **Examples**\n *\n * var cb = function(val) { console.log(val.data); };\n *\n * // Subscribe to changes on a top-level 'run' topic\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run', cb);\n *\n * // Subscribe to changes on children of the 'run' topic. Note this will also be triggered for changes to run.x.y.z.\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/*', cb);\n *\n * // Subscribe to changes on both the top-level 'run' topic and its children\n * cs.subscribe(['/acme-simulations/supply-chain-game/fall-seminar/run',\n * '/acme-simulations/supply-chain-game/fall-seminar/run/*'], cb);\n *\n * // Subscribe to changes on a particular variable\n * subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/variables/price', cb);\n *\n *\n * **Return Value**\n *\n * * *String* Returns a token you can later use to unsubscribe.\n *\n * **Parameters**\n * @param {String|Array} `topic` List of topics to listen for changes on.\n * @param {Function} `callback` Callback function to execute. Callback is called with signature `(evt, payload, metadata)`.\n * @param {Object} `context` Context in which the `callback` is executed.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n * @param {Number} `options.priority` Used to control order of operations. Defaults to 0. Can be any +ve or -ve number.\n * @param {String|Number|Function} `options.value` The `callback` is only triggered if this condition matches. See examples for details.\n *\n */\n subscribe: function (topic, callback, context, options) {\n\n var topics = [].concat(topic);\n var me = this;\n var subscriptionIds = [];\n var opts = me.channelOptions;\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n subscriptionIds.push(opts.transport.subscribe(topic, callback));\n });\n });\n return (subscriptionIds[1] ? subscriptionIds : subscriptionIds[0]);\n },\n\n /**\n * Publish data to a topic.\n *\n * **Examples**\n *\n * // Send data to all subscribers of the 'run' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run', { completed: false });\n *\n * // Send data to all subscribers of the 'run/variables' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * **Parameters**\n *\n * @param {String} `topic` Topic to publish to.\n * @param {*} `data` Data to publish to topic.\n *\n */\n publish: function (topic, data) {\n var topics = [].concat(topic);\n var me = this;\n var returnObjs = [];\n var opts = me.channelOptions;\n\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n if (topic.charAt(topic.length - 1) === '*') {\n topic = topic.replace(/\\*+$/, '');\n console.warn('You can cannot publish to channels with wildcards. Publishing to ', topic, 'instead');\n }\n returnObjs.push(opts.transport.publish(topic, data));\n });\n });\n return (returnObjs[1] ? returnObjs : returnObjs[0]);\n },\n\n /**\n * Unsubscribe from changes to a topic.\n *\n * **Example**\n *\n * cs.unsubscribe('sampleToken');\n *\n * **Parameters**\n * @param {String} `token` The token for topic is returned when you initially subscribe. Pass it here to unsubscribe from that topic.\n */\n unsubscribe: function (token) {\n this.channelOptions.transport.unsubscribe(token);\n return token;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n\n});\n\nmodule.exports = Channel;\n","'use strict';\n\n/**\n * ## Epicenter Channel Manager\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Epicenter Channel Manager is a wrapper around the (more generic) [Channel Manager](../channel-manager/), to instantiate it with Epicenter-specific defaults. If you are interested in including a notification or chat feature in your project, using an Epicenter Channel Manager is probably the easiest way to get started.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Epicenter Channel Manager. See [Including Epicenter.js](../../#include).\n *\n * To use the Epicenter Channel Manager: instantiate it, get the channel of the scope you want ([user](../../../glossary/#users), [world](../../../glossary/#world), or [group](../../../glossary/#groups)), then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.\n *\n * The parameters for instantiating an Epicenter Channel Manager include:\n *\n * * `options` Object with details about the Epicenter project for this Epicenter Channel Manager instance.\n * * `options.account` The Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `options.project` Epicenter project id.\n * * `options.userName` Epicenter userName used for authentication.\n * * `options.userId` Epicenter user id used for authentication. Optional; `options.userName` is preferred.\n * * `options.token` Epicenter token used for authentication. (You can retrieve this using `authManager.getToken()` from the [Authorization Manager](../auth-manager/).)\n * * `options.allowAllChannels` If not included or if set to `false`, all channel paths are validated; if your project requires [Push Channel Authorization](../../../updating_your_settings/), you should use this option. If you want to allow other channel paths, set to `true`; this is not common.\n */\n\nvar ChannelManager = require('./channel-manager');\nvar classFrom = require('../util/inherit');\nvar urlService = require('../service/url-config-service');\nvar SessionManager = require('../store/session-manager');\n\nvar AuthManager = require('./auth-manager');\n\nvar validTypes = {\n project: true,\n group: true,\n world: true,\n user: true,\n data: true,\n general: true,\n chat: true\n};\nvar session = new AuthManager();\nvar getFromSettingsOrSessionOrError = function (value, sessionKeyName, settings) {\n if (!value) {\n var userInfo = session.getCurrentUserSessionInfo();\n if (settings && settings[sessionKeyName]) {\n value = settings[sessionKeyName];\n } else if (userInfo[sessionKeyName]) {\n value = userInfo[sessionKeyName];\n } else {\n throw new Error(sessionKeyName + ' not found. Please log-in again, or specify ' + sessionKeyName + ' explicitly');\n }\n }\n return value;\n};\nvar __super = ChannelManager.prototype;\nvar EpicenterChannelManager = classFrom(ChannelManager, {\n constructor: function (options) {\n this.sessionManager = new SessionManager();\n var defaultCometOptions = this.sessionManager.getMergedOptions(options);\n\n var urlOpts = urlService(defaultCometOptions.server);\n if (!defaultCometOptions.url) {\n //Default epicenter cometd endpoint\n defaultCometOptions.url = urlOpts.protocol + '://' + urlOpts.host + '/channel/subscribe';\n }\n\n if (defaultCometOptions.handshake === undefined) {\n var userName = defaultCometOptions.userName;\n var userId = defaultCometOptions.userId;\n var token = defaultCometOptions.token;\n if ((userName || userId) && token) {\n var userProp = userName ? 'userName' : 'userId';\n var ext = {\n authorization: 'Bearer ' + token\n };\n ext[userProp] = userName ? userName : userId;\n\n defaultCometOptions.handshake = {\n ext: ext\n };\n }\n }\n\n this.options = defaultCometOptions;\n return __super.constructor.call(this, defaultCometOptions);\n },\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * This method enforces Epicenter-specific channel naming: all channels requested must be in the form `/{type}/{account id}/{project id}/{...}`, where `type` is one of `run`, `data`, `user`, `world`, or `chat`.\n *\n * **Example**\n *\n * var cm = new F.manager.EpicenterChannelManager();\n * var channel = cm.getChannel('/group/acme/supply-chain-game/');\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} `options` (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n */\n getChannel: function (options) {\n if (options && typeof options !== 'object') {\n options = {\n base: options\n };\n }\n var channelOpts = $.extend({}, this.options, options);\n var base = channelOpts.base;\n if (!base) {\n throw new Error('No base topic was provided');\n }\n\n if (!channelOpts.allowAllChannels) {\n var baseParts = base.split('/');\n var channelType = baseParts[1];\n if (baseParts.length < 4) {\n throw new Error('Invalid channel base name, it must be in the form /{type}/{account id}/{project id}/{...}');\n }\n if (!validTypes[channelType]) {\n throw new Error('Invalid channel type');\n }\n }\n return __super.getChannel.apply(this, arguments);\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [group](../../../glossary/#groups). The group must exist in the account (team) and project provided.\n *\n * There are no notifications from Epicenter on this channel; all messages are user-originated.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `groupName` (Optional) Group to broadcast to. If not provided, picks up group from current session if end user is logged in.\n */\n getGroupChannel: function (groupName) {\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/group', account, project, groupName].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var worldChannel = cm.getWorldChannel(worldObject);\n * worldChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` The world object or id.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getWorldChannel: function (world, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/world', account, project, groupName, worldid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the current [end user](../../../glossary/#users) in that user's current [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager). Note that this channel only gets notifications for worlds currently in memory. (See more background on [persistence](../../../run_persistence).)\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var userChannel = cm.getUserChannel(worldObject);\n * userChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `user` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getUserChannel: function (world, user, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n var userid = ($.isPlainObject(user) && user.id) ? user.id : user;\n userid = getFromSettingsOrSessionOrError(userid, 'userId', this.options);\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/user', account, project, groupName, worldid, userid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) that automatically tracks the presence of an [end user](../../../glossary/#users), that is, whether the end user is currently online in this group and world. Notifications are automatically sent when the end user comes online, and when the end user goes offline (not present for more than 2 minutes). Useful in multiplayer games for letting each end user know whether other users in their shared world are also online.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'model.eqn'\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldService) {\n * var presenceChannel = cm.getPresenceChannel(worldObject);\n * presenceChannel.on('presence', function (evt, notification) {\n * console.log(notification.online, notification.userId);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `userid` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getPresenceChannel: function (world, userid, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n userid = getFromSettingsOrSessionOrError(userid, 'userId', this.options);\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/user', account, project, groupName, worldid].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n var lastPingTime = { };\n\n var PING_INTERVAL = 6000;\n channel.subscribe('internal-ping-channel', function (notification) {\n var incomingUserId = notification.data.user;\n if (!lastPingTime[incomingUserId] && incomingUserId !== userid) {\n channel.trigger.call(channel, 'presence', { userId: incomingUserId, online: true });\n }\n lastPingTime[incomingUserId] = (new Date()).valueOf();\n });\n\n setInterval(function () {\n channel.publish('internal-ping-channel', { user: userid });\n\n $.each(lastPingTime, function (key, value) {\n var now = (new Date()).valueOf();\n if (value && value + (PING_INTERVAL * 2) < now) {\n lastPingTime[key] = null;\n channel.trigger.call(channel, 'presence', { userId: key, online: false });\n }\n });\n }, PING_INTERVAL);\n\n return channel;\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given collection. (The collection name is specified in the `root` argument when the [Data Service](../data-api-service/) is instantiated.) Must be one of the collections in this account (team) and project.\n *\n * There are automatic notifications from Epicenter on this channel when data is created, updated, or deleted in this collection. See more on [automatic messages to the data channel](../../../rest_apis/multiplayer/channel/#data-messages).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var dc = cm.getDataChannel('survey-responses');\n * dc.subscribe('', function(data, meta) {\n * console.log(data);\n *\n * // meta.date is time of change,\n * // meta.subType is the kind of change: new, update, or delete\n * // meta.path is the full path to the changed data\n * console.log(meta);\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `collection` Name of collection whose automatic notifications you want to receive.\n */\n getDataChannel: function (collection) {\n if (!collection) {\n throw new Error('Please specify a collection to listen on.');\n }\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n var baseTopic = ['/data', account, project, collection].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n //TODO: Fix after Epicenter bug is resolved\n var oldsubs = channel.subscribe;\n channel.subscribe = function (topic, callback, context, options) {\n var callbackWithCleanData = function (payload) {\n var meta = {\n path: payload.channel,\n subType: payload.data.subType,\n date: payload.data.date\n };\n var actualData = payload.data.data;\n if (actualData.data) { //Delete notifications are one data-level behind of course\n actualData = actualData.data;\n }\n\n callback.call(context, actualData, meta);\n };\n return oldsubs.call(channel, topic, callbackWithCleanData, context, options);\n };\n\n return channel;\n }\n});\n\nmodule.exports = EpicenterChannelManager;\n","'use strict';\n\nmodule.exports = {\n _pick: function (obj, props) {\n var res = {};\n for (var p in obj) {\n if (props.indexOf(p) !== -1) {\n res[p] = obj[p];\n }\n }\n\n return res;\n }\n};\n","'use strict';\n\nvar keyNames = require('../managers/key-names');\nvar StorageFactory = require('./store-factory');\nvar optionUtils = require('../util/option-utils');\n\nvar EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY;\nvar defaults = {\n /**\n * Where to store user access tokens for temporary access. Defaults to storing in a cookie in the browser.\n * @type {string}\n */\n store: { synchronous: true }\n};\n\nvar SessionManager = function (managerOptions) {\n managerOptions = managerOptions || {};\n function getBaseOptions(overrides) {\n overrides = overrides || {};\n var libOptions = optionUtils.getOptions();\n var finalOptions = $.extend(true, {}, defaults, libOptions, managerOptions, overrides);\n return finalOptions;\n }\n\n function getStore(overrides) {\n var baseOptions = getBaseOptions(overrides);\n var storeOpts = baseOptions.store || {};\n if (storeOpts.root === undefined && baseOptions.account && baseOptions.project && !baseOptions.isLocal) {\n storeOpts.root = '/app/' + baseOptions.account + '/' + baseOptions.project;\n }\n return new StorageFactory(storeOpts);\n }\n\n var publicAPI = {\n saveSession: function (userInfo, options) {\n var serialized = JSON.stringify(userInfo);\n getStore(options).set(EPI_SESSION_KEY, serialized);\n },\n getSession: function (options) {\n // var session = getStore(options).get(EPI_SESSION_KEY) || '{}';\n // return JSON.parse(session);\n var store = getStore(options);\n var finalOpts = store.serviceOptions;\n var serialized = store.get(EPI_SESSION_KEY) || '{}';\n var session = JSON.parse(serialized);\n // If the url contains the project and account\n // validate the account and project in the session\n // and override project, groupName, groupId and isFac\n // Otherwise (i.e. localhost) use the saved session values\n var account = finalOpts.account;\n var project = finalOpts.project;\n if (account && session.account !== account) {\n // This means that the token was not used to login to the same account\n return {};\n }\n if (session.groups && account && project) {\n var group = session.groups[project] || { groupId: '', groupName: '', isFac: false };\n $.extend(session, { project: project }, group);\n }\n return session;\n },\n removeSession: function (options) {\n var store = getStore(options);\n Object.keys(keyNames).forEach(function (cookieKey) {\n var cookieName = keyNames[cookieKey];\n store.remove(cookieName);\n });\n return true;\n },\n getStore: function (options) {\n return getStore(options);\n },\n\n getMergedOptions: function () {\n var args = Array.prototype.slice.call(arguments);\n var overrides = $.extend.apply($, [true, {}].concat(args));\n var baseOptions = getBaseOptions(overrides);\n var session = this.getSession(overrides);\n\n var sessionDefaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n //jshint camelcase: false\n //jscs:disable\n token: session.auth_token,\n /**\n * The group name. If left undefined, taken from the cookie session.\n * @type {String}\n */\n group: session.groupName,\n /**\n * The group id. If left undefined, taken from the cookie session.\n * @type {String}\n */\n groupId: session.groupId,\n userId: session.userId\n };\n return $.extend(true, sessionDefaults, baseOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n\nmodule.exports = SessionManager;","'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar SessionManager = require('../store/session-manager');\nvar objectAssign = require('object-assign');\n\nvar serviceUtils = {\n /*\n * Gets the default options for a api service.\n * It will merge:\n * - The Session options (Using the Session Manager)\n * - The Authorization Header from the token option\n * - The full url from the endpoint option\n * With the supplied overrides and defaults\n *\n */\n getDefaultOptions: function (defaults) {\n var rest = Array.prototype.slice.call(arguments, 1);\n var sessionManager = new SessionManager();\n var serviceOptions = sessionManager.getMergedOptions.apply(sessionManager, [defaults].concat(rest));\n\n serviceOptions.transport = objectAssign({}, serviceOptions.transport, {\n url: this.getApiUrl(serviceOptions.apiEndpoint, serviceOptions)\n });\n\n if (serviceOptions.token) {\n serviceOptions.transport.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n return serviceOptions;\n },\n\n getApiUrl: function (apiEndpoint, serviceOptions) {\n var urlConfig = new ConfigService(serviceOptions).get('server');\n return urlConfig.getAPIPath(apiEndpoint);\n }\n};\n\nmodule.exports = serviceUtils;","module.exports = {\n 'new-if-initialized': require('./new-if-initialized-strategy'),\n 'new-if-persisted': require('./new-if-persisted-strategy'),\n 'new-if-missing': require('./new-if-missing-strategy'),\n 'always-new': require('./always-new-strategy'),\n 'multiplayer': require('./multiplayer-strategy'),\n 'persistent-single-player': require('./persistent-single-player-strategy'),\n 'none': require('./identity-strategy')\n};\n","'use strict';\n\n\nmodule.exports = {\n reset: function (params, options, manager) {\n return manager.reset(options);\n }\n};\n","'use strict';\n\nvar Channel = require('../service/channel-service');\nvar SessionManager = require('../store/session-manager');\n\n/**\n * ## Channel Manager\n *\n * There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Manager is a wrapper around the default [cometd JavaScript library](http://docs.cometd.org/2/reference/javascript.html), `$.cometd`. It provides a few nice features that `$.cometd` doesn't, including:\n *\n * * Automatic re-subscription to channels if you lose your connection\n * * Online / Offline notifications\n * * 'Events' for cometd notifications (instead of having to listen on specific meta channels)\n *\n * While you can work directly with the Channel Manager through Node.js (for example, `require('manager/channel-manager')`) -- or even work directly with `$.cometd` and Epicenter's underlying [Push Channel API](../../../rest_apis/multiplayer/channel/) -- most often it will be easiest to work with the [Epicenter Channel Manager](../epicenter-channel-manager/). The Epicenter Channel Manager is a wrapper that instantiates a Channel Manager with Epicenter-specific defaults.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Manager. (See [Including Epicenter.js](../../#include).)\n *\n * To use the Channel Manager in client-side JavaScript, instantiate the [Epicenter Channel Manager](../epicenter-channel-manager/), get the channel, then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * The parameters for instantiating a Channel Manager include:\n *\n * * `options` The options object to configure the Channel Manager. Besides the common options listed here, see http://docs.cometd.org/reference/javascript.html for other supported options.\n * * `options.url` The Cometd endpoint URL.\n * * `options.websocketEnabled` Whether websocket support is active (boolean).\n * * `options.channel` Other defaults to pass on to instances of the underlying Channel Service. See [Channel Service](../channel-service/) for details.\n *\n */\nvar ChannelManager = function (options) {\n if (!$.cometd) {\n throw new Error('Cometd library not found. Please include epicenter-multiplayer-dependencies.js');\n }\n if (!options || !options.url) {\n throw new Error('Please provide an url for the cometd server');\n }\n\n var defaults = {\n /**\n * The Cometd endpoint URL.\n * @type {string}\n */\n url: '',\n\n /**\n * The log level for the channel (logs to console).\n * @type {string}\n */\n logLevel: 'info',\n\n /**\n * Whether websocket support is active. Defaults to `false`; Epicenter doesn't currently support communication through websockets.\n * @type {boolean}\n */\n websocketEnabled: false,\n\n /**\n * If false each instance of Channel will have a separate cometd connection to server, which could be noisy. Set to true to re-use the same connection across instances.\n * @type {boolean}\n */\n shareConnection: false,\n\n /**\n * Other defaults to pass on to instances of the underlying [Channel Service](../channel-service/), which are created through `getChannel()`.\n * @type {object}\n */\n channel: {\n\n },\n\n /**\n * Options to pass to the channel handshake.\n *\n * For example, the [Epicenter Channel Manager](../epicenter-channel-manager/) passes `ext` and authorization information. More information on possible options is in the details of the underlying [Push Channel API](../../../rest_apis/multiplayer/channel/).\n *\n * @type {object}\n */\n handshake: undefined\n };\n this.sessionManager = new SessionManager();\n var defaultCometOptions = this.sessionManager.getMergedOptions(defaults, options);\n this.currentSubscriptions = [];\n this.options = defaultCometOptions;\n\n if (defaultCometOptions.shareConnection && ChannelManager.prototype._cometd) {\n this.cometd = ChannelManager.prototype._cometd;\n return this;\n }\n var cometd = new $.Cometd();\n ChannelManager.prototype._cometd = cometd;\n\n cometd.websocketEnabled = defaultCometOptions.websocketEnabled;\n\n this.isConnected = false;\n var connectionBroken = function (message) {\n $(this).trigger('disconnect', message);\n };\n var connectionSucceeded = function (message) {\n $(this).trigger('connect', message);\n };\n var me = this;\n\n cometd.configure(defaultCometOptions);\n\n cometd.addListener('/meta/connect', function (message) {\n var wasConnected = this.isConnected;\n this.isConnected = (message.successful === true);\n if (!wasConnected && this.isConnected) { //Connecting for the first time\n connectionSucceeded.call(this, message);\n } else if (wasConnected && !this.isConnected) { //Only throw disconnected message fro the first disconnect, not once per try\n connectionBroken.call(this, message);\n }\n }.bind(this));\n\n cometd.addListener('/meta/disconnect', connectionBroken);\n\n cometd.addListener('/meta/handshake', function (message) {\n if (message.successful) {\n //http://docs.cometd.org/reference/javascript_subscribe.html#javascript_subscribe_meta_channels\n // ^ \"dynamic subscriptions are cleared (like any other subscription) and the application needs to figure out which dynamic subscription must be performed again\"\n cometd.batch(function () {\n $(me.currentSubscriptions).each(function (index, subs) {\n cometd.resubscribe(subs);\n });\n });\n }\n });\n\n //Other interesting events for reference\n cometd.addListener('/meta/subscribe', function (message) {\n $(me).trigger('subscribe', message);\n });\n cometd.addListener('/meta/unsubscribe', function (message) {\n $(me).trigger('unsubscribe', message);\n });\n cometd.addListener('/meta/publish', function (message) {\n $(me).trigger('publish', message);\n });\n cometd.addListener('/meta/unsuccessful', function (message) {\n $(me).trigger('error', message);\n });\n\n cometd.handshake(defaultCometOptions.handshake);\n\n this.cometd = cometd;\n};\n\n\nChannelManager.prototype = $.extend(ChannelManager.prototype, {\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} `options` (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n */\n getChannel: function (options) {\n //If you just want to pass in a string\n if (options && !$.isPlainObject(options)) {\n options = {\n base: options\n };\n }\n var defaults = {\n transport: this.cometd\n };\n var channel = new Channel($.extend(true, {}, this.options.channel, defaults, options));\n\n\n //Wrap subs and unsubs so we can use it to re-attach handlers after being disconnected\n var subs = channel.subscribe;\n channel.subscribe = function () {\n var subid = subs.apply(channel, arguments);\n this.currentSubscriptions = this.currentSubscriptions.concat(subid);\n return subid;\n }.bind(this);\n\n\n var unsubs = channel.unsubscribe;\n channel.unsubscribe = function () {\n var removed = unsubs.apply(channel, arguments);\n for (var i = 0; i < this.currentSubscriptions.length; i++) {\n if (this.currentSubscriptions[i].id === removed.id) {\n this.currentSubscriptions.splice(i, 1);\n }\n }\n return removed;\n }.bind(this);\n\n return channel;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n});\n\nmodule.exports = ChannelManager;\n","'use strict';\n\nmodule.exports = {\n EPI_SESSION_KEY: 'epicenterjs.session',\n STRATEGY_SESSION_KEY: 'epicenter-scenario'\n};","/*!\n * The buffer module from node.js, for the browser.\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\n/* eslint-disable no-proto */\n\n'use strict'\n\nvar base64 = require('base64-js')\nvar ieee754 = require('ieee754')\nvar isArray = require('isarray')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n * === true Use Uint8Array implementation (fastest)\n * === false Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n * incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n ? global.TYPED_ARRAY_SUPPORT\n : typedArraySupport()\n\n/*\n * Export kMaxLength after typed array support is determined.\n */\nexports.kMaxLength = kMaxLength()\n\nfunction typedArraySupport () {\n try {\n var arr = new Uint8Array(1)\n arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}\n return arr.foo() === 42 && // typed array instances can be augmented\n typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n } catch (e) {\n return false\n }\n}\n\nfunction kMaxLength () {\n return Buffer.TYPED_ARRAY_SUPPORT\n ? 0x7fffffff\n : 0x3fffffff\n}\n\nfunction createBuffer (that, length) {\n if (kMaxLength() < length) {\n throw new RangeError('Invalid typed array length')\n }\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = new Uint8Array(length)\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n if (that === null) {\n that = new Buffer(length)\n }\n that.length = length\n }\n\n return that\n}\n\n/**\n * The Buffer constructor returns instances of `Uint8Array` that have their\n * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of\n * `Uint8Array`, so the returned instances will have all the node `Buffer` methods\n * and the `Uint8Array` methods. Square bracket notation works as expected -- it\n * returns a single octet.\n *\n * The `Uint8Array` prototype remains unmodified.\n */\n\nfunction Buffer (arg, encodingOrOffset, length) {\n if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {\n return new Buffer(arg, encodingOrOffset, length)\n }\n\n // Common case.\n if (typeof arg === 'number') {\n if (typeof encodingOrOffset === 'string') {\n throw new Error(\n 'If encoding is specified then the first argument must be a string'\n )\n }\n return allocUnsafe(this, arg)\n }\n return from(this, arg, encodingOrOffset, length)\n}\n\nBuffer.poolSize = 8192 // not used by this implementation\n\n// TODO: Legacy, not needed anymore. Remove in next major version.\nBuffer._augment = function (arr) {\n arr.__proto__ = Buffer.prototype\n return arr\n}\n\nfunction from (that, value, encodingOrOffset, length) {\n if (typeof value === 'number') {\n throw new TypeError('\"value\" argument must not be a number')\n }\n\n if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {\n return fromArrayBuffer(that, value, encodingOrOffset, length)\n }\n\n if (typeof value === 'string') {\n return fromString(that, value, encodingOrOffset)\n }\n\n return fromObject(that, value)\n}\n\n/**\n * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError\n * if value is a number.\n * Buffer.from(str[, encoding])\n * Buffer.from(array)\n * Buffer.from(buffer)\n * Buffer.from(arrayBuffer[, byteOffset[, length]])\n **/\nBuffer.from = function (value, encodingOrOffset, length) {\n return from(null, value, encodingOrOffset, length)\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n Buffer.prototype.__proto__ = Uint8Array.prototype\n Buffer.__proto__ = Uint8Array\n if (typeof Symbol !== 'undefined' && Symbol.species &&\n Buffer[Symbol.species] === Buffer) {\n // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97\n Object.defineProperty(Buffer, Symbol.species, {\n value: null,\n configurable: true\n })\n }\n}\n\nfunction assertSize (size) {\n if (typeof size !== 'number') {\n throw new TypeError('\"size\" argument must be a number')\n }\n}\n\nfunction alloc (that, size, fill, encoding) {\n assertSize(size)\n if (size <= 0) {\n return createBuffer(that, size)\n }\n if (fill !== undefined) {\n // Only pay attention to encoding if it's a string. This\n // prevents accidentally sending in a number that would\n // be interpretted as a start offset.\n return typeof encoding === 'string'\n ? createBuffer(that, size).fill(fill, encoding)\n : createBuffer(that, size).fill(fill)\n }\n return createBuffer(that, size)\n}\n\n/**\n * Creates a new filled Buffer instance.\n * alloc(size[, fill[, encoding]])\n **/\nBuffer.alloc = function (size, fill, encoding) {\n return alloc(null, size, fill, encoding)\n}\n\nfunction allocUnsafe (that, size) {\n assertSize(size)\n that = createBuffer(that, size < 0 ? 0 : checked(size) | 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) {\n for (var i = 0; i < size; ++i) {\n that[i] = 0\n }\n }\n return that\n}\n\n/**\n * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.\n * */\nBuffer.allocUnsafe = function (size) {\n return allocUnsafe(null, size)\n}\n/**\n * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.\n */\nBuffer.allocUnsafeSlow = function (size) {\n return allocUnsafe(null, size)\n}\n\nfunction fromString (that, string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') {\n encoding = 'utf8'\n }\n\n if (!Buffer.isEncoding(encoding)) {\n throw new TypeError('\"encoding\" must be a valid string encoding')\n }\n\n var length = byteLength(string, encoding) | 0\n that = createBuffer(that, length)\n\n that.write(string, encoding)\n return that\n}\n\nfunction fromArrayLike (that, array) {\n var length = checked(array.length) | 0\n that = createBuffer(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nfunction fromArrayBuffer (that, array, byteOffset, length) {\n array.byteLength // this throws if `array` is not a valid ArrayBuffer\n\n if (byteOffset < 0 || array.byteLength < byteOffset) {\n throw new RangeError('\\'offset\\' is out of bounds')\n }\n\n if (array.byteLength < byteOffset + (length || 0)) {\n throw new RangeError('\\'length\\' is out of bounds')\n }\n\n if (byteOffset === undefined && length === undefined) {\n array = new Uint8Array(array)\n } else if (length === undefined) {\n array = new Uint8Array(array, byteOffset)\n } else {\n array = new Uint8Array(array, byteOffset, length)\n }\n\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = array\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n that = fromArrayLike(that, array)\n }\n return that\n}\n\nfunction fromObject (that, obj) {\n if (Buffer.isBuffer(obj)) {\n var len = checked(obj.length) | 0\n that = createBuffer(that, len)\n\n if (that.length === 0) {\n return that\n }\n\n obj.copy(that, 0, 0, len)\n return that\n }\n\n if (obj) {\n if ((typeof ArrayBuffer !== 'undefined' &&\n obj.buffer instanceof ArrayBuffer) || 'length' in obj) {\n if (typeof obj.length !== 'number' || isnan(obj.length)) {\n return createBuffer(that, 0)\n }\n return fromArrayLike(that, obj)\n }\n\n if (obj.type === 'Buffer' && isArray(obj.data)) {\n return fromArrayLike(that, obj.data)\n }\n }\n\n throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')\n}\n\nfunction checked (length) {\n // Note: cannot use `length < kMaxLength` here because that fails when\n // length is NaN (which is otherwise coerced to zero.)\n if (length >= kMaxLength()) {\n throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n 'size: 0x' + kMaxLength().toString(16) + ' bytes')\n }\n return length | 0\n}\n\nfunction SlowBuffer (length) {\n if (+length != length) { // eslint-disable-line eqeqeq\n length = 0\n }\n return Buffer.alloc(+length)\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n throw new TypeError('Arguments must be Buffers')\n }\n\n if (a === b) return 0\n\n var x = a.length\n var y = b.length\n\n for (var i = 0, len = Math.min(x, y); i < len; ++i) {\n if (a[i] !== b[i]) {\n x = a[i]\n y = b[i]\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n switch (String(encoding).toLowerCase()) {\n case 'hex':\n case 'utf8':\n case 'utf-8':\n case 'ascii':\n case 'binary':\n case 'base64':\n case 'raw':\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return true\n default:\n return false\n }\n}\n\nBuffer.concat = function concat (list, length) {\n if (!isArray(list)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n\n if (list.length === 0) {\n return Buffer.alloc(0)\n }\n\n var i\n if (length === undefined) {\n length = 0\n for (i = 0; i < list.length; ++i) {\n length += list[i].length\n }\n }\n\n var buffer = Buffer.allocUnsafe(length)\n var pos = 0\n for (i = 0; i < list.length; ++i) {\n var buf = list[i]\n if (!Buffer.isBuffer(buf)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n buf.copy(buffer, pos)\n pos += buf.length\n }\n return buffer\n}\n\nfunction byteLength (string, encoding) {\n if (Buffer.isBuffer(string)) {\n return string.length\n }\n if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&\n (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {\n return string.byteLength\n }\n if (typeof string !== 'string') {\n string = '' + string\n }\n\n var len = string.length\n if (len === 0) return 0\n\n // Use a for loop to avoid recursion\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'ascii':\n case 'binary':\n case 'raw':\n case 'raws':\n return len\n case 'utf8':\n case 'utf-8':\n case undefined:\n return utf8ToBytes(string).length\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return len * 2\n case 'hex':\n return len >>> 1\n case 'base64':\n return base64ToBytes(string).length\n default:\n if (loweredCase) return utf8ToBytes(string).length // assume utf8\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\nBuffer.byteLength = byteLength\n\nfunction slowToString (encoding, start, end) {\n var loweredCase = false\n\n // No need to verify that \"this.length <= MAX_UINT32\" since it's a read-only\n // property of a typed array.\n\n // This behaves neither like String nor Uint8Array in that we set start/end\n // to their upper/lower bounds if the value passed is out of range.\n // undefined is handled specially as per ECMA-262 6th Edition,\n // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.\n if (start === undefined || start < 0) {\n start = 0\n }\n // Return early if start > this.length. Done here to prevent potential uint32\n // coercion fail below.\n if (start > this.length) {\n return ''\n }\n\n if (end === undefined || end > this.length) {\n end = this.length\n }\n\n if (end <= 0) {\n return ''\n }\n\n // Force coersion to uint32. This will also coerce falsey/NaN values to 0.\n end >>>= 0\n start >>>= 0\n\n if (end <= start) {\n return ''\n }\n\n if (!encoding) encoding = 'utf8'\n\n while (true) {\n switch (encoding) {\n case 'hex':\n return hexSlice(this, start, end)\n\n case 'utf8':\n case 'utf-8':\n return utf8Slice(this, start, end)\n\n case 'ascii':\n return asciiSlice(this, start, end)\n\n case 'binary':\n return binarySlice(this, start, end)\n\n case 'base64':\n return base64Slice(this, start, end)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return utf16leSlice(this, start, end)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = (encoding + '').toLowerCase()\n loweredCase = true\n }\n }\n}\n\n// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect\n// Buffer instances.\nBuffer.prototype._isBuffer = true\n\nfunction swap (b, n, m) {\n var i = b[n]\n b[n] = b[m]\n b[m] = i\n}\n\nBuffer.prototype.swap16 = function swap16 () {\n var len = this.length\n if (len % 2 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 16-bits')\n }\n for (var i = 0; i < len; i += 2) {\n swap(this, i, i + 1)\n }\n return this\n}\n\nBuffer.prototype.swap32 = function swap32 () {\n var len = this.length\n if (len % 4 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 32-bits')\n }\n for (var i = 0; i < len; i += 4) {\n swap(this, i, i + 3)\n swap(this, i + 1, i + 2)\n }\n return this\n}\n\nBuffer.prototype.toString = function toString () {\n var length = this.length | 0\n if (length === 0) return ''\n if (arguments.length === 0) return utf8Slice(this, 0, length)\n return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.equals = function equals (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return true\n return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n var str = ''\n var max = exports.INSPECT_MAX_BYTES\n if (this.length > 0) {\n str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n if (this.length > max) str += ' ... '\n }\n return ''\n}\n\nBuffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {\n if (!Buffer.isBuffer(target)) {\n throw new TypeError('Argument must be a Buffer')\n }\n\n if (start === undefined) {\n start = 0\n }\n if (end === undefined) {\n end = target ? target.length : 0\n }\n if (thisStart === undefined) {\n thisStart = 0\n }\n if (thisEnd === undefined) {\n thisEnd = this.length\n }\n\n if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {\n throw new RangeError('out of range index')\n }\n\n if (thisStart >= thisEnd && start >= end) {\n return 0\n }\n if (thisStart >= thisEnd) {\n return -1\n }\n if (start >= end) {\n return 1\n }\n\n start >>>= 0\n end >>>= 0\n thisStart >>>= 0\n thisEnd >>>= 0\n\n if (this === target) return 0\n\n var x = thisEnd - thisStart\n var y = end - start\n var len = Math.min(x, y)\n\n var thisCopy = this.slice(thisStart, thisEnd)\n var targetCopy = target.slice(start, end)\n\n for (var i = 0; i < len; ++i) {\n if (thisCopy[i] !== targetCopy[i]) {\n x = thisCopy[i]\n y = targetCopy[i]\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nfunction arrayIndexOf (arr, val, byteOffset, encoding) {\n var indexSize = 1\n var arrLength = arr.length\n var valLength = val.length\n\n if (encoding !== undefined) {\n encoding = String(encoding).toLowerCase()\n if (encoding === 'ucs2' || encoding === 'ucs-2' ||\n encoding === 'utf16le' || encoding === 'utf-16le') {\n if (arr.length < 2 || val.length < 2) {\n return -1\n }\n indexSize = 2\n arrLength /= 2\n valLength /= 2\n byteOffset /= 2\n }\n }\n\n function read (buf, i) {\n if (indexSize === 1) {\n return buf[i]\n } else {\n return buf.readUInt16BE(i * indexSize)\n }\n }\n\n var foundIndex = -1\n for (var i = byteOffset; i < arrLength; ++i) {\n if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {\n if (foundIndex === -1) foundIndex = i\n if (i - foundIndex + 1 === valLength) return foundIndex * indexSize\n } else {\n if (foundIndex !== -1) i -= i - foundIndex\n foundIndex = -1\n }\n }\n\n return -1\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {\n if (typeof byteOffset === 'string') {\n encoding = byteOffset\n byteOffset = 0\n } else if (byteOffset > 0x7fffffff) {\n byteOffset = 0x7fffffff\n } else if (byteOffset < -0x80000000) {\n byteOffset = -0x80000000\n }\n byteOffset >>= 0\n\n if (this.length === 0) return -1\n if (byteOffset >= this.length) return -1\n\n // Negative offsets start from the end of the buffer\n if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)\n\n if (typeof val === 'string') {\n val = Buffer.from(val, encoding)\n }\n\n if (Buffer.isBuffer(val)) {\n // special case: looking for empty string/buffer always fails\n if (val.length === 0) {\n return -1\n }\n return arrayIndexOf(this, val, byteOffset, encoding)\n }\n if (typeof val === 'number') {\n if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {\n return Uint8Array.prototype.indexOf.call(this, val, byteOffset)\n }\n return arrayIndexOf(this, [ val ], byteOffset, encoding)\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\nBuffer.prototype.includes = function includes (val, byteOffset, encoding) {\n return this.indexOf(val, byteOffset, encoding) !== -1\n}\n\nfunction hexWrite (buf, string, offset, length) {\n offset = Number(offset) || 0\n var remaining = buf.length - offset\n if (!length) {\n length = remaining\n } else {\n length = Number(length)\n if (length > remaining) {\n length = remaining\n }\n }\n\n // must be an even number of digits\n var strLen = string.length\n if (strLen % 2 !== 0) throw new Error('Invalid hex string')\n\n if (length > strLen / 2) {\n length = strLen / 2\n }\n for (var i = 0; i < length; ++i) {\n var parsed = parseInt(string.substr(i * 2, 2), 16)\n if (isNaN(parsed)) return i\n buf[offset + i] = parsed\n }\n return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction binaryWrite (buf, string, offset, length) {\n return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n // Buffer#write(string)\n if (offset === undefined) {\n encoding = 'utf8'\n length = this.length\n offset = 0\n // Buffer#write(string, encoding)\n } else if (length === undefined && typeof offset === 'string') {\n encoding = offset\n length = this.length\n offset = 0\n // Buffer#write(string, offset[, length][, encoding])\n } else if (isFinite(offset)) {\n offset = offset | 0\n if (isFinite(length)) {\n length = length | 0\n if (encoding === undefined) encoding = 'utf8'\n } else {\n encoding = length\n length = undefined\n }\n // legacy write(string, encoding, offset, length) - remove in v0.13\n } else {\n throw new Error(\n 'Buffer.write(string, encoding, offset[, length]) is no longer supported'\n )\n }\n\n var remaining = this.length - offset\n if (length === undefined || length > remaining) length = remaining\n\n if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n throw new RangeError('Attempt to write outside buffer bounds')\n }\n\n if (!encoding) encoding = 'utf8'\n\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'hex':\n return hexWrite(this, string, offset, length)\n\n case 'utf8':\n case 'utf-8':\n return utf8Write(this, string, offset, length)\n\n case 'ascii':\n return asciiWrite(this, string, offset, length)\n\n case 'binary':\n return binaryWrite(this, string, offset, length)\n\n case 'base64':\n // Warning: maxLength not taken into account in base64Write\n return base64Write(this, string, offset, length)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return ucs2Write(this, string, offset, length)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n return {\n type: 'Buffer',\n data: Array.prototype.slice.call(this._arr || this, 0)\n }\n}\n\nfunction base64Slice (buf, start, end) {\n if (start === 0 && end === buf.length) {\n return base64.fromByteArray(buf)\n } else {\n return base64.fromByteArray(buf.slice(start, end))\n }\n}\n\nfunction utf8Slice (buf, start, end) {\n end = Math.min(buf.length, end)\n var res = []\n\n var i = start\n while (i < end) {\n var firstByte = buf[i]\n var codePoint = null\n var bytesPerSequence = (firstByte > 0xEF) ? 4\n : (firstByte > 0xDF) ? 3\n : (firstByte > 0xBF) ? 2\n : 1\n\n if (i + bytesPerSequence <= end) {\n var secondByte, thirdByte, fourthByte, tempCodePoint\n\n switch (bytesPerSequence) {\n case 1:\n if (firstByte < 0x80) {\n codePoint = firstByte\n }\n break\n case 2:\n secondByte = buf[i + 1]\n if ((secondByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n if (tempCodePoint > 0x7F) {\n codePoint = tempCodePoint\n }\n }\n break\n case 3:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n codePoint = tempCodePoint\n }\n }\n break\n case 4:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n fourthByte = buf[i + 3]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n codePoint = tempCodePoint\n }\n }\n }\n }\n\n if (codePoint === null) {\n // we did not generate a valid codePoint so insert a\n // replacement char (U+FFFD) and advance only 1 byte\n codePoint = 0xFFFD\n bytesPerSequence = 1\n } else if (codePoint > 0xFFFF) {\n // encode to utf16 (surrogate pair dance)\n codePoint -= 0x10000\n res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n codePoint = 0xDC00 | codePoint & 0x3FF\n }\n\n res.push(codePoint)\n i += bytesPerSequence\n }\n\n return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n var len = codePoints.length\n if (len <= MAX_ARGUMENTS_LENGTH) {\n return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n }\n\n // Decode in chunks to avoid \"call stack size exceeded\".\n var res = ''\n var i = 0\n while (i < len) {\n res += String.fromCharCode.apply(\n String,\n codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n )\n }\n return res\n}\n\nfunction asciiSlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i] & 0x7F)\n }\n return ret\n}\n\nfunction binarySlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i])\n }\n return ret\n}\n\nfunction hexSlice (buf, start, end) {\n var len = buf.length\n\n if (!start || start < 0) start = 0\n if (!end || end < 0 || end > len) end = len\n\n var out = ''\n for (var i = start; i < end; ++i) {\n out += toHex(buf[i])\n }\n return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n var bytes = buf.slice(start, end)\n var res = ''\n for (var i = 0; i < bytes.length; i += 2) {\n res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n }\n return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n var len = this.length\n start = ~~start\n end = end === undefined ? len : ~~end\n\n if (start < 0) {\n start += len\n if (start < 0) start = 0\n } else if (start > len) {\n start = len\n }\n\n if (end < 0) {\n end += len\n if (end < 0) end = 0\n } else if (end > len) {\n end = len\n }\n\n if (end < start) end = start\n\n var newBuf\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n newBuf = this.subarray(start, end)\n newBuf.__proto__ = Buffer.prototype\n } else {\n var sliceLen = end - start\n newBuf = new Buffer(sliceLen, undefined)\n for (var i = 0; i < sliceLen; ++i) {\n newBuf[i] = this[i + start]\n }\n }\n\n return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n checkOffset(offset, byteLength, this.length)\n }\n\n var val = this[offset + --byteLength]\n var mul = 1\n while (byteLength > 0 && (mul *= 0x100)) {\n val += this[offset + --byteLength] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return ((this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16)) +\n (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] * 0x1000000) +\n ((this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n this[offset + 3])\n}\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var i = byteLength\n var mul = 1\n var val = this[offset + --i]\n while (i > 0 && (mul *= 0x100)) {\n val += this[offset + --i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n if (!(this[offset] & 0x80)) return (this[offset])\n return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset] | (this[offset + 1] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset + 1] | (this[offset] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16) |\n (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] << 24) |\n (this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n if (!Buffer.isBuffer(buf)) throw new TypeError('\"buffer\" argument must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('\"value\" argument is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n var maxBytes = Math.pow(2, 8 * byteLength) - 1\n checkInt(this, value, offset, byteLength, maxBytes, 0)\n }\n\n var mul = 1\n var i = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n var maxBytes = Math.pow(2, 8 * byteLength) - 1\n checkInt(this, value, offset, byteLength, maxBytes, 0)\n }\n\n var i = byteLength - 1\n var mul = 1\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {\n buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n (littleEndian ? i : 1 - i) * 8\n }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffffffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {\n buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset + 3] = (value >>> 24)\n this[offset + 2] = (value >>> 16)\n this[offset + 1] = (value >>> 8)\n this[offset] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = 0\n var mul = 1\n var sub = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {\n sub = 1\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = byteLength - 1\n var mul = 1\n var sub = 0\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {\n sub = 1\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n if (value < 0) value = 0xff + value + 1\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n this[offset + 2] = (value >>> 16)\n this[offset + 3] = (value >>> 24)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (value < 0) value = 0xffffffff + value + 1\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n if (offset < 0) throw new RangeError('Index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n }\n ieee754.write(buf, value, offset, littleEndian, 23, 4)\n return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n }\n ieee754.write(buf, value, offset, littleEndian, 52, 8)\n return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n if (!start) start = 0\n if (!end && end !== 0) end = this.length\n if (targetStart >= target.length) targetStart = target.length\n if (!targetStart) targetStart = 0\n if (end > 0 && end < start) end = start\n\n // Copy 0 bytes; we're done\n if (end === start) return 0\n if (target.length === 0 || this.length === 0) return 0\n\n // Fatal error conditions\n if (targetStart < 0) {\n throw new RangeError('targetStart out of bounds')\n }\n if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n // Are we oob?\n if (end > this.length) end = this.length\n if (target.length - targetStart < end - start) {\n end = target.length - targetStart + start\n }\n\n var len = end - start\n var i\n\n if (this === target && start < targetStart && targetStart < end) {\n // descending copy from end\n for (i = len - 1; i >= 0; --i) {\n target[i + targetStart] = this[i + start]\n }\n } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n // ascending copy from start\n for (i = 0; i < len; ++i) {\n target[i + targetStart] = this[i + start]\n }\n } else {\n Uint8Array.prototype.set.call(\n target,\n this.subarray(start, start + len),\n targetStart\n )\n }\n\n return len\n}\n\n// Usage:\n// buffer.fill(number[, offset[, end]])\n// buffer.fill(buffer[, offset[, end]])\n// buffer.fill(string[, offset[, end]][, encoding])\nBuffer.prototype.fill = function fill (val, start, end, encoding) {\n // Handle string cases:\n if (typeof val === 'string') {\n if (typeof start === 'string') {\n encoding = start\n start = 0\n end = this.length\n } else if (typeof end === 'string') {\n encoding = end\n end = this.length\n }\n if (val.length === 1) {\n var code = val.charCodeAt(0)\n if (code < 256) {\n val = code\n }\n }\n if (encoding !== undefined && typeof encoding !== 'string') {\n throw new TypeError('encoding must be a string')\n }\n if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {\n throw new TypeError('Unknown encoding: ' + encoding)\n }\n } else if (typeof val === 'number') {\n val = val & 255\n }\n\n // Invalid ranges are not set to a default, so can range check early.\n if (start < 0 || this.length < start || this.length < end) {\n throw new RangeError('Out of range index')\n }\n\n if (end <= start) {\n return this\n }\n\n start = start >>> 0\n end = end === undefined ? this.length : end >>> 0\n\n if (!val) val = 0\n\n var i\n if (typeof val === 'number') {\n for (i = start; i < end; ++i) {\n this[i] = val\n }\n } else {\n var bytes = Buffer.isBuffer(val)\n ? val\n : utf8ToBytes(new Buffer(val, encoding).toString())\n var len = bytes.length\n for (i = 0; i < end - start; ++i) {\n this[i + start] = bytes[i % len]\n }\n }\n\n return this\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n str = stringtrim(str).replace(INVALID_BASE64_RE, '')\n // Node converts strings with length < 2 to ''\n if (str.length < 2) return ''\n // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n while (str.length % 4 !== 0) {\n str = str + '='\n }\n return str\n}\n\nfunction stringtrim (str) {\n if (str.trim) return str.trim()\n return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n if (n < 16) return '0' + n.toString(16)\n return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n units = units || Infinity\n var codePoint\n var length = string.length\n var leadSurrogate = null\n var bytes = []\n\n for (var i = 0; i < length; ++i) {\n codePoint = string.charCodeAt(i)\n\n // is surrogate component\n if (codePoint > 0xD7FF && codePoint < 0xE000) {\n // last char was a lead\n if (!leadSurrogate) {\n // no lead yet\n if (codePoint > 0xDBFF) {\n // unexpected trail\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n } else if (i + 1 === length) {\n // unpaired lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n }\n\n // valid lead\n leadSurrogate = codePoint\n\n continue\n }\n\n // 2 leads in a row\n if (codePoint < 0xDC00) {\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n leadSurrogate = codePoint\n continue\n }\n\n // valid surrogate pair\n codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n } else if (leadSurrogate) {\n // valid bmp char, but last char was a lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n }\n\n leadSurrogate = null\n\n // encode utf8\n if (codePoint < 0x80) {\n if ((units -= 1) < 0) break\n bytes.push(codePoint)\n } else if (codePoint < 0x800) {\n if ((units -= 2) < 0) break\n bytes.push(\n codePoint >> 0x6 | 0xC0,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x10000) {\n if ((units -= 3) < 0) break\n bytes.push(\n codePoint >> 0xC | 0xE0,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x110000) {\n if ((units -= 4) < 0) break\n bytes.push(\n codePoint >> 0x12 | 0xF0,\n codePoint >> 0xC & 0x3F | 0x80,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else {\n throw new Error('Invalid code point')\n }\n }\n\n return bytes\n}\n\nfunction asciiToBytes (str) {\n var byteArray = []\n for (var i = 0; i < str.length; ++i) {\n // Node's code seems to be doing this and not & 0x7F..\n byteArray.push(str.charCodeAt(i) & 0xFF)\n }\n return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n var c, hi, lo\n var byteArray = []\n for (var i = 0; i < str.length; ++i) {\n if ((units -= 2) < 0) break\n\n c = str.charCodeAt(i)\n hi = c >> 8\n lo = c % 256\n byteArray.push(lo)\n byteArray.push(hi)\n }\n\n return byteArray\n}\n\nfunction base64ToBytes (str) {\n return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n for (var i = 0; i < length; ++i) {\n if ((i + offset >= dst.length) || (i >= src.length)) break\n dst[i + offset] = src[i]\n }\n return i\n}\n\nfunction isnan (val) {\n return val !== val // eslint-disable-line no-self-compare\n}\n","'use strict';\n\nvar ConfigService = require('../service/configuration-service');\n\nvar urlConfig = new ConfigService().get('server');\nvar customDefaults = {};\nvar libDefaults = {\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: urlConfig.accountPath,\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: urlConfig.projectPath,\n isLocal: urlConfig.isLocalhost(),\n store: {}\n};\n\nvar optionUtils = {\n /**\n * Gets the final options by overriding the global options set with\n * optionUtils#setDefaults() and the lib defaults.\n * @param {object} `options` The final options object.\n */\n getOptions: function (options) {\n return $.extend(true, {}, libDefaults, customDefaults, options);\n },\n /**\n * Sets the global defaults for the optionUtils#getOptions() method.\n * @param {object} `defaults` The defaults object.\n */\n setDefaults: function (defaults) {\n customDefaults = defaults;\n }\n};\nmodule.exports = optionUtils;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar IdentityStrategy = require('./identity-strategy');\nvar StorageFactory = require('../../store/store-factory');\nvar StateApi = require('../../service/state-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar keyNames = require('../key-names');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n constructor: function Strategy(runService, options) {\n this.run = runService;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n this._store = new StorageFactory(this.options.store);\n this.stateApi = new StateApi();\n this._auth = new AuthManager();\n\n this._loadAndCheck = this._loadAndCheck.bind(this);\n this._restoreRun = this._restoreRun.bind(this);\n this._getAllRuns = this._getAllRuns.bind(this);\n this._loadRun = this._loadRun.bind(this);\n },\n\n reset: function (runServiceOptions) {\n var session = this._auth.getCurrentUserSessionInfo();\n var opt = $.extend({\n scope: { group: session.groupName }\n }, this.runOptions);\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n run.freshlyCreated = true;\n return run;\n });\n },\n\n getRun: function () {\n return this._getAllRuns()\n .then(this._loadAndCheck);\n },\n\n _getAllRuns: function () {\n var session = JSON.parse(this._store.get(keyNames.EPI_SESSION_KEY) || '{}');\n return this.run.query({\n 'user.id': session.userId || '0000',\n 'scope.group': session.groupName\n });\n },\n\n _loadAndCheck: function (runs) {\n if (!runs || !runs.length) {\n return this.reset();\n }\n\n var dateComp = function (a, b) { return new Date(b.date) - new Date(a.date); };\n var latestRun = runs.sort(dateComp)[0];\n var _this = this;\n var shouldReplay = false;\n\n return this.run.load(latestRun.id, null, {\n success: function (run, msg, headers) {\n shouldReplay = headers.getResponseHeader('pragma') === 'persistent';\n }\n }).then(function (run) {\n return shouldReplay ? _this._restoreRun(run.id) : run;\n });\n },\n\n _restoreRun: function (runId) {\n var _this = this;\n return this.stateApi.replay({ runId: runId })\n .then(function (resp) {\n return _this._loadRun(resp.run);\n });\n },\n\n _loadRun: function (id, options) {\n return this.run.load(id, null, options);\n }\n\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\n\nvar IdentityStrategy = require('./identity-strategy');\nvar WorldApiAdapter = require('../../service/world-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n\n constructor: function (runService, options) {\n this.runService = runService;\n this.options = $.extend(true, {}, defaults, options);\n this._auth = new AuthManager();\n this._loadRun = this._loadRun.bind(this);\n this.worldApi = new WorldApiAdapter(this.options.run);\n },\n\n reset: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n return this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(function (world) {\n return this.worldApi.newRunForWorld(world.id);\n }.bind(this));\n },\n\n getRun: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n var worldApi = this.worldApi;\n var model = this.options.model;\n var _this = this;\n var dtd = $.Deferred();\n\n if (!curUserId) {\n return dtd.reject({ statusCode: 400, error: 'We need an authenticated user to join a multiplayer world. (ERR: no userId in session)' }, session).promise();\n }\n\n var loadRunFromWorld = function (world) {\n if (!world) {\n return dtd.reject({ statusCode: 404, error: 'The user is not in any world.' }, { options: this.options, session: session });\n }\n\n return worldApi.getCurrentRunId({ model: model, filter: world.id })\n .then(_this._loadRun)\n .then(dtd.resolve)\n .fail(dtd.reject);\n };\n\n var serverError = function (error) {\n // is this possible?\n dtd.reject(error, session, this.options);\n };\n\n this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(loadRunFromWorld)\n .fail(serverError);\n\n return dtd.promise();\n },\n\n _loadRun: function (id, options) {\n return this.runService.load(id, null, options);\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n/* eslint-disable no-unused-vars */\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\nvar propIsEnumerable = Object.prototype.propertyIsEnumerable;\n\nfunction toObject(val) {\n\tif (val === null || val === undefined) {\n\t\tthrow new TypeError('Object.assign cannot be called with null or undefined');\n\t}\n\n\treturn Object(val);\n}\n\nfunction shouldUseNative() {\n\ttry {\n\t\tif (!Object.assign) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Detect buggy property enumeration order in older V8 versions.\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=4118\n\t\tvar test1 = new String('abc'); // eslint-disable-line\n\t\ttest1[5] = 'de';\n\t\tif (Object.getOwnPropertyNames(test1)[0] === '5') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=3056\n\t\tvar test2 = {};\n\t\tfor (var i = 0; i < 10; i++) {\n\t\t\ttest2['_' + String.fromCharCode(i)] = i;\n\t\t}\n\t\tvar order2 = Object.getOwnPropertyNames(test2).map(function (n) {\n\t\t\treturn test2[n];\n\t\t});\n\t\tif (order2.join('') !== '0123456789') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=3056\n\t\tvar test3 = {};\n\t\t'abcdefghijklmnopqrst'.split('').forEach(function (letter) {\n\t\t\ttest3[letter] = letter;\n\t\t});\n\t\tif (Object.keys(Object.assign({}, test3)).join('') !==\n\t\t\t\t'abcdefghijklmnopqrst') {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t} catch (e) {\n\t\t// We don't expect any of the above to throw, but better to be safe.\n\t\treturn false;\n\t}\n}\n\nmodule.exports = shouldUseNative() ? Object.assign : function (target, source) {\n\tvar from;\n\tvar to = toObject(target);\n\tvar symbols;\n\n\tfor (var s = 1; s < arguments.length; s++) {\n\t\tfrom = Object(arguments[s]);\n\n\t\tfor (var key in from) {\n\t\t\tif (hasOwnProperty.call(from, key)) {\n\t\t\t\tto[key] = from[key];\n\t\t\t}\n\t\t}\n\n\t\tif (Object.getOwnPropertySymbols) {\n\t\t\tsymbols = Object.getOwnPropertySymbols(from);\n\t\t\tfor (var i = 0; i < symbols.length; i++) {\n\t\t\t\tif (propIsEnumerable.call(from, symbols[i])) {\n\t\t\t\t\tto[symbols[i]] = from[symbols[i]];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn to;\n};\n","'use strict'\n\nexports.toByteArray = toByteArray\nexports.fromByteArray = fromByteArray\n\nvar lookup = []\nvar revLookup = []\nvar Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array\n\nfunction init () {\n var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\n for (var i = 0, len = code.length; i < len; ++i) {\n lookup[i] = code[i]\n revLookup[code.charCodeAt(i)] = i\n }\n\n revLookup['-'.charCodeAt(0)] = 62\n revLookup['_'.charCodeAt(0)] = 63\n}\n\ninit()\n\nfunction toByteArray (b64) {\n var i, j, l, tmp, placeHolders, arr\n var len = b64.length\n\n if (len % 4 > 0) {\n throw new Error('Invalid string. Length must be a multiple of 4')\n }\n\n // the number of equal signs (place holders)\n // if there are two placeholders, than the two characters before it\n // represent one byte\n // if there is only one, then the three characters before it represent 2 bytes\n // this is just a cheap hack to not do indexOf twice\n placeHolders = b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0\n\n // base64 is 4/3 + up to two characters of the original data\n arr = new Arr(len * 3 / 4 - placeHolders)\n\n // if there are placeholders, only get up to the last complete 4 chars\n l = placeHolders > 0 ? len - 4 : len\n\n var L = 0\n\n for (i = 0, j = 0; i < l; i += 4, j += 3) {\n tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]\n arr[L++] = (tmp >> 16) & 0xFF\n arr[L++] = (tmp >> 8) & 0xFF\n arr[L++] = tmp & 0xFF\n }\n\n if (placeHolders === 2) {\n tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)\n arr[L++] = tmp & 0xFF\n } else if (placeHolders === 1) {\n tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)\n arr[L++] = (tmp >> 8) & 0xFF\n arr[L++] = tmp & 0xFF\n }\n\n return arr\n}\n\nfunction tripletToBase64 (num) {\n return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]\n}\n\nfunction encodeChunk (uint8, start, end) {\n var tmp\n var output = []\n for (var i = start; i < end; i += 3) {\n tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])\n output.push(tripletToBase64(tmp))\n }\n return output.join('')\n}\n\nfunction fromByteArray (uint8) {\n var tmp\n var len = uint8.length\n var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes\n var output = ''\n var parts = []\n var maxChunkLength = 16383 // must be multiple of 3\n\n // go through the array every three bytes, we'll deal with trailing stuff later\n for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))\n }\n\n // pad the end with zeros, but make sure to not forget the extra bytes\n if (extraBytes === 1) {\n tmp = uint8[len - 1]\n output += lookup[tmp >> 2]\n output += lookup[(tmp << 4) & 0x3F]\n output += '=='\n } else if (extraBytes === 2) {\n tmp = (uint8[len - 2] << 8) + (uint8[len - 1])\n output += lookup[tmp >> 10]\n output += lookup[(tmp >> 4) & 0x3F]\n output += lookup[(tmp << 2) & 0x3F]\n output += '='\n }\n\n parts.push(output)\n\n return parts.join('')\n}\n","exports.read = function (buffer, offset, isLE, mLen, nBytes) {\n var e, m\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var nBits = -7\n var i = isLE ? (nBytes - 1) : 0\n var d = isLE ? -1 : 1\n var s = buffer[offset + i]\n\n i += d\n\n e = s & ((1 << (-nBits)) - 1)\n s >>= (-nBits)\n nBits += eLen\n for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n m = e & ((1 << (-nBits)) - 1)\n e >>= (-nBits)\n nBits += mLen\n for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n if (e === 0) {\n e = 1 - eBias\n } else if (e === eMax) {\n return m ? NaN : ((s ? -1 : 1) * Infinity)\n } else {\n m = m + Math.pow(2, mLen)\n e = e - eBias\n }\n return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n var e, m, c\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)\n var i = isLE ? 0 : (nBytes - 1)\n var d = isLE ? 1 : -1\n var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0\n\n value = Math.abs(value)\n\n if (isNaN(value) || value === Infinity) {\n m = isNaN(value) ? 1 : 0\n e = eMax\n } else {\n e = Math.floor(Math.log(value) / Math.LN2)\n if (value * (c = Math.pow(2, -e)) < 1) {\n e--\n c *= 2\n }\n if (e + eBias >= 1) {\n value += rt / c\n } else {\n value += rt * Math.pow(2, 1 - eBias)\n }\n if (value * c >= 2) {\n e++\n c /= 2\n }\n\n if (e + eBias >= eMax) {\n m = 0\n e = eMax\n } else if (e + eBias >= 1) {\n m = (value * c - 1) * Math.pow(2, mLen)\n e = e + eBias\n } else {\n m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)\n e = 0\n }\n }\n\n for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n e = (e << mLen) | m\n eLen += mLen\n for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n buffer[offset + i - d] |= s * 128\n}\n","var toString = {}.toString;\n\nmodule.exports = Array.isArray || function (arr) {\n return toString.call(arr) == '[object Array]';\n};\n"]} +======= +{"version":3,"sources":["node_modules/browser-pack/_prelude.js","src/api-version.json","src/app.js","src/env-load.js","src/util/query-util.js","src/util/make-sequence.js","src/util/run-util.js","src/util/inherit.js","src/transport/http-transport-factory.js","src/transport/ajax-http-transport.js","src/service/url-config-service.js","src/service/configuration-service.js","src/service/run-api-service.js","src/service/admin-file-service.js","src/service/variables-api-service.js","src/service/auth-api-service.js","src/service/data-api-service.js","src/service/state-api-adapter.js","src/service/world-api-adapter.js","src/service/user-api-adapter.js","src/service/member-api-adapter.js","src/service/asset-api-adapter.js","src/store/cookie-store.js","src/store/store-factory.js","src/managers/scenario-manager.js","src/managers/run-manager.js","src/managers/auth-manager.js","src/managers/world-manager.js","src/managers/epicenter-channel-manager.js","src/service/channel-service.js","src/managers/run-strategies/always-new-strategy.js","src/managers/run-strategies/conditional-creation-strategy.js","src/managers/run-strategies/identity-strategy.js","src/managers/run-strategies/new-if-missing-strategy.js","src/managers/run-strategies/new-if-persisted-strategy.js","src/managers/run-strategies/new-if-initialized-strategy.js","src/util/object-util.js","src/service/introspection-api-service.js","src/store/session-manager.js","src/managers/special-operations.js","src/managers/run-strategies/strategies-map.js","node_modules/buffer/index.js","src/managers/channel-manager.js","src/managers/key-names.js","src/util/option-utils.js","src/managers/run-strategies/multiplayer-strategy.js","src/managers/run-strategies/persistent-single-player-strategy.js","node_modules/isarray/index.js","node_modules/ieee754/index.js","node_modules/base64-js/lib/b64.js"],"names":["F","util","factory","transport","store","service","manager","strategy","load","require","query","makeSequence","run","classFrom","Transport","Ajax","URL","Config","Run","File","Variables","Data","Auth","World","State","User","Member","Asset","Cookie","Store","ScenarioManager","RunManager","AuthManager","WorldManager","identity","ChannelManager","Channel","version","api","global","module","exports","urlConfigService","envLoad","callback","envPromise","host","urlService","envPath","isLocalhost","infoUrl","$","ajax","url","async","done","res","extend","fail","protocol","toMatrixFormat","qs","undefined","String","returnArray","OPERATORS","each","key","value","inArray","trim","charAt","push","mtrx","join","toQueryFormat","isArray","isPlainObject","JSON","stringify","result","qsToObject","qsArray","split","returnObj","index","qKey","qVal","indexOf","mergeQS","qs1","qs2","obj1","this","obj2","addTrailingSlash","length","_w","val","then","p","Deferred","resolve","promise","seq","next","cur","list","splice","Array","prototype","slice","apply","arguments","seed","MakeSeq","obj","__calls","original","fn","start","_this","funcMaker","bind","args","Function","concat","prop","qutil","MAX_URL_LENGTH","normalizeOperations","operations","returnList","ops","_concat","arr","_normalizePlainObjects","opn","arg","_normalizeStructuredObjects","operation","name","params","_normalizeObject","_normalizeLiterals","_normalizeArrays","splitGetFactory","httpOptions","options","http","getValue","getFinalUrl","data","replace","queryParams","questionIdx","include","encodeURI","dtd","paramsCopy","urlNoIncludes","diff","oldSuccess","success","noop","oldError","error","currIncludes","includeOpts","currLength","encodeURIComponent","variable","pop","varLenght","reqs","map","reqParams","get","when","isValid","reject","firstResponse","isObject","isRunAPI","variables","aggregateRun","idx","aggregatedRuns","runs","idxRun","id","aggregatedVariables","vars","inherit","C","P","__super","constructor","dest","call","current","j","base","props","staticProps","parent","child","hasOwnProperty","qutils","config","defaults","contentType","headers","statusCode","404","parameterParser","xhrFields","withCredentials","transportOptions","d","isFunction","connect","method","connectOptions","type","ALLOWED_TO_BE_FUNCTIONS","logLevel","console","log","oldSuccessFn","response","ajaxStatus","ajaxReq","beforeSend","xhr","settings","requestUrl","publicAPI","ajaxOptions","splitGet","post","patch","put","delete","delimiter","head","epiVersion","window","location","pathname","UrlConfigService","path","API_PROTOCOL","HOST_API_MAPPING","forio.com","foriodev.com","publicExports","appPath","accountPath","accnt","projectPath","prj","versionPath","getAPIPath","PROJECT_APIS","apiPath","envConf","serviceOptions","server","setEnv","env","property","set","ConfigService","rutil","_pick","TransportFactory","VariablesService","IntrospectionService","SessionManager","token","account","project","filter","autoRestore","sessionManager","getMergedOptions","urlConfig","getFilterURL","addAutoRestoreHeader","isFilterRunId","autorestoreOpts","X-AutoRestore","Authorization","setFilterOrThrowError","Error","publicAsyncAPI","create","createOptions","runApiParams","model","outputModifier","runID","filters","save","attributes","do","opsArgs","postOptions","prms","serial","opParams","me","$d","doSingleOp","op","shift","parallel","queue","i","publicSyncAPI","getCurrentConfig","vs","runService","introspection","folderType","getContents","filePath","writeToFile","contents","fileName","boundary","body","remove","rename","newName","getURL","attrs","userName","password","login","resp","status","statusMessage","postParams","logout","root","q","saveAs","keys","apiEndpoint","parseRunIdOrError","runId","replay","replayOptions","action","clone","apiBase","assignmentEndpoint","projectEndpoint","group","setIdFilterOrThrowError","validateModelOrThrowError","worldApiParams","validParams","update","whitelist","updateOptions","deleteOptions","updateConfig","getOptions","getWorldsForUser","userId","worldId","addUsers","users","u","updateUser","user","patchOptions","removeUser","getCurrentRunId","getCurrentWorldForUser","groupName","worlds","sort","a","b","Date","lastModified","currentWorld","deleteRun","newRunForWorld","currentRunOptions","autoAssign","opt","maxUsers","getProjectSettings","toQFilter","toIdFilters","getFilters","threshold","getById","groupId","getFinalParams","patchUserActiveField","active","getGroupsForUser","isString","objParams","getParms","getGroupDetails","makeUserActive","makeUserInactive","scope","fullUrl","processData","assetApiParams","scopeConfig","validateFilename","filename","validateUrlParams","partKeys","buildUrl","parts","upload","toLowerCase","FormData","urlOptions","getServiceOptions","files","fullPathFiles","file","assetUrl","document","cookie","newCookie","hostname","domain","setOptions","cookieReg","RegExp","exec","decodeURIComponent","remOptions","destroy","aKeys","nIdx","cookieKey","RunService","validFilter","saved","getRuns","loadVariables","meta","_getService","archive","getRun","patchRunService","patched","orig","reservedOps","Object","specialOperations","StrategyCtor","strategiesMap","reset","runServiceOptions","isLocal","authAdapter","AuthAdapter","MemberAdapter","Buffer","requiresGroup","_findUserInGroup","members","adapterOptions","outSuccess","outError","decodeToken","encoded","decode","atob","toString","parse","handleGroupError","message","statusText","handleSuccess","access_token","userInfo","oldGroups","getSession","groups","userGroupOpts","auth","isTeamMember","parent_account_id","sessionInfo","auth_token","user_id","getUserGroups","memberInfo","userGroups","filteredGroups","grep","resGroup","groupData","isFac","role","sessionInfoWithGroup","saveSession","removeCookieFn","removeSession","getToken","session","memberAdapter","getCurrentUserSessionInfo","addGroups","extendedGroup","validProps","buildStrategy","worldApi","WorldApi","world","_auth","getCurrentWorld","getCurrentRun","getAndRestoreLatestRun","currentWorldId","runOpts","rm","curUserId","curGroupName","validTypes","general","chat","getFromSettingsOrSessionOrError","sessionKeyName","EpicenterChannelManager","defaultCometOptions","urlOpts","handshake","userProp","ext","authorization","getChannel","channelOpts","allowAllChannels","baseParts","channelType","getGroupChannel","baseTopic","getWorldChannel","worldid","getUserChannel","userid","getPresenceChannel","channel","lastPingTime","PING_INTERVAL","subscribe","notification","incomingUserId","trigger","online","valueOf","setInterval","publish","now","getDataChannel","collection","oldsubs","topic","context","callbackWithCleanData","payload","subType","date","actualData","topicResolver","channelOptions","makeName","channelName","topics","subscriptionIds","opts","batch","returnObjs","warn","unsubscribe","on","event","off","ConditionalStrategy","Strategy","createIf","setRunInSession","sessionKey","sessionStore","makeSeq","Base","SessionStore","UrlService","keyNames","STRATEGY_SESSION_KEY","condition","runOptions","runOptionsWithScope","userSession","freshlyCreated","runSession","_loadAndCheck","shouldCreate","msg","getResponseHeader","initialized","commandWrapper","command","introspect","reanimate","StorageFactory","optionUtils","EPI_SESSION_KEY","synchronous","managerOptions","getBaseOptions","overrides","libOptions","finalOptions","getStore","baseOptions","storeOpts","serialized","finalOpts","sessionDefaults","new-if-initialized","new-if-persisted","new-if-missing","always-new","multiplayer","persistent-single-player","none","typedArraySupport","Uint8Array","__proto__","foo","subarray","byteLength","e","kMaxLength","TYPED_ARRAY_SUPPORT","createBuffer","that","RangeError","encodingOrOffset","allocUnsafe","from","TypeError","ArrayBuffer","fromArrayBuffer","fromString","fromObject","assertSize","size","alloc","fill","encoding","checked","string","isEncoding","write","fromArrayLike","array","byteOffset","isBuffer","len","copy","buffer","isnan","SlowBuffer","isView","loweredCase","utf8ToBytes","base64ToBytes","slowToString","end","hexSlice","utf8Slice","asciiSlice","binarySlice","base64Slice","utf16leSlice","swap","n","m","arrayIndexOf","read","buf","indexSize","readUInt16BE","arrLength","valLength","foundIndex","hexWrite","offset","Number","remaining","strLen","parsed","parseInt","substr","isNaN","utf8Write","blitBuffer","asciiWrite","asciiToBytes","binaryWrite","base64Write","ucs2Write","utf16leToBytes","base64","fromByteArray","Math","min","firstByte","codePoint","bytesPerSequence","secondByte","thirdByte","fourthByte","tempCodePoint","decodeCodePointsArray","codePoints","MAX_ARGUMENTS_LENGTH","fromCharCode","ret","out","toHex","bytes","checkOffset","checkInt","max","objectWriteUInt16","littleEndian","objectWriteUInt32","checkIEEE754","writeFloat","noAssert","ieee754","writeDouble","base64clean","str","stringtrim","INVALID_BASE64_RE","units","Infinity","leadSurrogate","charCodeAt","byteArray","c","hi","lo","toByteArray","src","dst","INSPECT_MAX_BYTES","poolSize","_augment","Symbol","species","defineProperty","configurable","allocUnsafeSlow","_isBuffer","compare","x","y","pos","swap16","swap32","equals","inspect","match","target","thisStart","thisEnd","thisCopy","targetCopy","includes","isFinite","toJSON","_arr","newBuf","sliceLen","readUIntLE","mul","readUIntBE","readUInt8","readUInt16LE","readUInt32LE","readUInt32BE","readIntLE","pow","readIntBE","readInt8","readInt16LE","readInt16BE","readInt32LE","readInt32BE","readFloatLE","readFloatBE","readDoubleLE","readDoubleBE","writeUIntLE","maxBytes","writeUIntBE","writeUInt8","floor","writeUInt16LE","writeUInt16BE","writeUInt32LE","writeUInt32BE","writeIntLE","limit","sub","writeIntBE","writeInt8","writeInt16LE","writeInt16BE","writeInt32LE","writeInt32BE","writeFloatLE","writeFloatBE","writeDoubleLE","writeDoubleBE","targetStart","code","cometd","websocketEnabled","shareConnection","currentSubscriptions","_cometd","Cometd","isConnected","connectionBroken","connectionSucceeded","configure","addListener","wasConnected","successful","subs","resubscribe","subid","unsubs","removed","customDefaults","libDefaults","setDefaults","IdentityStrategy","WorldApiAdapter","_loadRun","loadRunFromWorld","serverError","StateApi","_store","stateApi","_restoreRun","_getAllRuns","user.id","scope.group","dateComp","latestRun","shouldReplay","isLE","mLen","nBytes","eLen","eMax","eBias","nBits","s","NaN","rt","abs","LN2","init","lookup","revLookup","b64","l","tmp","placeHolders","Arr","L","tripletToBase64","num","encodeChunk","uint8","output","extraBytes","maxChunkLength","len2"],"mappings":"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","file":"bundle.js","sourcesContent":["(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o\n * https://github.com/forio/epicenter-js-libs\n */\n\nvar F = {\n util: {},\n factory: {},\n transport: {},\n store: {},\n service: {},\n manager: {\n strategy: {}\n },\n\n};\n\nF.load = require('./env-load');\nF.load();\n\nF.util.query = require('./util/query-util');\nF.util.makeSequence = require('./util/make-sequence');\nF.util.run = require('./util/run-util');\nF.util.classFrom = require('./util/inherit');\n\nF.factory.Transport = require('./transport/http-transport-factory');\nF.transport.Ajax = require('./transport/ajax-http-transport');\n\nF.service.URL = require('./service/url-config-service');\nF.service.Config = require('./service/configuration-service');\nF.service.Run = require('./service/run-api-service');\nF.service.File = require('./service/admin-file-service');\nF.service.Variables = require('./service/variables-api-service');\nF.service.Data = require('./service/data-api-service');\nF.service.Auth = require('./service/auth-api-service');\nF.service.World = require('./service/world-api-adapter');\nF.service.State = require('./service/state-api-adapter');\nF.service.User = require('./service/user-api-adapter');\nF.service.Member = require('./service/member-api-adapter');\nF.service.Asset = require('./service/asset-api-adapter');\n\nF.store.Cookie = require('./store/cookie-store');\nF.factory.Store = require('./store/store-factory');\n\nF.manager.ScenarioManager = require('./managers/scenario-manager');\nF.manager.RunManager = require('./managers/run-manager');\nF.manager.AuthManager = require('./managers/auth-manager');\nF.manager.WorldManager = require('./managers/world-manager');\n\nF.manager.strategy['always-new'] = require('./managers/run-strategies/always-new-strategy');\nF.manager.strategy['conditional-creation'] = require('./managers/run-strategies/conditional-creation-strategy');\nF.manager.strategy.identity = require('./managers/run-strategies/identity-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-persisted'] = require('./managers/run-strategies/new-if-persisted-strategy');\nF.manager.strategy['new-if-initialized'] = require('./managers/run-strategies/new-if-initialized-strategy');\n\nF.manager.ChannelManager = require('./managers/epicenter-channel-manager');\nF.service.Channel = require('./service/channel-service');\n\nF.version = '<%= version %>';\nF.api = require('./api-version.json');\n\nglobal.F = F;\nmodule.exports = F;\n","'use strict';\n\nvar urlConfigService = require('./service/url-config-service');\n\nvar envLoad = function (callback) {\n var envPromise;\n var host;\n var urlService = urlConfigService();\n var envPath = '/epicenter/v1/config';\n if (urlService.isLocalhost()) {\n host = 'https://forio.com';\n } else {\n host = '';\n }\n var infoUrl = host + envPath;\n envPromise = $.ajax({ url: infoUrl, async: false });\n envPromise.done(function (res) {\n var api = res.api;\n $.extend(urlConfigService, api);\n }).fail(function (res) {\n // Epicenter/webserver not properly configured\n // fallback to api.forio.com\n $.extend(urlConfigService, { protocol: 'https', host: 'api.forio.com' });\n });\n return envPromise.done(callback).fail(callback);\n};\n\nmodule.exports = envLoad;\n","/**\n * Utilities for working with query strings\n*/\n'use strict';\n\nmodule.exports = (function () {\n\n return {\n /**\n * Converts to matrix format\n * @param {Object} qs Object to convert to query string\n * @return { string} Matrix-format query parameters\n */\n toMatrixFormat: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return ';';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n var OPERATORS = ['<', '>', '!'];\n $.each(qs, function (key, value) {\n if (typeof value !== 'string' || $.inArray($.trim(value).charAt(0), OPERATORS) === -1) {\n value = '=' + value;\n }\n returnArray.push(key + value);\n });\n\n var mtrx = ';' + returnArray.join(';');\n return mtrx;\n },\n\n /**\n * Converts strings/arrays/objects to type 'a=b&b=c'\n * @param { string|Array|Object} qs\n * @return { string}\n */\n toQueryFormat: function (qs) {\n if (qs === null || qs === undefined) {\n return '';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n $.each(qs, function (key, value) {\n if ($.isArray(value)) {\n value = value.join(',');\n }\n if ($.isPlainObject(value)) {\n //Mostly for data api\n value = JSON.stringify(value);\n }\n returnArray.push(key + '=' + value);\n });\n\n var result = returnArray.join('&');\n return result;\n },\n\n /**\n * Converts strings of type 'a=b&b=c' to { a:b, b:c}\n * @param { string} qs\n * @return {object}\n */\n qsToObject: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return {};\n }\n\n var qsArray = qs.split('&');\n var returnObj = {};\n $.each(qsArray, function (index, value) {\n var qKey = value.split('=')[0];\n var qVal = value.split('=')[1];\n\n if (qVal.indexOf(',') !== -1) {\n qVal = qVal.split(',');\n }\n\n returnObj[qKey] = qVal;\n });\n\n return returnObj;\n },\n\n /**\n * Normalizes and merges strings of type 'a=b', { b:c} to { a:b, b:c}\n * @param { string|Array|Object} qs1\n * @param { string|Array|Object} qs2\n * @return {Object}\n */\n mergeQS: function (qs1, qs2) {\n var obj1 = this.qsToObject(this.toQueryFormat(qs1));\n var obj2 = this.qsToObject(this.toQueryFormat(qs2));\n return $.extend(true, {}, obj1, obj2);\n },\n\n addTrailingSlash: function (url) {\n if (!url) {\n return '';\n }\n return (url.charAt(url.length - 1) === '/') ? url : (url + '/');\n }\n };\n}());\n\n\n\n","'use strict';\n/*jshint loopfunc:false */\n\nfunction _w(val) {\n if (val && val.then) {\n return val;\n }\n var p = $.Deferred();\n p.resolve(val);\n\n return p.promise();\n}\n\nfunction seq() {\n var list = Array.prototype.slice.apply(arguments);\n\n function next(p) {\n var cur = list.splice(0,1)[0];\n\n if (!cur) {\n return p;\n }\n\n return _w(cur(p)).then(next);\n }\n\n return function (seed) {\n return next(seed).fail(seq.fail);\n };\n}\n\nfunction MakeSeq(obj) {\n var res = {\n __calls: [],\n\n original: obj,\n\n then: function (fn) {\n this.__calls.push(fn);\n return this;\n },\n\n start: function () {\n var _this = this;\n\n // clean up\n this.then(function (run) {\n _this.__calls.length = 0;\n return run;\n });\n\n return seq.apply(null, this.__calls)();\n },\n\n fail: function (fn) {\n seq.fail = fn;\n return this;\n }\n };\n\n var funcMaker = function (p, obj) {\n var fn = obj[p].bind(obj);\n return function () {\n var args = Array.prototype.slice.apply(arguments);\n this.__calls.push(Function.bind.apply(fn, [null].concat(args)));\n return this;\n };\n };\n\n for (var prop in obj) {\n if (typeof obj[prop] === 'function') {\n res[prop] = funcMaker(prop, obj);\n } else {\n res[prop] = obj[prop];\n }\n }\n\n return res;\n}\n\nmodule.exports = MakeSeq;\n","/**\n * Utilities for working with the run service\n*/\n'use strict';\nvar qutil = require('./query-util');\nvar MAX_URL_LENGTH = 2048;\n\nmodule.exports = (function () {\n return {\n /**\n * returns operations of the form `[[op1,op2], [arg1, arg2]]`\n * @param {Object|Array|String} `operations` operations to perform\n * @param {Array} `args` arguments for operation\n * @return {String} Matrix-format query parameters\n */\n normalizeOperations: function (operations, args) {\n if (!args) {\n args = [];\n }\n var returnList = {\n ops: [],\n args: []\n };\n\n var _concat = function (arr) {\n return (arr !== null && arr !== undefined) ? [].concat(arr) : [];\n };\n\n //{ add: [1,2], subtract: [2,4] }\n var _normalizePlainObjects = function (operations, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (opn, arg) {\n returnList.ops.push(opn);\n returnList.args.push(_concat(arg));\n });\n return returnList;\n };\n //{ name: 'add', params: [1] }\n var _normalizeStructuredObjects = function (operation, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation.name);\n returnList.args.push(_concat(operation.params));\n return returnList;\n };\n\n var _normalizeObject = function (operation, returnList) {\n return ((operation.name) ? _normalizeStructuredObjects : _normalizePlainObjects)(operation, returnList);\n };\n\n var _normalizeLiterals = function (operation, args, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation);\n returnList.args.push(_concat(args));\n return returnList;\n };\n\n\n var _normalizeArrays = function (operations, arg, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (index, opn) {\n if ($.isPlainObject(opn)) {\n _normalizeObject(opn, returnList);\n } else {\n _normalizeLiterals(opn, args[index], returnList);\n }\n });\n return returnList;\n };\n\n if ($.isPlainObject(operations)) {\n _normalizeObject(operations, returnList);\n } else if ($.isArray(operations)) {\n _normalizeArrays(operations, args, returnList);\n } else {\n _normalizeLiterals(operations, args, returnList);\n }\n\n return returnList;\n },\n\n splitGetFactory: function (httpOptions) {\n return function (params, options) {\n var http = this;\n var getValue = function (name) {\n var value = options[name] || httpOptions[name];\n if (typeof value === 'function') {\n value = value();\n }\n return value;\n };\n var getFinalUrl = function (params) {\n var url = getValue('url', options);\n var data = params;\n // There is easy (or known) way to get the final URL jquery is going to send so\n // we're replicating it. The process might change at some point but it probably will not.\n // 1. Remove hash\n url = url.replace(/#.*$/, '');\n // 1. Append query string\n var queryParams = qutil.toQueryFormat(data);\n var questionIdx = url.indexOf('?');\n if (queryParams && questionIdx > -1) {\n return url + '&' + queryParams;\n } else if (queryParams) {\n return url + '?' + queryParams;\n }\n return url;\n };\n var url = getFinalUrl(params);\n // We must split the GET in multiple short URL's\n // The only property allowed to be split is \"include\"\n if (params && params.include && encodeURI(url).length > MAX_URL_LENGTH) {\n var dtd = $.Deferred();\n var paramsCopy = $.extend(true, {}, params);\n delete paramsCopy.include;\n var urlNoIncludes = getFinalUrl(paramsCopy);\n var diff = MAX_URL_LENGTH - urlNoIncludes.length;\n var oldSuccess = options.success || httpOptions.success || $.noop;\n var oldError = options.error || httpOptions.error || $.noop;\n // remove the original success and error callbacks\n options.success = $.noop;\n options.error = $.noop;\n\n var include = params.include;\n var currIncludes = [];\n var includeOpts = [currIncludes];\n var currLength = encodeURIComponent('?include=').length;\n var variable = include.pop();\n while (variable) {\n var varLenght = encodeURIComponent(variable).length;\n // Use a greedy approach for now, can be optimized to be solved in a more\n // efficient way\n // + 1 is the comma\n if (currLength + varLenght + 1 < diff) {\n currIncludes.push(variable);\n currLength += varLenght + 1;\n } else {\n currIncludes = [variable];\n includeOpts.push(currIncludes);\n currLength = '?include='.length + varLenght;\n }\n variable = include.pop();\n }\n var reqs = $.map(includeOpts, function (include) {\n var reqParams = $.extend({}, params, { include: include });\n return http.get(reqParams, options);\n });\n $.when.apply($, reqs).then(function () {\n // Each argument are arrays of the arguments of each done request\n // So the first argument of the first array of arguments is the data\n var isValid = arguments[0] && arguments[0][0];\n if (!isValid) {\n // Should never happen...\n oldError();\n return dtd.reject();\n }\n var firstResponse = arguments[0][0];\n var isObject = $.isPlainObject(firstResponse);\n var isRunAPI = (isObject && $.isPlainObject(firstResponse.variables)) || !isObject;\n if (isRunAPI) {\n if (isObject) {\n // aggregate the variables property only\n var aggregateRun = arguments[0][0];\n $.each(arguments, function (idx, args) {\n var run = args[0];\n $.extend(true, aggregateRun.variables, run.variables);\n });\n oldSuccess(aggregateRun, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregateRun, arguments[0][1], arguments[0][2]);\n } else {\n // array of runs\n // Agregate variables in each run\n var aggregatedRuns = {};\n $.each(arguments, function (idx, args) {\n var runs = args[0];\n if (!$.isArray(runs)) {\n return;\n }\n $.each(runs, function (idxRun, run) {\n if (run.id && !aggregatedRuns[run.id]) {\n run.variables = run.variables || {};\n aggregatedRuns[run.id] = run;\n } else if (run.id) {\n $.extend(true, aggregatedRuns[run.id].variables, run.variables);\n }\n });\n });\n // turn it into an array\n aggregatedRuns = $.map(aggregatedRuns, function (run) { return run; });\n oldSuccess(aggregatedRuns, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedRuns, arguments[0][1], arguments[0][2]);\n }\n } else {\n // is variables API\n // aggregate the response\n var aggregatedVariables = {};\n $.each(arguments, function (idx, args) {\n var vars = args[0];\n $.extend(true, aggregatedVariables, vars);\n });\n oldSuccess(aggregatedVariables, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedVariables, arguments[0][1], arguments[0][2]);\n }\n }, function () {\n oldError.apply(http, arguments);\n dtd.reject.apply(dtd, arguments);\n });\n return dtd.promise();\n } else {\n return http.get(params, options);\n }\n };\n }\n };\n}());\n","/**\n/* Inherit from a class (using prototype borrowing)\n*/\n'use strict';\n\nfunction inherit(C, P) {\n var F = function () {};\n F.prototype = P.prototype;\n C.prototype = new F();\n C.__super = P.prototype;\n C.prototype.constructor = C;\n}\n\n/**\n* Shallow copy of an object\n*/\nvar extend = function (dest /*, var_args*/) {\n var obj = Array.prototype.slice.call(arguments, 1);\n var current;\n for (var j = 0; j 1,\n * // where variables.price has been persisted (recorded)\n * // in the model.\n * rs.query({\n * 'saved': 'true',\n * '.price': '>1'\n * },\n * {\n * startrecord: 2,\n * endrecord: 5\n * });\n *\n * **Parameters**\n * @param {Object} `qs` Query object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Querying for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n query: function (qs, outputModifier, options) {\n serviceOptions.filter = qs; //shouldn't be able to over-ride\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Returns particular runs, based on conditions specified in the `qs` object.\n *\n * Similar to `.query()`.\n *\n * **Parameters**\n * @param {Object} `filter` Filter object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Filtering for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n filter: function (filter, outputModifier, options) {\n if ($.isPlainObject(serviceOptions.filter)) {\n $.extend(serviceOptions.filter, filter);\n } else {\n serviceOptions.filter = filter;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Get data for a specific run. This includes standard run data such as the account, model, project, and created and last modified dates. To request specific model variables, pass them as part of the `filters` parameter.\n *\n * Note that if the run is [in memory](../../../run_persistence/#runs-in-memory), any model variables are available; if the run is [in the database](../../../run_persistence/#runs-in-db), only model variables that have been persisted — that is, `record`ed in your Julia model — are available.\n *\n * **Example**\n *\n * rs.load('bb589677-d476-4971-a68e-0c58d191e450', { include: ['.price', '.sales'] });\n *\n * **Parameters**\n * @param {String} `runID` The run id.\n * @param {Object} `filters` (Optional) Object containing filters and operation modifiers. Use key `include` to list model variables that you want to include in the response. Other available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (runID, filters, options) {\n if (runID) {\n serviceOptions.filter = runID; //shouldn't be able to over-ride\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.get(filters, httpOptions);\n },\n\n\n /**\n * Save attributes (data, model variables) of the run.\n *\n * **Examples**\n *\n * // add 'completed' field to run record\n * rs.save({ completed: true });\n *\n * // update 'saved' field of run record, and update values of model variables for this run\n * rs.save({ saved: true, variables: { a: 23, b: 23 } });\n *\n * **Parameters**\n * @param {Object} `attributes` The run data and variables to save.\n * @param {Object} `attributes.variables` Model variables must be included in a `variables` field within the `attributes` object. (Otherwise they are treated as run data and added to the run record directly.)\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (attributes, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n setFilterOrThrowError(httpOptions);\n return http.patch(attributes, httpOptions);\n },\n\n /**\n * Call a method from the model.\n *\n * Depending on the language in which you have written your model, the method may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * The `params` argument is normally an array of arguments to the `operation`. In the special case where `operation` only takes one argument, you are not required to put that argument into an array.\n *\n * Note that you can combine the `operation` and `params` arguments into a single object if you prefer, as in the last example.\n *\n * **Examples**\n *\n * // method \"solve\" takes no arguments\n * rs.do('solve');\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', ['hello']);\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', 'hello');\n * // method \"sumArray\" takes one argument, an array\n * rs.do('sumArray', [[4,2,1]]);\n * // method \"add\" takes two arguments, both integers\n * rs.do({ name:'add', params:[2,4] });\n *\n * **Parameters**\n * @param {String} `operation` Name of method.\n * @param {Array} `params` (Optional) Any parameters the operation takes, passed as an array. In the special case where `operation` only takes one argument, you are not required to put that argument into an array, and can just pass it directly.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n do: function (operation, params, options) {\n // console.log('do', operation, params);\n var opsArgs;\n var postOptions;\n if (options) {\n opsArgs = params;\n postOptions = options;\n } else {\n if ($.isPlainObject(params)) {\n opsArgs = null;\n postOptions = params;\n } else {\n opsArgs = params;\n }\n }\n var result = rutil.normalizeOperations(operation, opsArgs);\n var httpOptions = $.extend(true, {}, serviceOptions, postOptions);\n\n setFilterOrThrowError(httpOptions);\n\n var prms = (result.args[0].length && (result.args[0] !== null && result.args[0] !== undefined)) ? result.args[0] : [];\n return http.post({ arguments: prms }, $.extend(true, {}, httpOptions, {\n url: urlConfig.getFilterURL() + 'operations/' + result.ops[0] + '/'\n }));\n },\n\n /**\n * Call several methods from the model, sequentially.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Examples**\n *\n * // methods \"initialize\" and \"solve\" do not take any arguments\n * rs.serial(['initialize', 'solve']);\n * // methods \"init\" and \"reset\" take two arguments each\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'reset', params: [2,3] }]);\n * // method \"init\" takes two arguments,\n * // method \"runmodel\" takes none\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'runmodel', params: [] }]);\n *\n * **Parameters**\n * @param {Array} `operations` If none of the methods take parameters, pass an array of the method names (strings). If any of the methods do take parameters, pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n serial: function (operations, params, options) {\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var me = this;\n\n var $d = $.Deferred();\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var doSingleOp = function () {\n var op = ops.shift();\n var arg = args.shift();\n\n me.do(op, arg, {\n success: function () {\n if (ops.length) {\n doSingleOp();\n } else {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this, arguments);\n }\n },\n error: function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this, arguments);\n }\n });\n };\n\n doSingleOp();\n\n return $d.promise();\n },\n\n /**\n * Call several methods from the model, executing them in parallel.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Example**\n *\n * // methods \"solve\" and \"reset\" do not take any arguments\n * rs.parallel(['solve', 'reset']);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel([ { name: 'add', params: [1,2] },\n * { name: 'subtract', params:[2,3] }]);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel({ add: [1,2], subtract: [2,4] });\n *\n * **Parameters**\n * @param {Array|Object} `operations` If none of the methods take parameters, pass an array of the method names (as strings). If any of the methods do take parameters, you have two options. You can pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters. Alternatively, you can pass a single object with the method name and a (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n parallel: function (operations, params, options) {\n var $d = $.Deferred();\n\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var queue = [];\n for (var i = 0; i< ops.length; i++) {\n queue.push(\n this.do(ops[i], args[i])\n );\n }\n $.when.apply(this, queue)\n .done(function () {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this.arguments);\n })\n .fail(function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this.arguments);\n });\n\n return $d.promise();\n }\n };\n\n var publicSyncAPI = {\n getCurrentConfig: function () {\n return serviceOptions;\n },\n /**\n * Returns a Variables Service instance. Use the variables instance to load, save, and query for specific model variables. See the [Variable API Service](../variables-api-service/) for more information.\n *\n * **Example**\n *\n * var vs = rs.variables();\n * vs.save({ sample_int: 4 });\n *\n * **Parameters**\n * @param {Object} `config` (Optional) Overrides for configuration options.\n */\n variables: function (config) {\n var vs = new VariablesService($.extend(true, {}, serviceOptions, config, {\n runService: this\n }));\n return vs;\n },\n\n introspection: function (config) {\n var introspection = new IntrospectionService($.extend(true, {}, serviceOptions, config));\n return introspection;\n }\n };\n\n $.extend(this, publicAsyncAPI);\n $.extend(this, publicSyncAPI);\n};\n","/**\n * ## File API Service\n *\n * This is used to upload/download files directly onto Epicenter, analogous to using the File Manager UI in Epicenter directly or SFTPing files in. The Asset API is typically used for all project use-cases, and it's unlikely this File Service will be used directly except by Admin tools (e.g. Flow Inspector).\n *\n * Partially implemented.\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The project id. Defaults to empty string.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The folder type. One of Model|Static|Node\n * @type {String}\n */\n folderType: 'static',\n\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('file')\n });\n\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAsyncAPI = {\n /**\n * Get a directory listing, or contents of a file\n * @param {String} `filePath` Path to the file\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getContents: function (filePath, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.get('', httpOptions);\n },\n\n /**\n * Writes to the given file path; replaces the existing file if it exists\n * @param {String} `filePath` Path to the file\n * @param {String} `contents` Contents to write to file\n * @param {Object} `options` (Optional) Overrides for configuration options\n */\n writeToFile: function (filePath, contents, options) {\n filePath = filePath.split('/');\n var fileName = filePath.pop();\n filePath = filePath.join('/');\n var path = serviceOptions.folderType + '/' + filePath;\n var boundary = '---------------------------7da24f2e50046';\n\n var body = '--' + boundary + '\\r\\n' +\n 'Content-Disposition: form-data; name=\"file\";' +\n 'filename=\"' + fileName + '\"\\r\\n' +\n 'Content-type: text/html\\r\\n\\r\\n' +\n contents + '\\r\\n' +\n '--' + boundary + '--';\n\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path,\n data: body,\n contentType: 'multipart/form-data; boundary=' + boundary\n });\n\n return http.put(body, httpOptions);\n },\n\n /**\n * Removes the file\n * @param {String} `filePath` Path to the file\n * @param {Object} `options` (Optional) Overrides for configuration options\n */\n remove: function (filePath, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.delete(null, httpOptions);\n },\n\n /**\n * Rename the file\n * @param {String} filePath Path to the file\n * @param {Stirng} newName New name of file\n * @param {Object} options (Optional) Overrides for configuration options\n */\n rename: function (filePath, newName, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.patch({ 'name': newName }, httpOptions);\n }\n };\n\n $.extend(this, publicAsyncAPI);\n};\n","/**\n *\n * ## Variables API Service\n *\n * Used in conjunction with the [Run API Service](../run-api-service/) to read, write, and search for specific model variables.\n *\n * var rm = new F.manager.RunManager({\n * run: {\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'supply-chain-model.jl'\n * }\n * });\n * rm.getRun()\n * .then(function() {\n * var vs = rm.run.variables();\n * vs.save({sample_int: 4});\n * });\n *\n */\n\n\n 'use strict';\n\n var TransportFactory = require('../transport/http-transport-factory');\n var rutil = require('../util/run-util');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * The runs object to which the variable filters apply. Defaults to null.\n * @type {runService}\n */\n runService: null\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var getURL = function () {\n return serviceOptions.runService.urlConfig.getFilterURL() + 'variables/';\n };\n\n var addAutoRestoreHeader = function (options) {\n return serviceOptions.runService.urlConfig.addAutoRestoreHeader(options);\n };\n\n var httpOptions = {\n url: getURL\n };\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n http.splitGet = rutil.splitGetFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Get values for a variable.\n *\n * **Example**\n *\n * vs.load('sample_int')\n * .then(function(val){\n * // val contains the value of sample_int\n * });\n *\n * **Parameters**\n * @param {String} `variable` Name of variable to load.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (variable, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n return http.get(outputModifier, $.extend({}, httpOptions, {\n url: getURL() + variable + '/'\n }));\n },\n\n /**\n * Returns particular variables, based on conditions specified in the `query` object.\n *\n * **Example**\n *\n * vs.query(['price', 'sales'])\n * .then(function(val) {\n * // val is an object with the values of the requested variables: val.price, val.sales\n * });\n *\n * vs.query({ include:['price', 'sales'] });\n *\n * **Parameters**\n * @param {Object|Array} `query` The names of the variables requested.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (query, outputModifier, options) {\n //Query and outputModifier are both querystrings in the url; only calling them out separately here to be consistent with the other calls\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n\n if ($.isArray(query)) {\n query = { include: query };\n }\n $.extend(query, outputModifier);\n return http.splitGet(query, httpOptions);\n },\n\n /**\n * Save values to model variables. Overwrites existing values. Note that you can only update model variables if the run is [in memory](../../../run_persistence/#runs-in-memory). (An alternate way to update model variables is to call a method from the model and make sure that the method persists the variables. See `do`, `serial`, and `parallel` in the [Run API Service](../run-api-service/) for calling methods from the model.)\n *\n * **Example**\n *\n * vs.save('price', 4);\n * vs.save({ price: 4, quantity: 5, products: [2,3,4] });\n *\n * **Parameters**\n * @param {Object|String} `variable` An object composed of the model variables and the values to save. Alternatively, a string with the name of the variable.\n * @param {Object} `val` (Optional) If passing a string for `variable`, use this argument for the value to save.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (variable, val, options) {\n var attrs;\n if (typeof variable === 'object') {\n attrs = variable;\n options = val;\n } else {\n (attrs = {})[variable] = val;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n return http.patch.call(this, attrs, httpOptions);\n }\n\n // Not Available until underlying API supports PUT. Otherwise save would be PUT and merge would be PATCH\n // *\n // * Save values to the api. Merges arrays, but otherwise same as save\n // * @param {Object|String} variable Object with attributes, or string key\n // * @param {Object} val Optional if prev parameter was a string, set value here\n // * @param {Object} options Overrides for configuration options\n // *\n // * @example\n // * vs.merge({ price: 4, quantity: 5, products: [2,3,4] })\n // * vs.merge('price', 4);\n\n // merge: function (variable, val, options) {\n // var attrs;\n // if (typeof variable === 'object') {\n // attrs = variable;\n // options = val;\n // } else {\n // (attrs = {})[variable] = val;\n // }\n // var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n // return http.patch.call(this, attrs, httpOptions);\n // }\n };\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ## Authentication API Service\n *\n * The Authentication API Service provides a method for logging in, which creates and returns a user access token.\n *\n * User access tokens are required for each call to Epicenter. (See [Project Access](../../../project_access/) for more information.)\n *\n * If you need additional functionality -- such as tracking session information, easily retrieving the user token, or getting the groups to which an end user belongs -- consider using the [Authorization Manager](../auth-manager/) instead.\n *\n * var auth = new F.service.Auth();\n * auth.login({ userName: 'jsmith@acmesimulations.com',\n * password: 'passw0rd' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Email or username to use for logging in. Defaults to empty string.\n * @type {String}\n */\n userName: '',\n\n /**\n * Password for specified `userName`. Defaults to empty string.\n * @type {String}\n */\n password: '',\n\n /**\n * The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects). Required if the `userName` is for an [end user](../../../glossary/#users). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('authentication')\n });\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Logs user in, returning the user access token.\n *\n * If no `userName` or `password` were provided in the initial configuration options, they are required in the `options` here. If no `account` was provided in the initial configuration options and the `userName` is for an [end user](../../../glossary/#users), the `account` is required as well.\n *\n * **Example**\n *\n * auth.login({\n * userName: 'jsmith',\n * password: 'passw0rd',\n * account: 'acme-simulations' })\n * .then(function (token) {\n * console.log(\"user access token is: \", token.access_token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n login: function (options) {\n var httpOptions = $.extend(true, { success: $.noop }, serviceOptions, options);\n if (!httpOptions.userName || !httpOptions.password) {\n var resp = { status: 401, statusMessage: 'No username or password specified.' };\n if (options.error) {\n options.error.call(this, resp);\n }\n\n return $.Deferred().reject(resp).promise();\n }\n\n var postParams = {\n userName: httpOptions.userName,\n password: httpOptions.password,\n };\n if (httpOptions.account) {\n //pass in null for account under options if you don't want it to be sent\n postParams.account = httpOptions.account;\n }\n\n return http.post(postParams, httpOptions);\n },\n\n // (replace with /* */ comment block, to make visible in docs, once this is more than a noop)\n //\n // Logs user out from specified accounts.\n //\n // Epicenter logout is not implemented yet, so for now this is a dummy promise that gets automatically resolved.\n //\n // **Example**\n //\n // auth.logout();\n //\n // **Parameters**\n // @param {Object} `options` (Optional) Overrides for configuration options.\n //\n logout: function (options) {\n var dtd = $.Deferred();\n dtd.resolve();\n return dtd.promise();\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * ## Data API Service\n *\n * The Data API Service allows you to create, access, and manipulate data related to any of your projects. Data are organized in collections. Each collection contains a document; each element of this top-level document is a JSON object. (See additional information on the underlying [Data API](../../../rest_apis/data_api/).)\n *\n * All API calls take in an \"options\" object as the last parameter. The options can be used to extend/override the Data API Service defaults. In particular, there are three required parameters when you instantiate the Data Service:\n *\n * * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `project`: Epicenter project id.\n * * `root`: The the name of the collection. If you have multiple collections within each of your projects, you can also pass the collection name as an option for each call.\n *\n * var ds = new F.service.Data({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * root: 'survey-responses',\n * server: { host: 'api.forio.com' }\n * });\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('user2',\n * { 'question1': 3, 'question2': 8,\n * 'question3': true, 'question4': 'always' } );\n * ds.query('',{ 'question2': { '$gt': 9} });\n *\n * Note that in addition to the `account`, `project`, and `root`, the Data Service parameters optionally include a `server` object, whose `host` field contains the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Name of collection. Defaults to `/`, that is, the root level of your project at `forio.com/app/your-account-id/your-project-id/`. Required.\n * @type {String}\n */\n root: '/',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The project id. Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * For operations that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n //Options to pass on to the underlying transport layer\n transport: {}\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var getURL = function (key, root) {\n if (!root) {\n root = serviceOptions.root;\n }\n var url = urlConfig.getAPIPath('data') + qutil.addTrailingSlash(root);\n if (key) {\n url+= qutil.addTrailingSlash(key);\n }\n return url;\n };\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: getURL\n });\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Search for data within a collection.\n *\n * Searching using comparison or logical operators (as opposed to exact matches) requires MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional details.\n *\n * **Examples**\n *\n * // request all data associated with document 'user1'\n * ds.query('user1');\n *\n * // exact matching:\n * // request all documents in collection where 'question2' is 9\n * ds.query('', { 'question2': 9});\n *\n * // comparison operators:\n * // request all documents in collection\n * // where 'question2' is greater than 9\n * ds.query('', { 'question2': { '$gt': 9} });\n *\n * // logical operators:\n * // request all documents in collection\n * // where 'question2' is less than 10, and 'question3' is false\n * ds.query('', { '$and': [ { 'question2': { '$lt':10} }, { 'question3': false }] });\n *\n * // regular expresssions: use any Perl-compatible regular expressions\n * // request all documents in collection\n * // where 'question5' contains the string '.*day'\n * ds.query('', { 'question5': { '$regex': '.*day' } });\n *\n * **Parameters**\n * @param {String} `key` The name of the document to search. Pass the empty string ('') to search the entire collection.\n * @param {Object} `query` The query object. For exact matching, this object contains the field name and field value to match. For matching based on comparison, this object contains the field name and the comparison expression. For matching based on logical operators, this object contains an expression using MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional examples.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (key, query, outputModifier, options) {\n var params = $.extend(true, { q: query }, outputModifier);\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(params, httpOptions);\n },\n\n /**\n * Save data to an anonymous document within the collection.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.save('question1', 'yes');\n * ds.save({question1:'yes', question2: 32 });\n * ds.save({ name:'John', className: 'CS101' }, { root: 'students' });\n *\n * **Parameters**\n *\n * @param {String|Object} `key` If `key` is a string, it is the id of the element to save (create) in this document. If `key` is an object, the object is the data to save (create) in this document. In both cases, the id for the document is generated automatically.\n * @param {Object} `value` (Optional) The data to save. If `key` is a string, this is the value to save. If `key` is an object, the value(s) to save are already part of `key` and this argument is not required.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (key, value, options) {\n var attrs;\n if (typeof key === 'object') {\n attrs = key;\n options = value;\n } else {\n (attrs = {})[key] = value;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL('', httpOptions.root);\n\n return http.post(attrs, httpOptions);\n },\n\n /**\n * Save data to a named document or element within the collection. The `root` of the collection must be specified separately in configuration options, either as part of the call or as part of the initialization of ds.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('student1',\n * { firstName: 'john', lastName: 'smith' },\n * { root: 'students' });\n * ds.saveAs('mgmt100/groupB',\n * { scenarioYear: '2015' },\n * { root: 'myclasses' });\n *\n * **Parameters**\n *\n * @param {String} `key` Id of the document.\n * @param {Object} `value` (Optional) The data to save, in key:value pairs.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n saveAs: function (key, value, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n\n return http.put(value, httpOptions);\n },\n\n /**\n * Get data for a specific document or field.\n *\n * **Example**\n *\n * ds.load('user1');\n * ds.load('user1/question3');\n *\n * **Parameters**\n * @param {String|Object} `key` The id of the data to return. Can be the id of a document, or a path to data within that document.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` Overrides for configuration options.\n */\n load: function (key, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(outputModifier, httpOptions);\n },\n\n /**\n * Removes data from collection. Only documents (top-level elements in each collection) can be deleted.\n *\n * **Example**\n *\n * ds.remove('user1');\n *\n *\n * **Parameters**\n *\n * @param {String|Array} `keys` The id of the document to remove from this collection, or an array of such ids.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n remove: function (keys, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n var params;\n if ($.isArray(keys)) {\n params = { id: keys };\n } else {\n params = '';\n httpOptions.url = getURL(keys, httpOptions.root);\n }\n return http.delete(params, httpOptions);\n }\n\n // Epicenter doesn't allow nuking collections\n // /**\n // * Removes collection being referenced\n // * @return null\n // */\n // destroy: function (options) {\n // return this.remove('', options);\n // }\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n * ## State API Adapter\n *\n * The State API Adapter allows you to replay or clone runs. It brings existing, persisted run data from the database back into memory, using the same run id (`replay`) or a new run id (`clone`). Runs must be in memory in order for you to update variables or call operations on them.\n *\n * Specifically, the State API Adapter works by \"re-running\" the run (user interactions) from the creation of the run up to the time it was last persisted in the database. This process uses the current version of the run's model. Therefore, if the model has changed since the original run was created, the retrieved run will use the new model — and may end up having different values or behavior as a result. Use with care!\n *\n * To use the State API Adapter, instantiate it and then call its methods:\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f'});\n *\n * The constructor takes an optional `options` parameter in which you can specify the `account` and `project` if they are not already available in the current context.\n *\n */\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar SessionManager = require('../store/session-manager');\nvar apiEndpoint = 'model/state';\n\nmodule.exports = function (config) {\n\n var defaults = {\n\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n var parseRunIdOrError = function (params) {\n if ($.isPlainObject(params) && params.runId) {\n return params.runId;\n } else {\n throw new Error('Please pass in a run id');\n }\n };\n\n var publicAPI = {\n /**\n * Replay a run. After this call, the run, with its original run id, is now available [in memory](../../../run_persistence/#runs-in-memory). (It continues to be persisted into the Epicenter database at regular intervals.)\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore'});\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to bring back to memory.\n * @param {string} `params.stopBefore` (Optional) The run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n replay: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'replay' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n },\n\n /**\n * Clone a given run and return a new run in the same state as the given run.\n *\n * The new run id is now available [in memory](../../../run_persistence/#runs-in-memory). The new run includes a copy of all of the data from the original run, EXCEPT:\n *\n * * The `saved` field in the new run record is not copied from the original run record. It defaults to `false`.\n * * The `initialized` field in the new run record is not copied from the original run record. It defaults to `false` but may change to `true` as the new run is advanced. For example, if there has been a call to the `step` function (for Vensim models), the `initialized` field is set to `true`.\n * * The `created` field in the new run record is the date and time at which the clone was created (not the time that the original run was created.)\n *\n * The original run remains only [in the database](../../../run_persistence/#runs-in-db).\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.clone({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore', exclude: ['interimCalculation'] });\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to clone from memory.\n * @param {string} `params.stopBefore` (Optional) The newly cloned run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the newly cloned run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n clone: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'clone' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * ## World API Adapter\n *\n * A [run](../../../glossary/#run) is a collection of end user interactions with a project and its model -- including setting variables, making decisions, and calling operations. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases. Only [team projects](../../../glossary/#team) can be multiplayer.\n *\n * The World API Adapter allows you to create, access, and manipulate multiplayer worlds within your Epicenter project. You can use this to add and remove end users from the world, and to create, access, and remove their runs. Because of this, typically the World Adapter is used for facilitator pages in your project. (The related [World Manager](../world-manager/) provides an easy way to access runs and worlds for particular end users, so is typically used in pages that end users will interact with.)\n *\n * As with all the other [API Adapters](../../), all methods take in an \"options\" object as the last parameter. The options can be used to extend/override the World API Service defaults.\n *\n * To use the World Adapter, instantiate it and then access the methods provided. Instantiating requires the account id (**Team ID** in the Epicenter user interface), project id (**Project ID**), and group (**Group Name**).\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // call methods, e.g. wa.addUsers()\n * });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar _pick = require('../util/object-util')._pick;\n\nvar apiBase = 'multiplayer/';\nvar assignmentEndpoint = apiBase + 'assign';\nvar apiEndpoint = apiBase + 'world';\nvar projectEndpoint = apiBase + 'project';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The group name. Defaults to undefined.\n * @type {String}\n */\n group: undefined,\n\n /**\n * The model file to use to create runs in this world. Defaults to undefined.\n * @type {String}\n */\n model: undefined,\n\n /**\n * Criteria by which to filter world. Currently only supports world-ids as filters.\n * @type {String}\n */\n filter: '',\n\n /**\n * Convenience alias for filter\n * @type {String}\n */\n id: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {},\n\n /**\n * Called when the call completes successfully. Defaults to `$.noop`.\n * @type {function}\n */\n success: $.noop,\n\n /**\n * Called when the call fails. Defaults to `$.noop`.\n * @type {function}\n */\n error: $.noop\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n if (serviceOptions.id) {\n serviceOptions.filter = serviceOptions.id;\n }\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var setIdFilterOrThrowError = function (options) {\n if (options.id) {\n serviceOptions.filter = options.id;\n }\n if (options.filter) {\n serviceOptions.filter = options.filter;\n }\n if (!serviceOptions.filter) {\n throw new Error('No world id specified to apply operations against. This could happen if the user is not assigned to a world and is trying to work with runs from that world.');\n }\n };\n\n var validateModelOrThrowError = function (options) {\n if (!options.model) {\n throw new Error('No model specified to get the current run');\n }\n };\n\n var publicAPI = {\n\n /**\n * Creates a new World.\n *\n * Using this method is rare. It is more common to create worlds automatically while you `autoAssign()` end users to worlds. (In this case, configuration data for the world, such as the roles, are read from the project-level world configuration information, for example by `getProjectSettings()`.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create({\n * roles: ['VP Marketing', 'VP Sales', 'VP Engineering']\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to create the world.\n * @param {string} `params.group` (Optional) The **Group Name** to create this world under. Only end users in this group are eligible to join the world. Optional here; required when instantiating the service (`new F.service.World()`).\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (params, options) {\n var createOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) });\n var worldApiParams = ['scope', 'files', 'roles', 'optionalRoles', 'minUsers', 'group', 'name'];\n var validParams = _pick(serviceOptions, ['account', 'project', 'group']);\n // whitelist the fields that we actually can send to the api\n params = _pick(params, worldApiParams);\n\n // account and project go in the body, not in the url\n params = $.extend({}, validParams, params);\n\n var oldSuccess = createOptions.success;\n createOptions.success = function (response) {\n serviceOptions.filter = response.id; //all future chained calls to operate on this id\n return oldSuccess.apply(this, arguments);\n };\n\n return http.post(params, createOptions);\n },\n\n /**\n * Updates a World, for example to replace the roles in the world.\n *\n * Typically, you complete world configuration at the project level, rather than at the world level. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both. However, this method is available if you need to update the configuration of a particular world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.update({ roles: ['VP Marketing', 'VP Sales', 'VP Engineering'] });\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to update the world.\n * @param {string} `params.name` A string identifier for the linked end users, for example, \"name\": \"Our Team\".\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n update: function (params, options) {\n var whitelist = ['roles', 'optionalRoles', 'minUsers'];\n options = options || {};\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n params = _pick(params || {}, whitelist);\n\n return http.patch(params, updateOptions);\n },\n\n /**\n * Deletes an existing world.\n *\n * This function optionally takes one argument. If the argument is a string, it is the id of the world to delete. If the argument is an object, it is the override for global options.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.delete();\n * });\n *\n * **Parameters**\n * @param {String|Object} `options` (Optional) The id of the world to delete, or options object to override global options.\n *\n */\n delete: function (options) {\n options = (options && (typeof options === 'string')) ? { filter: options } : {};\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Updates the configuration for the current instance of the World API Adapter (including all subsequent function calls, until the configuration is updated again).\n *\n * **Example**\n *\n * var wa = new F.service.World({...}).updateConfig({ filter: '123' }).addUser({ userId: '123' });\n *\n * **Parameters**\n * @param {object} `config` The configuration object to use in updating existing configuration.\n */\n updateConfig: function (config) {\n $.extend(serviceOptions, config);\n\n return this;\n },\n\n /**\n * Lists all worlds for a given account, project, and group. All three are required, and if not specified as parameters, are read from the service.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // lists all worlds in group \"team1\"\n * wa.list();\n *\n * // lists all worlds in group \"other-group-name\"\n * wa.list({ group: 'other-group-name' });\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n list: function (options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = _pick(getOptions, ['account', 'project', 'group']);\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Gets all worlds that an end user belongs to for a given account (team), project, and group.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getWorldsForUser('b1c19dda-2d2e-4777-ad5d-3929f17e86d3')\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose worlds are being retrieved.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getWorldsForUser: function (userId, options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = $.extend(\n _pick(getOptions, ['account', 'project', 'group']),\n { userId: userId }\n );\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Load information for a specific world. All further calls to the world service will use the id provided.\n *\n * **Parameters**\n * @param {String} `worldId` The id of the world to load.\n * @param {Object} `options` (Optional) Options object to override global options.\n */\n load: function (worldId, options) {\n if (worldId) {\n serviceOptions.filter = worldId;\n }\n if (!serviceOptions.filter) {\n throw new Error('Please provide a worldid to load');\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/' });\n return http.get('', httpOptions);\n },\n\n /**\n * Adds an end user or list of end users to a given world. The end user must be a member of the `group` that is associated with this world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // add one user\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.addUsers(['b1c19dda-2d2e-4777-ad5d-3929f17e86d3']);\n * wa.addUsers({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'VP Sales' });\n *\n * // add several users\n * wa.addUsers([\n * { userId: 'a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44',\n * role: 'VP Marketing' },\n * { userId: '8f2604cf-96cd-449f-82fa-e331530734ee',\n * role: 'VP Engineering' }\n * ]);\n *\n * // add one user to a specific world\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', world.id);\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', { filter: world.id });\n * });\n *\n * ** Parameters **\n * @param {string|object|array} `users` User id, array of user ids, object, or array of objects of the users to add to this world.\n * @param {string} `users.role` The `role` the user should have in the world. It is up to the caller to ensure, if needed, that the `role` passed in is one of the `roles` or `optionalRoles` of this world.\n * @param {string} `worldId` The world to which the users should be added. If not specified, the filter parameter of the `options` object is used.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n addUsers: function (users, worldId, options) {\n\n if (!users) {\n throw new Error('Please provide a list of users to add to the world');\n }\n\n // normalize the list of users to an array of user objects\n users = $.map([].concat(users), function (u) {\n var isObject = $.isPlainObject(u);\n\n if (typeof u !== 'string' && !isObject) {\n throw new Error('Some of the users in the list are not in the valid format: ' + u);\n }\n\n return isObject ? u : { userId: u };\n });\n\n // check if options were passed as the second parameter\n if ($.isPlainObject(worldId) && !options) {\n options = worldId;\n worldId = null;\n }\n\n options = options || {};\n\n // we must have options by now\n if (typeof worldId === 'string') {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users' }\n );\n\n return http.post(users, updateOptions);\n },\n\n /**\n * Updates the role of an end user in a given world. (You can only update one end user at a time.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.create().then(function(world) {\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.updateUser({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'leader' });\n * });\n *\n * **Parameters**\n * @param {object} `user` User object with `userId` and the new `role`.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n updateUser: function (user, options) {\n options = options || {};\n\n if (!user || !user.userId) {\n throw new Error('You need to pass a userId to update from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var patchOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.patch(_pick(user, 'role'), patchOptions);\n },\n\n /**\n * Removes an end user from a given world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.addUsers(['a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44', '8f2604cf-96cd-449f-82fa-e331530734ee']);\n * wa.removeUser('a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44');\n * wa.removeUser({ userId: '8f2604cf-96cd-449f-82fa-e331530734ee' });\n * });\n *\n * ** Parameters **\n * @param {object|string} `user` The `userId` of the user to remove from the world, or an object containing the `userId` field.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n removeUser: function (user, options) {\n options = options || {};\n\n if (typeof user === 'string') {\n user = { userId: user };\n }\n\n if (!user.userId) {\n throw new Error('You need to pass a userId to remove from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.delete(null, getOptions);\n },\n\n /**\n * Gets the run id of current run for the given world. If the world does not have a run, creates a new one and returns the run id.\n *\n * Remember that a [run](../../glossary/#run) is a collection of interactions with a project and its model. In the case of multiplayer projects, the run is shared by all end users in the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getCurrentRunId({ model: 'model.py' });\n * });\n *\n * ** Parameters **\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n getCurrentRunId: function (options) {\n options = options || {};\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n validateModelOrThrowError(getOptions);\n return http.post(_pick(getOptions, 'model'), getOptions);\n },\n\n /**\n * Gets the current (most recent) world for the given end user in the given group. Brings this most recent world into memory if needed.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function(world) {\n * // use data from world\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose current (most recent) world is being retrieved.\n * @param {string} `groupName` (Optional) The name of the group. If not provided, defaults to the group used to create the service.\n */\n getCurrentWorldForUser: function (userId, groupName) {\n var dtd = $.Deferred();\n var me = this;\n this.getWorldsForUser(userId, { group: groupName })\n .then(function (worlds) {\n // assume the most recent world as the 'active' world\n worlds.sort(function (a, b) { return new Date(b.lastModified) - new Date(a.lastModified); });\n var currentWorld = worlds[0];\n\n if (currentWorld) {\n serviceOptions.filter = currentWorld.id;\n }\n\n dtd.resolve(currentWorld, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Deletes the current run from the world.\n *\n * (Note that the world id remains part of the run record, indicating that the run was formerly an active run for the world.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.deleteRun('sample-world-id');\n *\n * **Parameters**\n * @param {string} `worldId` The `worldId` of the world from which the current run is being deleted.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n deleteRun: function (worldId, options) {\n options = options || {};\n\n if (worldId) {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Creates a new run for the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function (world) {\n * wa.newRunForWorld(world.id);\n * });\n *\n * **Parameters**\n * @param {string} `worldId` worldId in which we create the new run.\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n newRunForWorld: function (worldId, options) {\n var currentRunOptions = $.extend(true, {},\n options,\n { filter: worldId || serviceOptions.filter }\n );\n var _this = this;\n\n validateModelOrThrowError(currentRunOptions);\n\n return this.deleteRun(worldId, options)\n .then(function () {\n return _this.getCurrentRunId(currentRunOptions);\n });\n },\n\n /**\n * Assigns end users to worlds, creating new worlds as appropriate, automatically. Assigns all end users in the group, and creates new worlds as needed based on the project-level world configuration (roles, optional roles, and minimum end users per world).\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.autoAssign();\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n autoAssign: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(assignmentEndpoint) }\n );\n\n var params = {\n account: opt.account,\n project: opt.project,\n group: opt.group\n };\n\n if (opt.maxUsers) {\n params.maxUsers = opt.maxUsers;\n }\n\n return http.post(params, opt);\n },\n\n /**\n * Gets the project's world configuration.\n *\n * Typically, every interaction with your project uses the same configuration of each world. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both.\n *\n * (The [Multiplayer Project REST API](../../../rest_apis/multiplayer/multiplayer_project/) allows you to set these project-level world configurations. The World Adapter simply retrieves them, for example so they can be used in auto-assignment of end users to worlds.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getProjectSettings()\n * .then(function(settings) {\n * console.log(settings.roles);\n * console.log(settings.optionalRoles);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getProjectSettings: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(projectEndpoint) }\n );\n\n opt.url += [opt.account, opt.project].join('/');\n\n return http.get(null, opt);\n }\n\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n* ## User API Adapter\n*\n* The User API Adapter allows you to retrieve details about end users in your team (account). It is based on the querying capabilities of the underlying RESTful [User API](../../../rest_apis/user_management/user/).\n*\n* To use the User API Adapter, instantiate it and then call its methods.\n*\n* var ua = new F.service.User({\n* account: 'acme-simulations',\n* token: 'user-or-project-access-token'\n* });\n* ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n* ua.get({ userName: 'jsmith' });\n* ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n* '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n*\n* The constructor takes an optional `options` parameter in which you can specify the `account` and `token` if they are not already available in the current context.\n*/\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar qutil = require('../util/query-util');\n\nmodule.exports = function (config) {\n var defaults = {\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The access token to use when searching for end users. (See [more background on access tokens](../../../project_access/)).\n * @type {String}\n */\n token: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('user')\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Retrieve details about particular end users in your team, based on user name or user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.get({ userName: 'jsmith' });\n * ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n * '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n *\n * **Parameters**\n * @param {object} `filter` Object with field `userName` and value of the username. Alternatively, object with field `id` and value of an array of user ids.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n get: function (filter, options) {\n options = options || {};\n filter = filter || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options\n );\n\n var toQFilter = function (filter) {\n var res = {};\n\n // API only supports filtering by username for now\n if (filter.userName) {\n res.q = filter.userName;\n }\n\n return res;\n };\n\n var toIdFilters = function (id) {\n if (!id) {\n return '';\n }\n\n id = $.isArray(id) ? id : [id];\n return 'id=' + id.join('&id=');\n };\n\n var getFilters = [\n 'account=' + getOptions.account,\n toIdFilters(filter.id),\n qutil.toQueryFormat(toQFilter(filter))\n ].join('&');\n\n // special case for queries with large number of ids\n // make it as a post with GET semantics\n var threshold = 30;\n if (filter.id && $.isArray(filter.id) && filter.id.length >= threshold) {\n getOptions.url = urlConfig.getAPIPath('user') + '?_method=GET';\n return http.post({ id: filter.id }, getOptions);\n } else {\n return http.get(getFilters, getOptions);\n }\n },\n\n /**\n * Retrieve details about a single end user in your team, based on user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n *\n * **Parameters**\n * @param {string} `userId` The user id for the end user in your team.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n getById: function (userId, options) {\n return publicAPI.get({ id: userId }, options);\n }\n };\n\n $.extend(this, publicAPI);\n};\n\n\n\n\n","/**\n *\n * ## Member API Adapter\n *\n * The Member API Adapter provides methods to look up information about end users for your project and how they are divided across groups. It is based on query capabilities of the underlying RESTful [Member API](../../../rest_apis/user_management/member/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/). For example, if some of your end users are facilitators, or if your end users should be treated differently based on which group they are in, use the Member API to find that information.\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser({ userId: 'b6b313a3-ab84-479c-baea-206f6bff337' });\n * ma.getGroupDetails({ groupId: '00b53308-9833-47f2-b21e-1278c07d53b8' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'member/local';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Epicenter user id. Defaults to a blank string.\n * @type {string}\n */\n userId: undefined,\n\n /**\n * Epicenter group id. Defaults to a blank string. Note that this is the group *id*, not the group *name*.\n * @type {string}\n */\n groupId: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(transportOptions, serviceOptions);\n\n var getFinalParams = function (params) {\n if (typeof params === 'object') {\n return $.extend(true, serviceOptions, params);\n }\n return serviceOptions;\n };\n\n var patchUserActiveField = function (params, active, options) {\n var httpOptions = $.extend(true, serviceOptions, options, {\n url: urlConfig.getAPIPath(apiEndpoint) + params.groupId + '/' + params.userId\n });\n\n return http.patch({ active: active }, httpOptions);\n };\n\n var publicAPI = {\n\n /**\n * Retrieve details about all of the group memberships for one end user. The membership details are returned in an array, with one element (group record) for each group to which the end user belongs.\n *\n * In the membership array, each group record includes the group id, project id, account (team) id, and an array of members. However, only the user whose userId is included in the call is listed in the members array (regardless of whether there are other members in this group).\n *\n * **Example**\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser('42836d4b-5b61-4fe4-80eb-3136e956ee5c')\n * .then(function(memberships){\n * for (var i=0; i\n * // \n * // \n * // \n * // \n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar SessionManager = require('../store/session-manager');\n\nvar apiEndpoint = 'asset';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n /**\n * The group name. Defaults to session's `groupName`.\n * @type {String}\n */\n group: undefined,\n /**\n * The user id. Defaults to session's `userId`.\n * @type {String}\n */\n userId: undefined,\n /**\n * The scope for the asset. Valid values are: `user`, `group`, and `project`. See above for the required permissions to write to each scope. Defaults to `user`, meaning the current end user or a facilitator in the end user's group can edit the asset.\n * @type {String}\n */\n scope: 'user',\n /**\n * Determines if a request to list the assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`). Defaults to `true`.\n * @type {boolean}\n */\n fullUrl: true,\n /**\n * The transport object contains the options passed to the XHR request.\n * @type {object}\n */\n transport: {\n processData: false\n }\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var assetApiParams = ['encoding', 'data', 'contentType'];\n var scopeConfig = {\n user: ['scope', 'account', 'project', 'group', 'userId'],\n group: ['scope', 'account', 'project', 'group'],\n project: ['scope', 'account', 'project'],\n };\n\n var validateFilename = function (filename) {\n if (!filename) {\n throw new Error('filename is needed.');\n }\n };\n\n var validateUrlParams = function (options) {\n var partKeys = scopeConfig[options.scope];\n if (!partKeys) {\n throw new Error('scope parameter is needed.');\n }\n\n $.each(partKeys, function () {\n if (!options[this]) {\n throw new Error(this + ' parameter is needed.');\n }\n });\n };\n\n var buildUrl = function (filename, options) {\n validateUrlParams(options);\n var partKeys = scopeConfig[options.scope];\n var parts = $.map(partKeys, function (key) {\n return options[key];\n });\n if (filename) {\n // This prevents adding a trailing / in the URL as the Asset API\n // does not work correctly with it\n filename = '/' + filename;\n }\n return urlConfig.getAPIPath(apiEndpoint) + parts.join('/') + filename;\n };\n\n // Private function, all requests follow a more or less same approach to\n // use the Asset API and the difference is the HTTP verb\n //\n // @param {string} `method` (Required) HTTP verb\n // @param {string} `filename` (Required) Name of the file to delete/replace/create\n // @param {object} `params` (Optional) Body parameters to send to the Asset API\n // @param {object} `options` (Optional) Options object to override global options.\n var upload = function (method, filename, params, options) {\n validateFilename(filename);\n // make sure the parameter is clean\n method = method.toLowerCase();\n var contentType = params instanceof FormData === true ? false : 'application/json';\n if (contentType === 'application/json') {\n // whitelist the fields that we actually can send to the api\n params = _pick(params, assetApiParams);\n } else { // else we're sending form data which goes directly in request body\n // For multipart/form-data uploads the filename is not set in the URL,\n // it's getting picked by the FormData field filename.\n filename = method === 'post' || method === 'put' ? '' : filename;\n }\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var createOptions = $.extend(true, {}, urlOptions, { url: url, contentType: contentType });\n\n return http[method](params, createOptions);\n };\n\n var publicAPI = {\n /**\n * Creates a file in the Asset API. The server returns an error (status code `409`, conflict) if the file already exists, so\n * check first with a `list()` or a `get()`.\n *\n * **Example**\n *\n * var aa = new F.service.Asset({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * userId: ''\n * });\n *\n * // create a new asset using encoded text\n * aa.create('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHRlc3QgZmlsZS4=',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, create a new asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to create.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (filename, params, options) {\n return upload('post', filename, params, options);\n },\n\n /**\n * Gets a file from the Asset API, fetching the asset content. (To get a list\n * of the assets in a scope, use `list()`.)\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to retrieve.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n get: function (filename, options) {\n var getServiceOptions = _pick(serviceOptions, ['scope', 'account', 'project', 'group', 'userId']);\n var urlOptions = $.extend({}, getServiceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n\n return http.get({}, getOptions);\n },\n\n /**\n * Gets the list of the assets in a scope.\n *\n * **Example**\n *\n * aa.list({ fullUrl: true }).then(function(fileList){\n * console.log('array of files = ', fileList);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {string} `options.scope` (Optional) The scope (`user`, `group`, `project`).\n * @param {boolean} `options.fullUrl` (Optional) Determines if the list of assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`).\n *\n */\n list: function (options) {\n var dtd = $.Deferred();\n var me = this;\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl('', urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n var fullUrl = getOptions.fullUrl;\n\n if (!fullUrl) {\n return http.get({}, getOptions);\n }\n\n http.get({}, getOptions)\n .then(function (files) {\n var fullPathFiles = $.map(files, function (file) {\n return buildUrl(file, urlOptions);\n });\n dtd.resolve(fullPathFiles, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Replaces an existing file in the Asset API.\n *\n * **Example**\n *\n * // replace an asset using encoded text\n * aa.replace('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHNlY29uZCB0ZXN0IGZpbGUu',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, replace an asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#replace-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#replace-filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.replace(filename, data, { scope: 'user' });\n * });\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file being replaced.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n replace: function (filename, params, options) {\n return upload('put', filename, params, options);\n },\n\n /**\n * Deletes a file from the Asset API.\n *\n * **Example**\n *\n * aa.delete(sampleFileName);\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to delete.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n delete: function (filename, options) {\n return upload('delete', filename, {}, options);\n },\n\n assetUrl: function (filename, options) {\n var urlOptions = $.extend({}, serviceOptions, options);\n return buildUrl(filename, urlOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * @class Cookie Storage Service\n *\n * @example\n * var people = require('cookie-store')({ root: 'people' });\n people\n .save({lastName: 'smith' })\n\n */\n\n\n'use strict';\n\n// Thin document.cookie wrapper to allow unit testing\nvar Cookie = function () {\n this.get = function () {\n return document.cookie;\n };\n\n this.set = function (newCookie) {\n document.cookie = newCookie;\n };\n};\n\nmodule.exports = function (config) {\n var host = window.location.hostname;\n var defaults = {\n /**\n * Name of collection\n * @type { string}\n */\n root: '/',\n\n domain: '.' + host,\n cookie: new Cookie()\n };\n this.serviceOptions = $.extend({}, defaults, config);\n\n var publicAPI = {\n // * TBD\n // * Query collection; uses MongoDB syntax\n // * @see \n // *\n // * @param { string} qs Query Filter\n // * @param { string} limiters @see \n // *\n // * @example\n // * cs.query(\n // * { name: 'John', className: 'CSC101' },\n // * {limit: 10}\n // * )\n\n // query: function (qs, limiters) {\n\n // },\n\n /**\n * Save cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @param {Object} value (Optional)\n * @param {Object} options Overrides for service options\n *\n * @return {*} The saved value\n *\n * @example\n * cs.set('person', { firstName: 'john', lastName: 'smith' });\n * cs.set({ name:'smith', age:'32' });\n */\n set: function (key, value, options) {\n var setOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = setOptions.domain;\n var path = setOptions.root;\n var cookie = setOptions.cookie;\n\n cookie.set(encodeURIComponent(key) + '=' +\n encodeURIComponent(value) +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '')\n );\n\n return value;\n },\n\n /**\n * Load cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @return {*} The value stored\n *\n * @example\n * cs.get('person');\n */\n get: function (key) {\n var cookie = this.serviceOptions.cookie;\n var cookieReg = new RegExp('(?:^|;)\\\\s*' + encodeURIComponent(key).replace(/[\\-\\.\\+\\*]/g, '\\\\$&') + '\\\\s*\\\\=\\\\s*([^;]*).*$');\n var res = cookieReg.exec(cookie.get());\n var val = res ? decodeURIComponent(res[1]) : null;\n return val;\n },\n\n /**\n * Removes key from collection\n * @param { string} key key to remove\n * @return { string} key The key removed\n *\n * @example\n * cs.remove('person');\n */\n remove: function (key, options) {\n var remOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = remOptions.domain;\n var path = remOptions.root;\n var cookie = remOptions.cookie;\n\n cookie.set(encodeURIComponent(key) +\n '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '')\n );\n return key;\n },\n\n /**\n * Removes collection being referenced\n * @return { array} keys All the keys removed\n */\n destroy: function () {\n var cookie = this.serviceOptions.cookie;\n var aKeys = cookie.get().replace(/((?:^|\\s*;)[^\\=]+)(?=;|$)|^\\s*|\\s*(?:\\=[^;]*)?(?:\\1|$)/g, '').split(/\\s*(?:\\=[^;]*)?;\\s*/);\n for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {\n var cookieKey = decodeURIComponent(aKeys[nIdx]);\n this.remove(cookieKey);\n }\n return aKeys;\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n Decides type of store to provide\n*/\n\n'use strict';\n// var isNode = false; FIXME: Browserify/minifyify has issues with the next link\n// var store = (isNode) ? require('./session-store') : require('./cookie-store');\nvar store = require('./cookie-store');\n\nmodule.exports = store;\n","'use strict';\nvar RunService = require('../service/run-api-service');\n\nvar defaults = {\n validFilter: { saved: true }\n};\n\nfunction ScenarioManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n this.runService = this.options.run || new RunService(this.options);\n}\n\nScenarioManager.prototype = {\n getRuns: function (filter) {\n this.filter = $.extend(true, {}, this.options.validFilter, filter);\n return this.runService.query(this.filter);\n },\n\n loadVariables: function (vars) {\n return this.runService.query(this.filter, { include: vars });\n },\n\n save: function (run, meta) {\n return this._getService(run).save($.extend(true, {}, { saved: true }, meta));\n },\n\n archive: function (run) {\n return this._getService(run).save({ saved: false });\n },\n\n _getService: function (run) {\n if (typeof run === 'string') {\n return new RunService($.extend(true, {}, this.options, { filter: run }));\n }\n\n if (typeof run === 'object' && run instanceof RunService) {\n return run;\n }\n\n throw new Error('Save method requires a run service or a runId');\n },\n\n getRun: function (runId) {\n return new RunService($.extend(true, {}, this.options, { filter: runId }));\n }\n};\n\nmodule.exports = ScenarioManager;\n\n","/**\n* ## Run Manager\n*\n* The Run Manager gives you access to runs for your project. This allows you to read and update variables, call operations, etc. Additionally, the Run Manager gives you control over run creation depending on run states. Specifically, you can select [run creation strategies (rules)](../../strategy/) for which runs end users of your project work with when they log in to your project.\n*\n* There are many ways to create new runs, including the Epicenter.js [Run Service](../run-api-service/), the RESFTful [Run API](../../../rest_apis/aggregate_run_api) and the [Model Run API](../../../rest_apis/other_apis/model_apis/run/). However, for some projects it makes more sense to pick up where the user left off, using an existing run. And in some projects, whether to create a new run or use an existing one is conditional, for example based on characteristics of the existing run or your own knowledge about the model. The Run Manager provides this level of control: your call to `getRun()`, rather than always returning a new run, returns a run based on the strategy you've specified. (Note that many of the Epicenter sample projects use a Run Service directly, because generally the sample projects are played in one end user session and don't care about run states or run strategies.)\n*\n*\n* ### Using the Run Manager to create and access runs\n*\n* To use the Run Manager, instantiate it by passing in:\n*\n* * `run`: (required) Run object. Must contain:\n* * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n* * `project`: Epicenter project id.\n* * `model`: The name of your primary model file. (See more on [Writing your Model](../../../writing_your_model/).)\n* * `scope`: (optional) Scope object for the run, for example `scope.group` with value of the name of the group.\n* * `server`: (optional) An object with one field, `host`. The value of `host` is the string `api.forio.com`, the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n* * `files`: (optional) If and only if you are using a Vensim model and you have additional data to pass in to your model, you can pass a `files` object with the names of the files, for example: `\"files\": {\"data\": \"myExtraData.xls\"}`. (Note that you'll also need to add this same files object to your Vensim [configuration file](../../../model_code/vensim/).) See the [underlying Model Run API](../../../rest_apis/other_apis/model_apis/run/#post-creating-a-new-run-for-this-project) for additional information.\n*\n* * `strategy`: (optional) Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n*\n* * `sessionKey`: (optional) Name of browser cookie in which to store run information, including run id. Many conditional strategies, including the provided strategies, rely on this browser cookie to store the run id and help make the decision of whether to create a new run or use an existing one. The name of this cookie defaults to `epicenter-scenario` and can be set with the `sessionKey` parameter.\n*\n*\n* After instantiating a Run Manager, make a call to `getRun()` whenever you need to access a run for this end user. The `RunManager.run` contains the instantiated [Run Service](../run-api-service/). The Run Service allows you to access variables, call operations, etc.\n*\n* **Example**\n*\n* var rm = new F.manager.RunManager({\n* run: {\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* model: 'supply-chain-model.jl',\n* server: { host: 'api.forio.com' }\n* },\n* strategy: 'always-new',\n* sessionKey: 'epicenter-session'\n* });\n* rm.getRun()\n* .then(function(run) {\n* // the return value of getRun() is a run object\n* var thisRunId = run.id;\n* // the RunManager.run also contains the instantiated Run Service,\n* // so any Run Service method is valid here\n* rm.run.do('runModel');\n* })\n*\n*/\n\n'use strict';\nvar strategiesMap = require('./run-strategies/strategies-map');\nvar specialOperations = require('./special-operations');\nvar RunService = require('../service/run-api-service');\n\n\nfunction patchRunService(service, manager) {\n if (service.patched) {\n return service;\n }\n\n var orig = service.do;\n service.do = function (operation, params, options) {\n var reservedOps = Object.keys(specialOperations);\n if (reservedOps.indexOf(operation) === -1) {\n return orig.apply(service, arguments);\n } else {\n return specialOperations[operation].call(service, params, options, manager);\n }\n };\n\n service.patched = true;\n\n return service;\n}\n\n\n\nvar defaults = {\n /**\n * Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n * @type {String}\n */\n\n strategy: 'new-if-initialized'\n};\n\nfunction RunManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n if (this.options.run instanceof RunService) {\n this.run = this.options.run;\n } else {\n this.run = new RunService(this.options.run);\n }\n\n patchRunService(this.run, this);\n\n var StrategyCtor = typeof this.options.strategy === 'function' ? this.options.strategy : strategiesMap[this.options.strategy];\n\n if (!StrategyCtor) {\n throw new Error('Specified run creation strategy was invalid:', this.options.strategy);\n }\n\n this.strategy = new StrategyCtor(this.run, this.options);\n}\n\nRunManager.prototype = {\n /**\n * Returns the run object for a 'good' run.\n *\n * A good run is defined by the strategy. For example, if the strategy is `always-new`, the call\n * to `getRun()` always returns a newly created run; if the strategy is `new-if-persisted`,\n * `getRun()` creates a new run if the previous run is in a persisted state, otherwise\n * it returns the previous run. See [Run Manager Strategies](../../strategy/) for more on strategies.\n *\n * **Example**\n *\n * rm.getRun().then(function (run) {\n * // use the run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * @return {$promise} Promise to complete the call.\n */\n getRun: function () {\n return this.strategy\n .getRun();\n },\n\n /**\n * Returns the run object for a new run, regardless of strategy: force creation of a new run.\n *\n * **Example**\n *\n * rm.reset().then(function (run) {\n * // use the (new) run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * **Parameters**\n * @param {Object} `runServiceOptions` The options object to configure the Run Service. See [Run API Service](../run-api-service/) for more.\n */\n reset: function (runServiceOptions) {\n return this.strategy.reset(runServiceOptions);\n }\n};\n\nmodule.exports = RunManager;\n","/**\n* ## Authorization Manager\n*\n* The Authorization Manager provides an easy way to manage user authentication (logging in and out) and authorization (keeping track of tokens, sessions, and groups) for projects.\n*\n* The Authorization Manager is most useful for [team projects](../../../glossary/#team) with an access level of [Authenticated](../../../glossary/#access). These projects are accessed by [end users](../../../glossary/#users) who are members of one or more [groups](../../../glossary/#groups).\n*\n* #### Using the Authorization Manager\n*\n* To use the Authorization Manager, instantiate it. Then, make calls to any of the methods you need:\n*\n* var authMgr = new F.manager.AuthManager({\n* account: 'acme-simulations',\n* userName: 'enduser1',\n* password: 'passw0rd'\n* });\n* authMgr.login().then(function () {\n* authMgr.getCurrentUserSessionInfo();\n* });\n*\n*\n* The `options` object passed to the `F.manager.AuthManager()` call can include:\n*\n* * `account`: The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects).\n* * `userName`: Email or username to use for logging in.\n* * `password`: Password for specified `userName`.\n* * `project`: The **Project ID** for the project to log this user into. Optional.\n* * `groupId`: Id of the group to which `userName` belongs. Required for end users if the `project` is specified.\n*\n* If you prefer starting from a template, the Epicenter JS Libs [Login Component](../../#components) uses the Authorization Manager as well. This sample HTML page (and associated CSS and JS files) provides a login form for team members and end users of your project. It also includes a group selector for end users that are members of multiple groups.\n*/\n\n'use strict';\nvar AuthAdapter = require('../service/auth-api-service');\nvar MemberAdapter = require('../service/member-api-adapter');\nvar SessionManager = require('../store/session-manager');\nvar Buffer = require('buffer').Buffer;\nvar _pick = require('../util/object-util')._pick;\n\nvar defaults = {\n requiresGroup: true\n};\n\nfunction AuthManager(options) {\n options = $.extend(true, {}, defaults, options);\n this.sessionManager = new SessionManager(options);\n this.options = this.sessionManager.getMergedOptions();\n\n this.isLocal = this.options.isLocal;\n this.authAdapter = new AuthAdapter(this.options);\n}\n\nvar _findUserInGroup = function (members, id) {\n for (var j = 0; j 1) {\n if (groupId) {\n var filteredGroups = $.grep(memberInfo, function (resGroup) {\n return resGroup.groupId === groupId;\n });\n group = filteredGroups.length === 1 ? filteredGroups[0] : null;\n }\n }\n\n if (group) {\n var groupData = {\n 'groupId': group.groupId,\n 'groupName': group.name,\n 'isFac': _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator'\n };\n var sessionInfoWithGroup = $.extend({}, sessionInfo, groupData);\n sessionInfo.groups[project] = groupData;\n _this.sessionManager.saveSession(sessionInfoWithGroup, adapterOptions);\n outSuccess.apply(this, [data]);\n $d.resolve(data);\n } else {\n handleGroupError('This user is associated with more than one group. Please specify a group id to log into and try again', 403, data);\n }\n }).fail($d.reject);\n };\n\n adapterOptions.success = handleSuccess;\n adapterOptions.error = function (response) {\n if (adapterOptions.account) {\n // Try to login as a system user\n adapterOptions.account = null;\n adapterOptions.error = function () {\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n _this.authAdapter.login(adapterOptions);\n return;\n }\n\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n this.authAdapter.login(adapterOptions);\n return $d.promise();\n },\n\n /**\n * Logs user out by clearing all session information.\n *\n * **Example**\n *\n * authMgr.logout();\n *\n * **Parameters**\n *\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var _this = this;\n var adapterOptions = this.sessionManager.getMergedOptions(options);\n\n var removeCookieFn = function (response) {\n _this.sessionManager.removeSession();\n };\n\n return this.authAdapter.logout(adapterOptions).done(removeCookieFn);\n },\n\n /**\n * Returns the existing user access token if the user is already logged in. Otherwise, logs the user in, creating a new user access token, and returns the new token. (See [more background on access tokens](../../../project_access/)).\n *\n * **Example**\n *\n * authMgr.getToken()\n * .then(function (token) {\n * console.log('My token is ', token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getToken: function (options) {\n var httpOptions = this.sessionManager.getMergedOptions(options);\n\n var session = this.sessionManager.getSession();\n var $d = $.Deferred();\n //jshint camelcase: false\n //jscs:disable\n if (session.auth_token) {\n $d.resolve(session.auth_token);\n } else {\n this.login(httpOptions).then($d.resolve);\n }\n return $d.promise();\n },\n\n /**\n * Returns an array of group records, one for each group of which the current user is a member. Each group record includes the group `name`, `account`, `project`, and `groupId`.\n *\n * If some end users in your project are members of multiple groups, this is a useful method to call on your project's login page. When the user attempts to log in, you can use this to display the groups of which the user is member, and have the user select the correct group to log in to for this session.\n *\n * **Example**\n *\n * // get groups for current user\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n * authMgr.getUserGroups({ userId: sessionObj.userId, token: sessionObj.auth_token })\n * .then(function (groups) {\n * for (var i=0; i < groups.length; i++)\n * { console.log(groups[i].name); }\n * });\n *\n * // get groups for particular user\n * authMgr.getUserGroups({userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', token: savedProjAccessToken });\n *\n * **Parameters**\n * @param {Object} `params` Object with a userId and token properties.\n * @param {String} `params.userId` The userId. If looking up groups for the currently logged in user, this is in the session information. Otherwise, pass a string.\n * @param {String} `params.token` The authorization credentials (access token) to use for checking the groups for this user. If looking up groups for the currently logged in user, this is in the session information. A team member's token or a project access token can access all the groups for all end users in the team or project.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getUserGroups: function (params, options) {\n var adapterOptions = this.sessionManager.getMergedOptions({ success: $.noop }, options);\n var $d = $.Deferred();\n var outSuccess = adapterOptions.success;\n\n adapterOptions.success = function (memberInfo) {\n // The member API is at the account scope, we filter by project\n if (adapterOptions.project) {\n memberInfo = $.grep(memberInfo, function (group) {\n return group.project === adapterOptions.project;\n });\n }\n\n outSuccess.apply(this, [memberInfo]);\n $d.resolve(memberInfo);\n };\n\n var memberAdapter = new MemberAdapter({ token: params.token });\n memberAdapter.getGroupsForUser(params, adapterOptions).fail($d.reject);\n return $d.promise();\n },\n\n /**\n * Returns session information for the current user, including the `userId`, `account`, `project`, `groupId`, `groupName`, `isFac` (whether the end user is a facilitator of this group), and `auth_token` (user access token).\n *\n * *Important*: This method is synchronous. The session information is returned immediately in an object; no callbacks or promises are needed.\n *\n * Session information is stored in a cookie in the browser.\n *\n * **Example**\n *\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getCurrentUserSessionInfo: function (options) {\n return this.sessionManager.getSession(options);\n },\n\n // (replace with /* */ comment block, to make visible in docs, once EPICENTER-1939 is complete)\n //\n // Add one or more groups to the current session. \n //\n // This method assumes that the project and group exist and the user specified in the session is part of this project and group.\n //\n // Returns the new session object.\n //\n // **Example**\n //\n // authMgr.addGroups({ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' });\n // authMgr.addGroups([{ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' }, { project: ... }]);\n //\n // **Parameters**\n // @param {object|array} `groups` (Required) The group object must contain the `project` (**Project ID**) and `groupName` properties.\n // @param {string} `group.isFac` (optional) Defaults to `false`. Set to `true` if the user in the session should be a facilitator in this group.\n // @param {string} `group.groupId` (optional) Defaults to undefined. Needed mostly for the Members API.\n //\n addGroups: function (groups) {\n var session = this.getCurrentUserSessionInfo();\n var isArray = Array.isArray(groups);\n groups = isArray ? groups : [groups];\n\n $.each(groups, function (index, group) {\n var extendedGroup = $.extend({}, { isFac: false }, group);\n var project = extendedGroup.project;\n var validProps = ['groupName', 'groupId', 'isFac'];\n if (!project || !extendedGroup.groupName) {\n throw new Error('No project or groupName specified.');\n }\n // filter object\n extendedGroup = _pick(extendedGroup, validProps);\n session.groups[project] = extendedGroup;\n });\n this.sessionManager.saveSession(session);\n return session;\n }\n});\n\nmodule.exports = AuthManager;\n","/**\n* ## World Manager\n*\n* As discussed under the [World API Adapter](../world-api-adapter/), a [run](../../../glossary/#run) is a collection of end user interactions with a project and its model. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases.\n*\n* The World Manager provides an easy way to track and access the current world and run for particular end users. It is typically used in pages that end users will interact with. (The related [World API Adapter](../world-api-adapter/) handles creating multiplayer worlds, and adding and removing end users and runs from a world. Because of this, typically the World Adapter is used for facilitator pages in your project.)\n*\n* ### Using the World Manager\n*\n* To use the World Manager, instantiate it. Then, make calls to any of the methods you need.\n*\n* When you instantiate a World Manager, the world's account id, project id, and group are automatically taken from the session (thanks to the [Authentication Service](../auth-api-service)).\n*\n* Note that the World Manager does *not* create worlds automatically. (This is different than the [Run Manager](../run-manager).) However, you can pass in specific options to any runs created by the manager, using a `run` object.\n*\n* The parameters for creating a World Manager are:\n*\n* * `account`: The **Team ID** in the Epicenter user interface for this project.\n* * `project`: The **Project ID** for this project.\n* * `group`: The **Group Name** for this world.\n* * `run`: Options to use when creating new runs with the manager, e.g. `run: { files: ['data.xls'] }`.\n* * `run.model`: The name of the primary model file for this project. Required if you have not already passed it in as part of the `options` parameter for an enclosing call.\n*\n* For example:\n*\n* var wMgr = new F.manager.WorldManager({\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* run: { model: 'supply-chain.py' },\n* group: 'team1'\n* });\n*\n* wMgr.getCurrentRun();\n*/\n\n'use strict';\n\nvar WorldApi = require('../service/world-api-adapter');\nvar RunManager = require('./run-manager');\nvar AuthManager = require('./auth-manager');\nvar worldApi;\n\n// var defaults = {\n// account: '',\n// project: '',\n// group: '',\n// transport: {\n// }\n// };\n\n\nfunction buildStrategy(worldId, dtd) {\n\n return function Ctor(runService, options) {\n this.runService = runService;\n this.options = options;\n\n $.extend(this, {\n reset: function () {\n throw new Error('not implementd. Need api changes');\n },\n\n getRun: function () {\n var _this = this;\n //get or create!\n // Model is required in the options\n var model = this.options.run.model || this.options.model;\n return worldApi.getCurrentRunId({ model: model, filter: worldId })\n .then(function (runId) {\n return _this.runService.load(runId);\n })\n .then(function (run) {\n dtd.resolve.call(this, run, _this.runService);\n })\n .fail(dtd.reject);\n }\n }\n );\n };\n}\n\n\nmodule.exports = function (options) {\n this.options = options || { run: {}, world: {} };\n\n $.extend(true, this.options, this.options.run);\n $.extend(true, this.options, this.options.world);\n\n worldApi = new WorldApi(this.options);\n this._auth = new AuthManager();\n var _this = this;\n\n var api = {\n\n /**\n * Returns the current world (object) and an instance of the [World API Adapter](../world-api-adapter/).\n *\n * **Example**\n *\n * wMgr.getCurrentWorld()\n * .then(function(world, worldAdapter) {\n * console.log(world.id);\n * worldAdapter.getCurrentRunId();\n * });\n *\n * **Parameters**\n * @param {string} `userId` (Optional) The id of the user whose world is being accessed. Defaults to the user in the current session.\n * @param {string} `groupName` (Optional) The name of the group whose world is being accessed. Defaults to the group for the user in the current session.\n */\n getCurrentWorld: function (userId, groupName) {\n var session = this._auth.getCurrentUserSessionInfo();\n if (!userId) {\n userId = session.userId;\n }\n if (!groupName) {\n groupName = session.groupName;\n }\n return worldApi.getCurrentWorldForUser(userId, groupName);\n },\n\n /**\n * Returns the current run (object) and an instance of the [Run API Service](../run-api-service/).\n *\n * **Example**\n *\n * wMgr.getCurrentRun({model: 'myModel.py'})\n * .then(function(run, runService) {\n * console.log(run.id);\n * runService.do('startGame');\n * });\n *\n * **Parameters**\n * @param {string} `model` (Optional) The name of the model file. Required if not already passed in as `run.model` when the World Manager is created.\n */\n getCurrentRun: function (model) {\n var dtd = $.Deferred();\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n function getAndRestoreLatestRun(world) {\n if (!world) {\n return dtd.reject({ error: 'The user is not part of any world!' });\n }\n\n var currentWorldId = world.id;\n var runOpts = $.extend(true, _this.options, { model: model });\n var strategy = buildStrategy(currentWorldId, dtd);\n var opt = $.extend(true, {}, {\n strategy: strategy,\n run: runOpts\n });\n var rm = new RunManager(opt);\n\n return rm.getRun()\n .then(function (run) {\n dtd.resolve(run, rm.runService, rm);\n });\n }\n\n this.getCurrentWorld(curUserId, curGroupName)\n .then(getAndRestoreLatestRun);\n\n return dtd.promise();\n }\n };\n\n $.extend(this, api);\n};\n","'use strict';\n\n/**\n * ## Epicenter Channel Manager\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Epicenter Channel Manager is a wrapper around the (more generic) [Channel Manager](../channel-manager/), to instantiate it with Epicenter-specific defaults. If you are interested in including a notification or chat feature in your project, using an Epicenter Channel Manager is probably the easiest way to get started.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Epicenter Channel Manager. See [Including Epicenter.js](../../#include).\n *\n * To use the Epicenter Channel Manager: instantiate it, get the channel of the scope you want ([user](../../../glossary/#users), [world](../../../glossary/#world), or [group](../../../glossary/#groups)), then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.\n *\n * The parameters for instantiating an Epicenter Channel Manager include:\n *\n * * `options` Object with details about the Epicenter project for this Epicenter Channel Manager instance.\n * * `options.account` The Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `options.project` Epicenter project id.\n * * `options.userName` Epicenter userName used for authentication.\n * * `options.userId` Epicenter user id used for authentication. Optional; `options.userName` is preferred.\n * * `options.token` Epicenter token used for authentication. (You can retrieve this using `authManager.getToken()` from the [Authorization Manager](../auth-manager/).)\n * * `options.allowAllChannels` If not included or if set to `false`, all channel paths are validated; if your project requires [Push Channel Authorization](../../../updating_your_settings/), you should use this option. If you want to allow other channel paths, set to `true`; this is not common.\n */\n\nvar ChannelManager = require('./channel-manager');\nvar classFrom = require('../util/inherit');\nvar urlService = require('../service/url-config-service');\nvar SessionManager = require('../store/session-manager');\n\nvar AuthManager = require('./auth-manager');\n\nvar validTypes = {\n project: true,\n group: true,\n world: true,\n user: true,\n data: true,\n general: true,\n chat: true\n};\nvar session = new AuthManager();\nvar getFromSettingsOrSessionOrError = function (value, sessionKeyName, settings) {\n if (!value) {\n var userInfo = session.getCurrentUserSessionInfo();\n if (settings && settings[sessionKeyName]) {\n value = settings[sessionKeyName];\n } else if (userInfo[sessionKeyName]) {\n value = userInfo[sessionKeyName];\n } else {\n throw new Error(sessionKeyName + ' not found. Please log-in again, or specify ' + sessionKeyName + ' explicitly');\n }\n }\n return value;\n};\nvar __super = ChannelManager.prototype;\nvar EpicenterChannelManager = classFrom(ChannelManager, {\n constructor: function (options) {\n this.sessionManager = new SessionManager();\n var defaultCometOptions = this.sessionManager.getMergedOptions(options);\n\n var urlOpts = urlService(defaultCometOptions.server);\n if (!defaultCometOptions.url) {\n //Default epicenter cometd endpoint\n defaultCometOptions.url = urlOpts.protocol + '://' + urlOpts.host + '/channel/subscribe';\n }\n\n if (defaultCometOptions.handshake === undefined) {\n var userName = defaultCometOptions.userName;\n var userId = defaultCometOptions.userId;\n var token = defaultCometOptions.token;\n if ((userName || userId) && token) {\n var userProp = userName ? 'userName' : 'userId';\n var ext = {\n authorization: 'Bearer ' + token\n };\n ext[userProp] = userName ? userName : userId;\n\n defaultCometOptions.handshake = {\n ext: ext\n };\n }\n }\n\n this.options = defaultCometOptions;\n return __super.constructor.call(this, defaultCometOptions);\n },\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * This method enforces Epicenter-specific channel naming: all channels requested must be in the form `/{type}/{account id}/{project id}/{...}`, where `type` is one of `run`, `data`, `user`, `world`, or `chat`.\n *\n * **Example**\n *\n * var cm = new F.manager.EpicenterChannelManager();\n * var channel = cm.getChannel('/group/acme/supply-chain-game/');\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} `options` (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n */\n getChannel: function (options) {\n if (options && typeof options !== 'object') {\n options = {\n base: options\n };\n }\n var channelOpts = $.extend({}, this.options, options);\n var base = channelOpts.base;\n if (!base) {\n throw new Error('No base topic was provided');\n }\n\n if (!channelOpts.allowAllChannels) {\n var baseParts = base.split('/');\n var channelType = baseParts[1];\n if (baseParts.length < 4) {\n throw new Error('Invalid channel base name, it must be in the form /{type}/{account id}/{project id}/{...}');\n }\n if (!validTypes[channelType]) {\n throw new Error('Invalid channel type');\n }\n }\n return __super.getChannel.apply(this, arguments);\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [group](../../../glossary/#groups). The group must exist in the account (team) and project provided.\n *\n * There are no notifications from Epicenter on this channel; all messages are user-originated.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `groupName` (Optional) Group to broadcast to. If not provided, picks up group from current session if end user is logged in.\n */\n getGroupChannel: function (groupName) {\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/group', account, project, groupName].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var worldChannel = cm.getWorldChannel(worldObject);\n * worldChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` The world object or id.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getWorldChannel: function (world, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/world', account, project, groupName, worldid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the current [end user](../../../glossary/#users) in that user's current [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager). Note that this channel only gets notifications for worlds currently in memory. (See more background on [persistence](../../../run_persistence).)\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var userChannel = cm.getUserChannel(worldObject);\n * userChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `user` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getUserChannel: function (world, user, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n var userid = ($.isPlainObject(user) && user.id) ? user.id : user;\n userid = getFromSettingsOrSessionOrError(userid, 'userId', this.options);\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/user', account, project, groupName, worldid, userid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) that automatically tracks the presence of an [end user](../../../glossary/#users), that is, whether the end user is currently online in this group and world. Notifications are automatically sent when the end user comes online, and when the end user goes offline (not present for more than 2 minutes). Useful in multiplayer games for letting each end user know whether other users in their shared world are also online.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'model.eqn'\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldService) {\n * var presenceChannel = cm.getPresenceChannel(worldObject);\n * presenceChannel.on('presence', function (evt, notification) {\n * console.log(notification.online, notification.userId);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `userid` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getPresenceChannel: function (world, userid, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n userid = getFromSettingsOrSessionOrError(userid, 'userId', this.options);\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/user', account, project, groupName, worldid].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n var lastPingTime = { };\n\n var PING_INTERVAL = 6000;\n channel.subscribe('internal-ping-channel', function (notification) {\n var incomingUserId = notification.data.user;\n if (!lastPingTime[incomingUserId] && incomingUserId !== userid) {\n channel.trigger.call(channel, 'presence', { userId: incomingUserId, online: true });\n }\n lastPingTime[incomingUserId] = (new Date()).valueOf();\n });\n\n setInterval(function () {\n channel.publish('internal-ping-channel', { user: userid });\n\n $.each(lastPingTime, function (key, value) {\n var now = (new Date()).valueOf();\n if (value && value + (PING_INTERVAL * 2) < now) {\n lastPingTime[key] = null;\n channel.trigger.call(channel, 'presence', { userId: key, online: false });\n }\n });\n }, PING_INTERVAL);\n\n return channel;\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given collection. (The collection name is specified in the `root` argument when the [Data Service](../data-api-service/) is instantiated.) Must be one of the collections in this account (team) and project.\n *\n * There are automatic notifications from Epicenter on this channel when data is created, updated, or deleted in this collection. See more on [automatic messages to the data channel](../../../rest_apis/multiplayer/channel/#data-messages).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var dc = cm.getDataChannel('survey-responses');\n * dc.subscribe('', function(data, meta) {\n * console.log(data);\n *\n * // meta.date is time of change,\n * // meta.subType is the kind of change: new, update, or delete\n * // meta.path is the full path to the changed data\n * console.log(meta);\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `collection` Name of collection whose automatic notifications you want to receive.\n */\n getDataChannel: function (collection) {\n if (!collection) {\n throw new Error('Please specify a collection to listen on.');\n }\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n var baseTopic = ['/data', account, project, collection].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n //TODO: Fix after Epicenter bug is resolved\n var oldsubs = channel.subscribe;\n channel.subscribe = function (topic, callback, context, options) {\n var callbackWithCleanData = function (payload) {\n var meta = {\n path: payload.channel,\n subType: payload.data.subType,\n date: payload.data.date\n };\n var actualData = payload.data.data;\n if (actualData.data) { //Delete notifications are one data-level behind of course\n actualData = actualData.data;\n }\n\n callback.call(context, actualData, meta);\n };\n return oldsubs.call(channel, topic, callbackWithCleanData, context, options);\n };\n\n return channel;\n }\n});\n\nmodule.exports = EpicenterChannelManager;\n","'use strict';\n\n/**\n * ## Channel Service\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Service is a building block for this functionality. It creates a publish-subscribe object, allowing you to publish messages, subscribe to messages, or unsubscribe from messages for a given 'topic' on a `$.cometd` transport instance.\n *\n * Typically, you use the [Epicenter Channel Manager](../epicenter-channel-manager/) to create or retrieve channels, then use the Channel Service `subscribe()` and `publish()` methods to listen to or update data. (For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.)\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Service. See [Including Epicenter.js](../../#include).\n *\n * To use the Channel Service, instantiate it, then make calls to any of the methods you need.\n *\n * var cs = new F.service.Channel();\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * The parameters for instantiating a Channel Service include:\n *\n * * `options` The options object to configure the Channel Service.\n * * `options.base` The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * * `options.topicResolver` A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. Returns a String. By default, it just echoes the topic.\n * * `options.transport` The instance of `$.cometd` to hook onto. See http://docs.cometd.org/reference/javascript.html for additional background on cometd.\n */\nvar Channel = function (options) {\n var defaults = {\n\n /**\n * The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * @type {string}\n */\n base: '',\n\n /**\n * A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. By default, it just echoes the topic.\n *\n * **Parameters**\n *\n * * `topic` Topic to parse.\n *\n * **Return Value**\n *\n * * *String*: This function should return a string topic.\n *\n * @type {function}\n */\n topicResolver: function (topic) {\n return topic;\n },\n\n /**\n * The instance of `$.cometd` to hook onto.\n * @type {object}\n */\n transport: null\n };\n this.channelOptions = $.extend(true, {}, defaults, options);\n};\n\nvar makeName = function (channelName, topic) {\n //Replace trailing/double slashes\n var newName = (channelName ? (channelName + '/' + topic) : topic).replace(/\\/\\//g, '/').replace(/\\/$/,'');\n return newName;\n};\n\n\nChannel.prototype = $.extend(Channel.prototype, {\n\n // future functionality:\n // // Set the context for the callback\n // cs.subscribe('run', function () { this.innerHTML = 'Triggered'}, document.body);\n //\n // // Control the order of operations by setting the `priority`\n // cs.subscribe('run', cb, this, {priority: 9});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is 50\n // cs.subscribe('run/variables/price', cb, this, {priority: 30, value: 50});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is greater than 50\n // subscribe('run/variables/price', cb, this, {priority: 30, value: '>50'});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is even\n // subscribe('run/variables/price', cb, this, {priority: 30, value: function (val) {return val % 2 === 0}});\n\n\n /**\n * Subscribe to changes on a topic.\n *\n * The topic should include the full path of the account id (**Team ID** for team projects), project id, and group name. (In most cases, it is simpler to use the [Epicenter Channel Manager](../epicenter-channel-manager/) instead, in which case this is configured for you.)\n *\n * **Examples**\n *\n * var cb = function(val) { console.log(val.data); };\n *\n * // Subscribe to changes on a top-level 'run' topic\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run', cb);\n *\n * // Subscribe to changes on children of the 'run' topic. Note this will also be triggered for changes to run.x.y.z.\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/*', cb);\n *\n * // Subscribe to changes on both the top-level 'run' topic and its children\n * cs.subscribe(['/acme-simulations/supply-chain-game/fall-seminar/run',\n * '/acme-simulations/supply-chain-game/fall-seminar/run/*'], cb);\n *\n * // Subscribe to changes on a particular variable\n * subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/variables/price', cb);\n *\n *\n * **Return Value**\n *\n * * *String* Returns a token you can later use to unsubscribe.\n *\n * **Parameters**\n * @param {String|Array} `topic` List of topics to listen for changes on.\n * @param {Function} `callback` Callback function to execute. Callback is called with signature `(evt, payload, metadata)`.\n * @param {Object} `context` Context in which the `callback` is executed.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n * @param {Number} `options.priority` Used to control order of operations. Defaults to 0. Can be any +ve or -ve number.\n * @param {String|Number|Function} `options.value` The `callback` is only triggered if this condition matches. See examples for details.\n *\n */\n subscribe: function (topic, callback, context, options) {\n\n var topics = [].concat(topic);\n var me = this;\n var subscriptionIds = [];\n var opts = me.channelOptions;\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n subscriptionIds.push(opts.transport.subscribe(topic, callback));\n });\n });\n return (subscriptionIds[1] ? subscriptionIds : subscriptionIds[0]);\n },\n\n /**\n * Publish data to a topic.\n *\n * **Examples**\n *\n * // Send data to all subscribers of the 'run' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run', { completed: false });\n *\n * // Send data to all subscribers of the 'run/variables' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * **Parameters**\n *\n * @param {String} `topic` Topic to publish to.\n * @param {*} `data` Data to publish to topic.\n *\n */\n publish: function (topic, data) {\n var topics = [].concat(topic);\n var me = this;\n var returnObjs = [];\n var opts = me.channelOptions;\n\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n if (topic.charAt(topic.length - 1) === '*') {\n topic = topic.replace(/\\*+$/, '');\n console.warn('You can cannot publish to channels with wildcards. Publishing to ', topic, 'instead');\n }\n returnObjs.push(opts.transport.publish(topic, data));\n });\n });\n return (returnObjs[1] ? returnObjs : returnObjs[0]);\n },\n\n /**\n * Unsubscribe from changes to a topic.\n *\n * **Example**\n *\n * cs.unsubscribe('sampleToken');\n *\n * **Parameters**\n * @param {String} `token` The token for topic is returned when you initially subscribe. Pass it here to unsubscribe from that topic.\n */\n unsubscribe: function (token) {\n this.channelOptions.transport.unsubscribe(token);\n return token;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n\n});\n\nmodule.exports = Channel;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // always create a new run!\n return true;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar makeSeq = require('../../util/make-sequence');\nvar Base = require('./identity-strategy');\nvar SessionStore = require('../../store/store-factory');\nvar classFrom = require('../../util/inherit');\nvar UrlService = require('../../service/url-config-service');\nvar AuthManager = require('../auth-manager');\n\nvar sessionStore = new SessionStore({});\nvar urlService = new UrlService();\nvar keyNames = require('../key-names');\n\nvar defaults = {\n sessionKey: keyNames.STRATEGY_SESSION_KEY,\n path: ''\n};\n\nfunction setRunInSession(sessionKey, run, path) {\n if (!path) {\n if (!urlService.isLocalhost()) {\n path = '/' + [urlService.appPath, urlService.accountPath, urlService.projectPath].join('/');\n // make sure we don't get consecuteive '/' so we have a valid path for the session\n path = path.replace(/\\/{2,}/g,'/');\n } else {\n path = '';\n }\n }\n // set the seesionKey for the run\n sessionStore.set(sessionKey, JSON.stringify({ runId: run.id }), { root: path });\n}\n\n/**\n* Conditional Creation Strategy\n* This strategy will try to get the run stored in the cookie and\n* evaluate if needs to create a new run by calling the 'condition' function\n*/\n\n/* jshint eqnull: true */\nvar Strategy = classFrom(Base, {\n constructor: function Strategy(runService, condition, options) {\n\n if (condition == null) {\n throw new Error('Conditional strategy needs a condition to createte a run');\n }\n\n this._auth = new AuthManager();\n this.run = makeSeq(runService);\n this.condition = typeof condition !== 'function' ? function () { return condition; } : condition;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n },\n\n runOptionsWithScope: function () {\n var userSession = this._auth.getCurrentUserSessionInfo();\n return $.extend({\n scope: { group: userSession.groupName }\n }, this.runOptions);\n },\n\n reset: function (runServiceOptions) {\n var _this = this;\n var opt = this.runOptionsWithScope();\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run, _this.options.path);\n run.freshlyCreated = true;\n return run;\n })\n .start();\n },\n\n getRun: function () {\n var runSession = JSON.parse(sessionStore.get(this.options.sessionKey));\n\n if (runSession && runSession.runId) {\n return this._loadAndCheck(runSession);\n } else {\n return this.reset();\n }\n },\n\n _loadAndCheck: function (runSession) {\n var shouldCreate = false;\n var _this = this;\n\n return this.run\n .load(runSession.runId, null, {\n success: function (run, msg, headers) {\n shouldCreate = _this.condition.call(_this, run, headers);\n }\n })\n .then(function (run) {\n if (shouldCreate) {\n var opt = _this.runOptionsWithScope();\n // we need to do this, on the original runService (ie not sequencialized)\n // so we don't get in the middle of the queue\n return _this.run.original.create(opt)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run);\n run.freshlyCreated = true;\n return run;\n });\n }\n\n return run;\n })\n .start();\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar Base = {};\n\n// Interface that all strategies need to implement\nmodule.exports = classFrom(Base, {\n constructor: function (runService, options) {\n this.runService = runService;\n },\n\n reset: function () {\n // return a newly created run\n return $.Deferred().resolve().promise();\n },\n\n getRun: function () {\n // return a usable run\n return $.Deferred().resolve(this.runService).promise();\n }\n});\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\n/*\n* create a new run only if nothing is stored in the cookie\n* this is useful for baseRuns.\n*/\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // if we are here, it means that the run exists... so we don't need a new one\n return false;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent';\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent' || run.initialized;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nmodule.exports = {\n _pick: function (obj, props) {\n var res = {};\n for (var p in obj) {\n if (props.indexOf(p) !== -1) {\n res[p] = obj[p];\n }\n }\n\n return res;\n }\n};\n","/**\n *\n * ## Introspection API Service\n *\n * Used in conjunction with the [Run API Service](../run-api-service/) to access Native DMS 3 Introspection calls\n *\n * var rm = new F.manager.RunManager({\n * run: {\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'supply-chain-model.jl'\n * }\n * });\n * rm.getRun()\n * .then(function() {\n * var is = rm.run.introspection();\n * });\n *\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var defaults = {\n server: {\n versionPath: 'v3/'\n }\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n urlConfig.filter = ';';\n\n var httpOptions = {\n url: urlConfig.getAPIPath('model') + 'publish'\n };\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAPI = {\n /**\n * Get the available Functions and Variables\n *\n * **Example**\n *\n * vs.get()\n * .then(function(data) {\n * // data contains an object with available functions (used with operations API) and available variables (used with variables API)\n * console.log(data.functions);\n * console.log(data.variables);\n * });\n *\n * **Parameters**\n * @param {String} `runId` (Optional) Overrides the run id used when the service was created\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n get: function (runId, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n var params = {\n runId: runId || httpOptions.filter,\n commandWrapper: { command: { introspect: {} } },\n reanimate: false\n };\n return http.post(params, httpOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","'use strict';\n\nvar keyNames = require('../managers/key-names');\nvar StorageFactory = require('./store-factory');\nvar optionUtils = require('../util/option-utils');\n\nvar EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY;\nvar defaults = {\n /**\n * Where to store user access tokens for temporary access. Defaults to storing in a cookie in the browser.\n * @type {string}\n */\n store: { synchronous: true }\n};\n\nvar SessionManager = function (managerOptions) {\n managerOptions = managerOptions || {};\n function getBaseOptions(overrides) {\n overrides = overrides || {};\n var libOptions = optionUtils.getOptions();\n var finalOptions = $.extend(true, {}, defaults, libOptions, managerOptions, overrides);\n return finalOptions;\n }\n\n function getStore(overrides) {\n var baseOptions = getBaseOptions(overrides);\n var storeOpts = baseOptions.store || {};\n if (storeOpts.root === undefined && baseOptions.account && baseOptions.project && !baseOptions.isLocal) {\n storeOpts.root = '/app/' + baseOptions.account + '/' + baseOptions.project;\n }\n return new StorageFactory(storeOpts);\n }\n\n var publicAPI = {\n saveSession: function (userInfo, options) {\n var serialized = JSON.stringify(userInfo);\n getStore(options).set(EPI_SESSION_KEY, serialized);\n },\n getSession: function (options) {\n // var session = getStore(options).get(EPI_SESSION_KEY) || '{}';\n // return JSON.parse(session);\n var store = getStore(options);\n var finalOpts = store.serviceOptions;\n var serialized = store.get(EPI_SESSION_KEY) || '{}';\n var session = JSON.parse(serialized);\n // If the url contains the project and account\n // validate the account and project in the session\n // and override project, groupName, groupId and isFac\n // Otherwise (i.e. localhost) use the saved session values\n var account = finalOpts.account;\n var project = finalOpts.project;\n if (account && session.account !== account) {\n // This means that the token was not used to login to the same account\n return {};\n }\n if (session.groups && account && project) {\n var group = session.groups[project] || { groupId: '', groupName: '', isFac: false };\n $.extend(session, { project: project }, group);\n }\n return session;\n },\n removeSession: function (options) {\n return getStore(options).remove(EPI_SESSION_KEY);\n },\n getStore: function (options) {\n return getStore(options);\n },\n\n getMergedOptions: function () {\n var args = Array.prototype.slice.call(arguments);\n var overrides = $.extend.apply($, [true, {}].concat(args));\n var baseOptions = getBaseOptions(overrides);\n var session = this.getSession(overrides);\n\n var sessionDefaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n //jshint camelcase: false\n //jscs:disable\n token: session.auth_token,\n /**\n * The group name. If left undefined, taken from the cookie session.\n * @type {String}\n */\n group: session.groupName,\n /**\n * The group id. If left undefined, taken from the cookie session.\n * @type {String}\n */\n groupId: session.groupId,\n userId: session.userId\n };\n return $.extend(true, sessionDefaults, baseOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n\nmodule.exports = SessionManager;","'use strict';\n\n\nmodule.exports = {\n reset: function (params, options, manager) {\n return manager.reset(options);\n }\n};\n","module.exports = {\n 'new-if-initialized': require('./new-if-initialized-strategy'),\n 'new-if-persisted': require('./new-if-persisted-strategy'),\n 'new-if-missing': require('./new-if-missing-strategy'),\n 'always-new': require('./always-new-strategy'),\n 'multiplayer': require('./multiplayer-strategy'),\n 'persistent-single-player': require('./persistent-single-player-strategy'),\n 'none': require('./identity-strategy')\n};\n","/*!\n * The buffer module from node.js, for the browser.\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\n/* eslint-disable no-proto */\n\n'use strict'\n\nvar base64 = require('base64-js')\nvar ieee754 = require('ieee754')\nvar isArray = require('isarray')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n * === true Use Uint8Array implementation (fastest)\n * === false Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n * incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n ? global.TYPED_ARRAY_SUPPORT\n : typedArraySupport()\n\n/*\n * Export kMaxLength after typed array support is determined.\n */\nexports.kMaxLength = kMaxLength()\n\nfunction typedArraySupport () {\n try {\n var arr = new Uint8Array(1)\n arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}\n return arr.foo() === 42 && // typed array instances can be augmented\n typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n } catch (e) {\n return false\n }\n}\n\nfunction kMaxLength () {\n return Buffer.TYPED_ARRAY_SUPPORT\n ? 0x7fffffff\n : 0x3fffffff\n}\n\nfunction createBuffer (that, length) {\n if (kMaxLength() < length) {\n throw new RangeError('Invalid typed array length')\n }\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = new Uint8Array(length)\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n if (that === null) {\n that = new Buffer(length)\n }\n that.length = length\n }\n\n return that\n}\n\n/**\n * The Buffer constructor returns instances of `Uint8Array` that have their\n * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of\n * `Uint8Array`, so the returned instances will have all the node `Buffer` methods\n * and the `Uint8Array` methods. Square bracket notation works as expected -- it\n * returns a single octet.\n *\n * The `Uint8Array` prototype remains unmodified.\n */\n\nfunction Buffer (arg, encodingOrOffset, length) {\n if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {\n return new Buffer(arg, encodingOrOffset, length)\n }\n\n // Common case.\n if (typeof arg === 'number') {\n if (typeof encodingOrOffset === 'string') {\n throw new Error(\n 'If encoding is specified then the first argument must be a string'\n )\n }\n return allocUnsafe(this, arg)\n }\n return from(this, arg, encodingOrOffset, length)\n}\n\nBuffer.poolSize = 8192 // not used by this implementation\n\n// TODO: Legacy, not needed anymore. Remove in next major version.\nBuffer._augment = function (arr) {\n arr.__proto__ = Buffer.prototype\n return arr\n}\n\nfunction from (that, value, encodingOrOffset, length) {\n if (typeof value === 'number') {\n throw new TypeError('\"value\" argument must not be a number')\n }\n\n if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {\n return fromArrayBuffer(that, value, encodingOrOffset, length)\n }\n\n if (typeof value === 'string') {\n return fromString(that, value, encodingOrOffset)\n }\n\n return fromObject(that, value)\n}\n\n/**\n * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError\n * if value is a number.\n * Buffer.from(str[, encoding])\n * Buffer.from(array)\n * Buffer.from(buffer)\n * Buffer.from(arrayBuffer[, byteOffset[, length]])\n **/\nBuffer.from = function (value, encodingOrOffset, length) {\n return from(null, value, encodingOrOffset, length)\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n Buffer.prototype.__proto__ = Uint8Array.prototype\n Buffer.__proto__ = Uint8Array\n if (typeof Symbol !== 'undefined' && Symbol.species &&\n Buffer[Symbol.species] === Buffer) {\n // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97\n Object.defineProperty(Buffer, Symbol.species, {\n value: null,\n configurable: true\n })\n }\n}\n\nfunction assertSize (size) {\n if (typeof size !== 'number') {\n throw new TypeError('\"size\" argument must be a number')\n }\n}\n\nfunction alloc (that, size, fill, encoding) {\n assertSize(size)\n if (size <= 0) {\n return createBuffer(that, size)\n }\n if (fill !== undefined) {\n // Only pay attention to encoding if it's a string. This\n // prevents accidentally sending in a number that would\n // be interpretted as a start offset.\n return typeof encoding === 'string'\n ? createBuffer(that, size).fill(fill, encoding)\n : createBuffer(that, size).fill(fill)\n }\n return createBuffer(that, size)\n}\n\n/**\n * Creates a new filled Buffer instance.\n * alloc(size[, fill[, encoding]])\n **/\nBuffer.alloc = function (size, fill, encoding) {\n return alloc(null, size, fill, encoding)\n}\n\nfunction allocUnsafe (that, size) {\n assertSize(size)\n that = createBuffer(that, size < 0 ? 0 : checked(size) | 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) {\n for (var i = 0; i < size; ++i) {\n that[i] = 0\n }\n }\n return that\n}\n\n/**\n * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.\n * */\nBuffer.allocUnsafe = function (size) {\n return allocUnsafe(null, size)\n}\n/**\n * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.\n */\nBuffer.allocUnsafeSlow = function (size) {\n return allocUnsafe(null, size)\n}\n\nfunction fromString (that, string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') {\n encoding = 'utf8'\n }\n\n if (!Buffer.isEncoding(encoding)) {\n throw new TypeError('\"encoding\" must be a valid string encoding')\n }\n\n var length = byteLength(string, encoding) | 0\n that = createBuffer(that, length)\n\n that.write(string, encoding)\n return that\n}\n\nfunction fromArrayLike (that, array) {\n var length = checked(array.length) | 0\n that = createBuffer(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nfunction fromArrayBuffer (that, array, byteOffset, length) {\n array.byteLength // this throws if `array` is not a valid ArrayBuffer\n\n if (byteOffset < 0 || array.byteLength < byteOffset) {\n throw new RangeError('\\'offset\\' is out of bounds')\n }\n\n if (array.byteLength < byteOffset + (length || 0)) {\n throw new RangeError('\\'length\\' is out of bounds')\n }\n\n if (length === undefined) {\n array = new Uint8Array(array, byteOffset)\n } else {\n array = new Uint8Array(array, byteOffset, length)\n }\n\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = array\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n that = fromArrayLike(that, array)\n }\n return that\n}\n\nfunction fromObject (that, obj) {\n if (Buffer.isBuffer(obj)) {\n var len = checked(obj.length) | 0\n that = createBuffer(that, len)\n\n if (that.length === 0) {\n return that\n }\n\n obj.copy(that, 0, 0, len)\n return that\n }\n\n if (obj) {\n if ((typeof ArrayBuffer !== 'undefined' &&\n obj.buffer instanceof ArrayBuffer) || 'length' in obj) {\n if (typeof obj.length !== 'number' || isnan(obj.length)) {\n return createBuffer(that, 0)\n }\n return fromArrayLike(that, obj)\n }\n\n if (obj.type === 'Buffer' && isArray(obj.data)) {\n return fromArrayLike(that, obj.data)\n }\n }\n\n throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')\n}\n\nfunction checked (length) {\n // Note: cannot use `length < kMaxLength` here because that fails when\n // length is NaN (which is otherwise coerced to zero.)\n if (length >= kMaxLength()) {\n throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n 'size: 0x' + kMaxLength().toString(16) + ' bytes')\n }\n return length | 0\n}\n\nfunction SlowBuffer (length) {\n if (+length != length) { // eslint-disable-line eqeqeq\n length = 0\n }\n return Buffer.alloc(+length)\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n throw new TypeError('Arguments must be Buffers')\n }\n\n if (a === b) return 0\n\n var x = a.length\n var y = b.length\n\n for (var i = 0, len = Math.min(x, y); i < len; ++i) {\n if (a[i] !== b[i]) {\n x = a[i]\n y = b[i]\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n switch (String(encoding).toLowerCase()) {\n case 'hex':\n case 'utf8':\n case 'utf-8':\n case 'ascii':\n case 'binary':\n case 'base64':\n case 'raw':\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return true\n default:\n return false\n }\n}\n\nBuffer.concat = function concat (list, length) {\n if (!isArray(list)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n\n if (list.length === 0) {\n return Buffer.alloc(0)\n }\n\n var i\n if (length === undefined) {\n length = 0\n for (i = 0; i < list.length; ++i) {\n length += list[i].length\n }\n }\n\n var buffer = Buffer.allocUnsafe(length)\n var pos = 0\n for (i = 0; i < list.length; ++i) {\n var buf = list[i]\n if (!Buffer.isBuffer(buf)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n buf.copy(buffer, pos)\n pos += buf.length\n }\n return buffer\n}\n\nfunction byteLength (string, encoding) {\n if (Buffer.isBuffer(string)) {\n return string.length\n }\n if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&\n (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {\n return string.byteLength\n }\n if (typeof string !== 'string') {\n string = '' + string\n }\n\n var len = string.length\n if (len === 0) return 0\n\n // Use a for loop to avoid recursion\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'ascii':\n case 'binary':\n case 'raw':\n case 'raws':\n return len\n case 'utf8':\n case 'utf-8':\n case undefined:\n return utf8ToBytes(string).length\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return len * 2\n case 'hex':\n return len >>> 1\n case 'base64':\n return base64ToBytes(string).length\n default:\n if (loweredCase) return utf8ToBytes(string).length // assume utf8\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\nBuffer.byteLength = byteLength\n\nfunction slowToString (encoding, start, end) {\n var loweredCase = false\n\n // No need to verify that \"this.length <= MAX_UINT32\" since it's a read-only\n // property of a typed array.\n\n // This behaves neither like String nor Uint8Array in that we set start/end\n // to their upper/lower bounds if the value passed is out of range.\n // undefined is handled specially as per ECMA-262 6th Edition,\n // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.\n if (start === undefined || start < 0) {\n start = 0\n }\n // Return early if start > this.length. Done here to prevent potential uint32\n // coercion fail below.\n if (start > this.length) {\n return ''\n }\n\n if (end === undefined || end > this.length) {\n end = this.length\n }\n\n if (end <= 0) {\n return ''\n }\n\n // Force coersion to uint32. This will also coerce falsey/NaN values to 0.\n end >>>= 0\n start >>>= 0\n\n if (end <= start) {\n return ''\n }\n\n if (!encoding) encoding = 'utf8'\n\n while (true) {\n switch (encoding) {\n case 'hex':\n return hexSlice(this, start, end)\n\n case 'utf8':\n case 'utf-8':\n return utf8Slice(this, start, end)\n\n case 'ascii':\n return asciiSlice(this, start, end)\n\n case 'binary':\n return binarySlice(this, start, end)\n\n case 'base64':\n return base64Slice(this, start, end)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return utf16leSlice(this, start, end)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = (encoding + '').toLowerCase()\n loweredCase = true\n }\n }\n}\n\n// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect\n// Buffer instances.\nBuffer.prototype._isBuffer = true\n\nfunction swap (b, n, m) {\n var i = b[n]\n b[n] = b[m]\n b[m] = i\n}\n\nBuffer.prototype.swap16 = function swap16 () {\n var len = this.length\n if (len % 2 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 16-bits')\n }\n for (var i = 0; i < len; i += 2) {\n swap(this, i, i + 1)\n }\n return this\n}\n\nBuffer.prototype.swap32 = function swap32 () {\n var len = this.length\n if (len % 4 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 32-bits')\n }\n for (var i = 0; i < len; i += 4) {\n swap(this, i, i + 3)\n swap(this, i + 1, i + 2)\n }\n return this\n}\n\nBuffer.prototype.toString = function toString () {\n var length = this.length | 0\n if (length === 0) return ''\n if (arguments.length === 0) return utf8Slice(this, 0, length)\n return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.equals = function equals (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return true\n return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n var str = ''\n var max = exports.INSPECT_MAX_BYTES\n if (this.length > 0) {\n str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n if (this.length > max) str += ' ... '\n }\n return ''\n}\n\nBuffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {\n if (!Buffer.isBuffer(target)) {\n throw new TypeError('Argument must be a Buffer')\n }\n\n if (start === undefined) {\n start = 0\n }\n if (end === undefined) {\n end = target ? target.length : 0\n }\n if (thisStart === undefined) {\n thisStart = 0\n }\n if (thisEnd === undefined) {\n thisEnd = this.length\n }\n\n if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {\n throw new RangeError('out of range index')\n }\n\n if (thisStart >= thisEnd && start >= end) {\n return 0\n }\n if (thisStart >= thisEnd) {\n return -1\n }\n if (start >= end) {\n return 1\n }\n\n start >>>= 0\n end >>>= 0\n thisStart >>>= 0\n thisEnd >>>= 0\n\n if (this === target) return 0\n\n var x = thisEnd - thisStart\n var y = end - start\n var len = Math.min(x, y)\n\n var thisCopy = this.slice(thisStart, thisEnd)\n var targetCopy = target.slice(start, end)\n\n for (var i = 0; i < len; ++i) {\n if (thisCopy[i] !== targetCopy[i]) {\n x = thisCopy[i]\n y = targetCopy[i]\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nfunction arrayIndexOf (arr, val, byteOffset, encoding) {\n var indexSize = 1\n var arrLength = arr.length\n var valLength = val.length\n\n if (encoding !== undefined) {\n encoding = String(encoding).toLowerCase()\n if (encoding === 'ucs2' || encoding === 'ucs-2' ||\n encoding === 'utf16le' || encoding === 'utf-16le') {\n if (arr.length < 2 || val.length < 2) {\n return -1\n }\n indexSize = 2\n arrLength /= 2\n valLength /= 2\n byteOffset /= 2\n }\n }\n\n function read (buf, i) {\n if (indexSize === 1) {\n return buf[i]\n } else {\n return buf.readUInt16BE(i * indexSize)\n }\n }\n\n var foundIndex = -1\n for (var i = byteOffset; i < arrLength; ++i) {\n if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {\n if (foundIndex === -1) foundIndex = i\n if (i - foundIndex + 1 === valLength) return foundIndex * indexSize\n } else {\n if (foundIndex !== -1) i -= i - foundIndex\n foundIndex = -1\n }\n }\n\n return -1\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {\n if (typeof byteOffset === 'string') {\n encoding = byteOffset\n byteOffset = 0\n } else if (byteOffset > 0x7fffffff) {\n byteOffset = 0x7fffffff\n } else if (byteOffset < -0x80000000) {\n byteOffset = -0x80000000\n }\n byteOffset >>= 0\n\n if (this.length === 0) return -1\n if (byteOffset >= this.length) return -1\n\n // Negative offsets start from the end of the buffer\n if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)\n\n if (typeof val === 'string') {\n val = Buffer.from(val, encoding)\n }\n\n if (Buffer.isBuffer(val)) {\n // special case: looking for empty string/buffer always fails\n if (val.length === 0) {\n return -1\n }\n return arrayIndexOf(this, val, byteOffset, encoding)\n }\n if (typeof val === 'number') {\n if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {\n return Uint8Array.prototype.indexOf.call(this, val, byteOffset)\n }\n return arrayIndexOf(this, [ val ], byteOffset, encoding)\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\nBuffer.prototype.includes = function includes (val, byteOffset, encoding) {\n return this.indexOf(val, byteOffset, encoding) !== -1\n}\n\nfunction hexWrite (buf, string, offset, length) {\n offset = Number(offset) || 0\n var remaining = buf.length - offset\n if (!length) {\n length = remaining\n } else {\n length = Number(length)\n if (length > remaining) {\n length = remaining\n }\n }\n\n // must be an even number of digits\n var strLen = string.length\n if (strLen % 2 !== 0) throw new Error('Invalid hex string')\n\n if (length > strLen / 2) {\n length = strLen / 2\n }\n for (var i = 0; i < length; ++i) {\n var parsed = parseInt(string.substr(i * 2, 2), 16)\n if (isNaN(parsed)) return i\n buf[offset + i] = parsed\n }\n return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction binaryWrite (buf, string, offset, length) {\n return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n // Buffer#write(string)\n if (offset === undefined) {\n encoding = 'utf8'\n length = this.length\n offset = 0\n // Buffer#write(string, encoding)\n } else if (length === undefined && typeof offset === 'string') {\n encoding = offset\n length = this.length\n offset = 0\n // Buffer#write(string, offset[, length][, encoding])\n } else if (isFinite(offset)) {\n offset = offset | 0\n if (isFinite(length)) {\n length = length | 0\n if (encoding === undefined) encoding = 'utf8'\n } else {\n encoding = length\n length = undefined\n }\n // legacy write(string, encoding, offset, length) - remove in v0.13\n } else {\n throw new Error(\n 'Buffer.write(string, encoding, offset[, length]) is no longer supported'\n )\n }\n\n var remaining = this.length - offset\n if (length === undefined || length > remaining) length = remaining\n\n if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n throw new RangeError('Attempt to write outside buffer bounds')\n }\n\n if (!encoding) encoding = 'utf8'\n\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'hex':\n return hexWrite(this, string, offset, length)\n\n case 'utf8':\n case 'utf-8':\n return utf8Write(this, string, offset, length)\n\n case 'ascii':\n return asciiWrite(this, string, offset, length)\n\n case 'binary':\n return binaryWrite(this, string, offset, length)\n\n case 'base64':\n // Warning: maxLength not taken into account in base64Write\n return base64Write(this, string, offset, length)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return ucs2Write(this, string, offset, length)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n return {\n type: 'Buffer',\n data: Array.prototype.slice.call(this._arr || this, 0)\n }\n}\n\nfunction base64Slice (buf, start, end) {\n if (start === 0 && end === buf.length) {\n return base64.fromByteArray(buf)\n } else {\n return base64.fromByteArray(buf.slice(start, end))\n }\n}\n\nfunction utf8Slice (buf, start, end) {\n end = Math.min(buf.length, end)\n var res = []\n\n var i = start\n while (i < end) {\n var firstByte = buf[i]\n var codePoint = null\n var bytesPerSequence = (firstByte > 0xEF) ? 4\n : (firstByte > 0xDF) ? 3\n : (firstByte > 0xBF) ? 2\n : 1\n\n if (i + bytesPerSequence <= end) {\n var secondByte, thirdByte, fourthByte, tempCodePoint\n\n switch (bytesPerSequence) {\n case 1:\n if (firstByte < 0x80) {\n codePoint = firstByte\n }\n break\n case 2:\n secondByte = buf[i + 1]\n if ((secondByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n if (tempCodePoint > 0x7F) {\n codePoint = tempCodePoint\n }\n }\n break\n case 3:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n codePoint = tempCodePoint\n }\n }\n break\n case 4:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n fourthByte = buf[i + 3]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n codePoint = tempCodePoint\n }\n }\n }\n }\n\n if (codePoint === null) {\n // we did not generate a valid codePoint so insert a\n // replacement char (U+FFFD) and advance only 1 byte\n codePoint = 0xFFFD\n bytesPerSequence = 1\n } else if (codePoint > 0xFFFF) {\n // encode to utf16 (surrogate pair dance)\n codePoint -= 0x10000\n res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n codePoint = 0xDC00 | codePoint & 0x3FF\n }\n\n res.push(codePoint)\n i += bytesPerSequence\n }\n\n return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n var len = codePoints.length\n if (len <= MAX_ARGUMENTS_LENGTH) {\n return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n }\n\n // Decode in chunks to avoid \"call stack size exceeded\".\n var res = ''\n var i = 0\n while (i < len) {\n res += String.fromCharCode.apply(\n String,\n codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n )\n }\n return res\n}\n\nfunction asciiSlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i] & 0x7F)\n }\n return ret\n}\n\nfunction binarySlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i])\n }\n return ret\n}\n\nfunction hexSlice (buf, start, end) {\n var len = buf.length\n\n if (!start || start < 0) start = 0\n if (!end || end < 0 || end > len) end = len\n\n var out = ''\n for (var i = start; i < end; ++i) {\n out += toHex(buf[i])\n }\n return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n var bytes = buf.slice(start, end)\n var res = ''\n for (var i = 0; i < bytes.length; i += 2) {\n res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n }\n return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n var len = this.length\n start = ~~start\n end = end === undefined ? len : ~~end\n\n if (start < 0) {\n start += len\n if (start < 0) start = 0\n } else if (start > len) {\n start = len\n }\n\n if (end < 0) {\n end += len\n if (end < 0) end = 0\n } else if (end > len) {\n end = len\n }\n\n if (end < start) end = start\n\n var newBuf\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n newBuf = this.subarray(start, end)\n newBuf.__proto__ = Buffer.prototype\n } else {\n var sliceLen = end - start\n newBuf = new Buffer(sliceLen, undefined)\n for (var i = 0; i < sliceLen; ++i) {\n newBuf[i] = this[i + start]\n }\n }\n\n return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n checkOffset(offset, byteLength, this.length)\n }\n\n var val = this[offset + --byteLength]\n var mul = 1\n while (byteLength > 0 && (mul *= 0x100)) {\n val += this[offset + --byteLength] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return ((this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16)) +\n (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] * 0x1000000) +\n ((this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n this[offset + 3])\n}\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var i = byteLength\n var mul = 1\n var val = this[offset + --i]\n while (i > 0 && (mul *= 0x100)) {\n val += this[offset + --i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n if (!(this[offset] & 0x80)) return (this[offset])\n return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset] | (this[offset + 1] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset + 1] | (this[offset] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16) |\n (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] << 24) |\n (this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n if (!Buffer.isBuffer(buf)) throw new TypeError('\"buffer\" argument must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('\"value\" argument is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n var maxBytes = Math.pow(2, 8 * byteLength) - 1\n checkInt(this, value, offset, byteLength, maxBytes, 0)\n }\n\n var mul = 1\n var i = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n var maxBytes = Math.pow(2, 8 * byteLength) - 1\n checkInt(this, value, offset, byteLength, maxBytes, 0)\n }\n\n var i = byteLength - 1\n var mul = 1\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {\n buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n (littleEndian ? i : 1 - i) * 8\n }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffffffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {\n buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset + 3] = (value >>> 24)\n this[offset + 2] = (value >>> 16)\n this[offset + 1] = (value >>> 8)\n this[offset] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = 0\n var mul = 1\n var sub = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {\n sub = 1\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = byteLength - 1\n var mul = 1\n var sub = 0\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {\n sub = 1\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n if (value < 0) value = 0xff + value + 1\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n this[offset + 2] = (value >>> 16)\n this[offset + 3] = (value >>> 24)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (value < 0) value = 0xffffffff + value + 1\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n if (offset < 0) throw new RangeError('Index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n }\n ieee754.write(buf, value, offset, littleEndian, 23, 4)\n return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n }\n ieee754.write(buf, value, offset, littleEndian, 52, 8)\n return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n if (!start) start = 0\n if (!end && end !== 0) end = this.length\n if (targetStart >= target.length) targetStart = target.length\n if (!targetStart) targetStart = 0\n if (end > 0 && end < start) end = start\n\n // Copy 0 bytes; we're done\n if (end === start) return 0\n if (target.length === 0 || this.length === 0) return 0\n\n // Fatal error conditions\n if (targetStart < 0) {\n throw new RangeError('targetStart out of bounds')\n }\n if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n // Are we oob?\n if (end > this.length) end = this.length\n if (target.length - targetStart < end - start) {\n end = target.length - targetStart + start\n }\n\n var len = end - start\n var i\n\n if (this === target && start < targetStart && targetStart < end) {\n // descending copy from end\n for (i = len - 1; i >= 0; --i) {\n target[i + targetStart] = this[i + start]\n }\n } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n // ascending copy from start\n for (i = 0; i < len; ++i) {\n target[i + targetStart] = this[i + start]\n }\n } else {\n Uint8Array.prototype.set.call(\n target,\n this.subarray(start, start + len),\n targetStart\n )\n }\n\n return len\n}\n\n// Usage:\n// buffer.fill(number[, offset[, end]])\n// buffer.fill(buffer[, offset[, end]])\n// buffer.fill(string[, offset[, end]][, encoding])\nBuffer.prototype.fill = function fill (val, start, end, encoding) {\n // Handle string cases:\n if (typeof val === 'string') {\n if (typeof start === 'string') {\n encoding = start\n start = 0\n end = this.length\n } else if (typeof end === 'string') {\n encoding = end\n end = this.length\n }\n if (val.length === 1) {\n var code = val.charCodeAt(0)\n if (code < 256) {\n val = code\n }\n }\n if (encoding !== undefined && typeof encoding !== 'string') {\n throw new TypeError('encoding must be a string')\n }\n if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {\n throw new TypeError('Unknown encoding: ' + encoding)\n }\n } else if (typeof val === 'number') {\n val = val & 255\n }\n\n // Invalid ranges are not set to a default, so can range check early.\n if (start < 0 || this.length < start || this.length < end) {\n throw new RangeError('Out of range index')\n }\n\n if (end <= start) {\n return this\n }\n\n start = start >>> 0\n end = end === undefined ? this.length : end >>> 0\n\n if (!val) val = 0\n\n var i\n if (typeof val === 'number') {\n for (i = start; i < end; ++i) {\n this[i] = val\n }\n } else {\n var bytes = Buffer.isBuffer(val)\n ? val\n : utf8ToBytes(new Buffer(val, encoding).toString())\n var len = bytes.length\n for (i = 0; i < end - start; ++i) {\n this[i + start] = bytes[i % len]\n }\n }\n\n return this\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n str = stringtrim(str).replace(INVALID_BASE64_RE, '')\n // Node converts strings with length < 2 to ''\n if (str.length < 2) return ''\n // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n while (str.length % 4 !== 0) {\n str = str + '='\n }\n return str\n}\n\nfunction stringtrim (str) {\n if (str.trim) return str.trim()\n return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n if (n < 16) return '0' + n.toString(16)\n return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n units = units || Infinity\n var codePoint\n var length = string.length\n var leadSurrogate = null\n var bytes = []\n\n for (var i = 0; i < length; ++i) {\n codePoint = string.charCodeAt(i)\n\n // is surrogate component\n if (codePoint > 0xD7FF && codePoint < 0xE000) {\n // last char was a lead\n if (!leadSurrogate) {\n // no lead yet\n if (codePoint > 0xDBFF) {\n // unexpected trail\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n } else if (i + 1 === length) {\n // unpaired lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n }\n\n // valid lead\n leadSurrogate = codePoint\n\n continue\n }\n\n // 2 leads in a row\n if (codePoint < 0xDC00) {\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n leadSurrogate = codePoint\n continue\n }\n\n // valid surrogate pair\n codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n } else if (leadSurrogate) {\n // valid bmp char, but last char was a lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n }\n\n leadSurrogate = null\n\n // encode utf8\n if (codePoint < 0x80) {\n if ((units -= 1) < 0) break\n bytes.push(codePoint)\n } else if (codePoint < 0x800) {\n if ((units -= 2) < 0) break\n bytes.push(\n codePoint >> 0x6 | 0xC0,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x10000) {\n if ((units -= 3) < 0) break\n bytes.push(\n codePoint >> 0xC | 0xE0,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x110000) {\n if ((units -= 4) < 0) break\n bytes.push(\n codePoint >> 0x12 | 0xF0,\n codePoint >> 0xC & 0x3F | 0x80,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else {\n throw new Error('Invalid code point')\n }\n }\n\n return bytes\n}\n\nfunction asciiToBytes (str) {\n var byteArray = []\n for (var i = 0; i < str.length; ++i) {\n // Node's code seems to be doing this and not & 0x7F..\n byteArray.push(str.charCodeAt(i) & 0xFF)\n }\n return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n var c, hi, lo\n var byteArray = []\n for (var i = 0; i < str.length; ++i) {\n if ((units -= 2) < 0) break\n\n c = str.charCodeAt(i)\n hi = c >> 8\n lo = c % 256\n byteArray.push(lo)\n byteArray.push(hi)\n }\n\n return byteArray\n}\n\nfunction base64ToBytes (str) {\n return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n for (var i = 0; i < length; ++i) {\n if ((i + offset >= dst.length) || (i >= src.length)) break\n dst[i + offset] = src[i]\n }\n return i\n}\n\nfunction isnan (val) {\n return val !== val // eslint-disable-line no-self-compare\n}\n","'use strict';\n\nvar Channel = require('../service/channel-service');\nvar SessionManager = require('../store/session-manager');\n\n/**\n * ## Channel Manager\n *\n * There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Manager is a wrapper around the default [cometd JavaScript library](http://docs.cometd.org/2/reference/javascript.html), `$.cometd`. It provides a few nice features that `$.cometd` doesn't, including:\n *\n * * Automatic re-subscription to channels if you lose your connection\n * * Online / Offline notifications\n * * 'Events' for cometd notifications (instead of having to listen on specific meta channels)\n *\n * While you can work directly with the Channel Manager through Node.js (for example, `require('manager/channel-manager')`) -- or even work directly with `$.cometd` and Epicenter's underlying [Push Channel API](../../../rest_apis/multiplayer/channel/) -- most often it will be easiest to work with the [Epicenter Channel Manager](../epicenter-channel-manager/). The Epicenter Channel Manager is a wrapper that instantiates a Channel Manager with Epicenter-specific defaults.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Manager. (See [Including Epicenter.js](../../#include).)\n *\n * To use the Channel Manager in client-side JavaScript, instantiate the [Epicenter Channel Manager](../epicenter-channel-manager/), get the channel, then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * The parameters for instantiating a Channel Manager include:\n *\n * * `options` The options object to configure the Channel Manager. Besides the common options listed here, see http://docs.cometd.org/reference/javascript.html for other supported options.\n * * `options.url` The Cometd endpoint URL.\n * * `options.websocketEnabled` Whether websocket support is active (boolean).\n * * `options.channel` Other defaults to pass on to instances of the underlying Channel Service. See [Channel Service](../channel-service/) for details.\n *\n */\nvar ChannelManager = function (options) {\n if (!$.cometd) {\n throw new Error('Cometd library not found. Please include epicenter-multiplayer-dependencies.js');\n }\n if (!options || !options.url) {\n throw new Error('Please provide an url for the cometd server');\n }\n\n var defaults = {\n /**\n * The Cometd endpoint URL.\n * @type {string}\n */\n url: '',\n\n /**\n * The log level for the channel (logs to console).\n * @type {string}\n */\n logLevel: 'info',\n\n /**\n * Whether websocket support is active. Defaults to `false`; Epicenter doesn't currently support communication through websockets.\n * @type {boolean}\n */\n websocketEnabled: false,\n\n /**\n * If false each instance of Channel will have a separate cometd connection to server, which could be noisy. Set to true to re-use the same connection across instances.\n * @type {boolean}\n */\n shareConnection: false,\n\n /**\n * Other defaults to pass on to instances of the underlying [Channel Service](../channel-service/), which are created through `getChannel()`.\n * @type {object}\n */\n channel: {\n\n },\n\n /**\n * Options to pass to the channel handshake.\n *\n * For example, the [Epicenter Channel Manager](../epicenter-channel-manager/) passes `ext` and authorization information. More information on possible options is in the details of the underlying [Push Channel API](../../../rest_apis/multiplayer/channel/).\n *\n * @type {object}\n */\n handshake: undefined\n };\n this.sessionManager = new SessionManager();\n var defaultCometOptions = this.sessionManager.getMergedOptions(defaults, options);\n this.currentSubscriptions = [];\n this.options = defaultCometOptions;\n\n if (defaultCometOptions.shareConnection && ChannelManager.prototype._cometd) {\n this.cometd = ChannelManager.prototype._cometd;\n return this;\n }\n var cometd = new $.Cometd();\n ChannelManager.prototype._cometd = cometd;\n\n cometd.websocketEnabled = defaultCometOptions.websocketEnabled;\n\n this.isConnected = false;\n var connectionBroken = function (message) {\n $(this).trigger('disconnect', message);\n };\n var connectionSucceeded = function (message) {\n $(this).trigger('connect', message);\n };\n var me = this;\n\n cometd.configure(defaultCometOptions);\n\n cometd.addListener('/meta/connect', function (message) {\n var wasConnected = this.isConnected;\n this.isConnected = (message.successful === true);\n if (!wasConnected && this.isConnected) { //Connecting for the first time\n connectionSucceeded.call(this, message);\n } else if (wasConnected && !this.isConnected) { //Only throw disconnected message fro the first disconnect, not once per try\n connectionBroken.call(this, message);\n }\n }.bind(this));\n\n cometd.addListener('/meta/disconnect', connectionBroken);\n\n cometd.addListener('/meta/handshake', function (message) {\n if (message.successful) {\n //http://docs.cometd.org/reference/javascript_subscribe.html#javascript_subscribe_meta_channels\n // ^ \"dynamic subscriptions are cleared (like any other subscription) and the application needs to figure out which dynamic subscription must be performed again\"\n cometd.batch(function () {\n $(me.currentSubscriptions).each(function (index, subs) {\n cometd.resubscribe(subs);\n });\n });\n }\n });\n\n //Other interesting events for reference\n cometd.addListener('/meta/subscribe', function (message) {\n $(me).trigger('subscribe', message);\n });\n cometd.addListener('/meta/unsubscribe', function (message) {\n $(me).trigger('unsubscribe', message);\n });\n cometd.addListener('/meta/publish', function (message) {\n $(me).trigger('publish', message);\n });\n cometd.addListener('/meta/unsuccessful', function (message) {\n $(me).trigger('error', message);\n });\n\n cometd.handshake(defaultCometOptions.handshake);\n\n this.cometd = cometd;\n};\n\n\nChannelManager.prototype = $.extend(ChannelManager.prototype, {\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} `options` (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n */\n getChannel: function (options) {\n //If you just want to pass in a string\n if (options && !$.isPlainObject(options)) {\n options = {\n base: options\n };\n }\n var defaults = {\n transport: this.cometd\n };\n var channel = new Channel($.extend(true, {}, this.options.channel, defaults, options));\n\n\n //Wrap subs and unsubs so we can use it to re-attach handlers after being disconnected\n var subs = channel.subscribe;\n channel.subscribe = function () {\n var subid = subs.apply(channel, arguments);\n this.currentSubscriptions = this.currentSubscriptions.concat(subid);\n return subid;\n }.bind(this);\n\n\n var unsubs = channel.unsubscribe;\n channel.unsubscribe = function () {\n var removed = unsubs.apply(channel, arguments);\n for (var i = 0; i < this.currentSubscriptions.length; i++) {\n if (this.currentSubscriptions[i].id === removed.id) {\n this.currentSubscriptions.splice(i, 1);\n }\n }\n return removed;\n }.bind(this);\n\n return channel;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n});\n\nmodule.exports = ChannelManager;\n","'use strict';\n\nmodule.exports = {\n EPI_SESSION_KEY: 'epicenterjs.session',\n STRATEGY_SESSION_KEY: 'epicenter-scenario'\n};","'use strict';\n\nvar ConfigService = require('../service/configuration-service');\n\nvar urlConfig = new ConfigService().get('server');\nvar customDefaults = {};\nvar libDefaults = {\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: urlConfig.accountPath,\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: urlConfig.projectPath,\n isLocal: urlConfig.isLocalhost(),\n store: {}\n};\n\nvar optionUtils = {\n /**\n * Gets the final options by overriding the global options set with\n * optionUtils#setDefaults() and the lib defaults.\n * @param {object} `options` The final options object.\n */\n getOptions: function (options) {\n return $.extend(true, {}, libDefaults, customDefaults, options);\n },\n /**\n * Sets the global defaults for the optionUtils#getOptions() method.\n * @param {object} `defaults` The defaults object.\n */\n setDefaults: function (defaults) {\n customDefaults = defaults;\n }\n};\nmodule.exports = optionUtils;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\n\nvar IdentityStrategy = require('./identity-strategy');\nvar WorldApiAdapter = require('../../service/world-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n\n constructor: function (runService, options) {\n this.runService = runService;\n this.options = $.extend(true, {}, defaults, options);\n this._auth = new AuthManager();\n this._loadRun = this._loadRun.bind(this);\n this.worldApi = new WorldApiAdapter(this.options.run);\n },\n\n reset: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n return this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(function (world) {\n return this.worldApi.newRunForWorld(world.id);\n }.bind(this));\n },\n\n getRun: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n var worldApi = this.worldApi;\n var model = this.options.model;\n var _this = this;\n var dtd = $.Deferred();\n\n if (!curUserId) {\n return dtd.reject({ statusCode: 400, error: 'We need an authenticated user to join a multiplayer world. (ERR: no userId in session)' }, session).promise();\n }\n\n var loadRunFromWorld = function (world) {\n if (!world) {\n return dtd.reject({ statusCode: 404, error: 'The user is not in any world.' }, { options: this.options, session: session });\n }\n\n return worldApi.getCurrentRunId({ model: model, filter: world.id })\n .then(_this._loadRun)\n .then(dtd.resolve)\n .fail(dtd.reject);\n };\n\n var serverError = function (error) {\n // is this possible?\n dtd.reject(error, session, this.options);\n };\n\n this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(loadRunFromWorld)\n .fail(serverError);\n\n return dtd.promise();\n },\n\n _loadRun: function (id, options) {\n return this.runService.load(id, null, options);\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar IdentityStrategy = require('./identity-strategy');\nvar StorageFactory = require('../../store/store-factory');\nvar StateApi = require('../../service/state-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar keyNames = require('../key-names');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n constructor: function Strategy(runService, options) {\n this.run = runService;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n this._store = new StorageFactory(this.options.store);\n this.stateApi = new StateApi();\n this._auth = new AuthManager();\n\n this._loadAndCheck = this._loadAndCheck.bind(this);\n this._restoreRun = this._restoreRun.bind(this);\n this._getAllRuns = this._getAllRuns.bind(this);\n this._loadRun = this._loadRun.bind(this);\n },\n\n reset: function (runServiceOptions) {\n var session = this._auth.getCurrentUserSessionInfo();\n var opt = $.extend({\n scope: { group: session.groupName }\n }, this.runOptions);\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n run.freshlyCreated = true;\n return run;\n });\n },\n\n getRun: function () {\n return this._getAllRuns()\n .then(this._loadAndCheck);\n },\n\n _getAllRuns: function () {\n var session = JSON.parse(this._store.get(keyNames.EPI_SESSION_KEY) || '{}');\n return this.run.query({\n 'user.id': session.userId || '0000',\n 'scope.group': session.groupName\n });\n },\n\n _loadAndCheck: function (runs) {\n if (!runs || !runs.length) {\n return this.reset();\n }\n\n var dateComp = function (a, b) { return new Date(b.date) - new Date(a.date); };\n var latestRun = runs.sort(dateComp)[0];\n var _this = this;\n var shouldReplay = false;\n\n return this.run.load(latestRun.id, null, {\n success: function (run, msg, headers) {\n shouldReplay = headers.getResponseHeader('pragma') === 'persistent';\n }\n }).then(function (run) {\n return shouldReplay ? _this._restoreRun(run.id) : run;\n });\n },\n\n _restoreRun: function (runId) {\n var _this = this;\n return this.stateApi.replay({ runId: runId })\n .then(function (resp) {\n return _this._loadRun(resp.run);\n });\n },\n\n _loadRun: function (id, options) {\n return this.run.load(id, null, options);\n }\n\n});\n\nmodule.exports = Strategy;\n","var toString = {}.toString;\n\nmodule.exports = Array.isArray || function (arr) {\n return toString.call(arr) == '[object Array]';\n};\n","exports.read = function (buffer, offset, isLE, mLen, nBytes) {\n var e, m\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var nBits = -7\n var i = isLE ? (nBytes - 1) : 0\n var d = isLE ? -1 : 1\n var s = buffer[offset + i]\n\n i += d\n\n e = s & ((1 << (-nBits)) - 1)\n s >>= (-nBits)\n nBits += eLen\n for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n m = e & ((1 << (-nBits)) - 1)\n e >>= (-nBits)\n nBits += mLen\n for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n if (e === 0) {\n e = 1 - eBias\n } else if (e === eMax) {\n return m ? NaN : ((s ? -1 : 1) * Infinity)\n } else {\n m = m + Math.pow(2, mLen)\n e = e - eBias\n }\n return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n var e, m, c\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)\n var i = isLE ? 0 : (nBytes - 1)\n var d = isLE ? 1 : -1\n var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0\n\n value = Math.abs(value)\n\n if (isNaN(value) || value === Infinity) {\n m = isNaN(value) ? 1 : 0\n e = eMax\n } else {\n e = Math.floor(Math.log(value) / Math.LN2)\n if (value * (c = Math.pow(2, -e)) < 1) {\n e--\n c *= 2\n }\n if (e + eBias >= 1) {\n value += rt / c\n } else {\n value += rt * Math.pow(2, 1 - eBias)\n }\n if (value * c >= 2) {\n e++\n c /= 2\n }\n\n if (e + eBias >= eMax) {\n m = 0\n e = eMax\n } else if (e + eBias >= 1) {\n m = (value * c - 1) * Math.pow(2, mLen)\n e = e + eBias\n } else {\n m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)\n e = 0\n }\n }\n\n for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n e = (e << mLen) | m\n eLen += mLen\n for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n buffer[offset + i - d] |= s * 128\n}\n","'use strict'\n\nexports.toByteArray = toByteArray\nexports.fromByteArray = fromByteArray\n\nvar lookup = []\nvar revLookup = []\nvar Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array\n\nfunction init () {\n var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\n for (var i = 0, len = code.length; i < len; ++i) {\n lookup[i] = code[i]\n revLookup[code.charCodeAt(i)] = i\n }\n\n revLookup['-'.charCodeAt(0)] = 62\n revLookup['_'.charCodeAt(0)] = 63\n}\n\ninit()\n\nfunction toByteArray (b64) {\n var i, j, l, tmp, placeHolders, arr\n var len = b64.length\n\n if (len % 4 > 0) {\n throw new Error('Invalid string. Length must be a multiple of 4')\n }\n\n // the number of equal signs (place holders)\n // if there are two placeholders, than the two characters before it\n // represent one byte\n // if there is only one, then the three characters before it represent 2 bytes\n // this is just a cheap hack to not do indexOf twice\n placeHolders = b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0\n\n // base64 is 4/3 + up to two characters of the original data\n arr = new Arr(len * 3 / 4 - placeHolders)\n\n // if there are placeholders, only get up to the last complete 4 chars\n l = placeHolders > 0 ? len - 4 : len\n\n var L = 0\n\n for (i = 0, j = 0; i < l; i += 4, j += 3) {\n tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]\n arr[L++] = (tmp >> 16) & 0xFF\n arr[L++] = (tmp >> 8) & 0xFF\n arr[L++] = tmp & 0xFF\n }\n\n if (placeHolders === 2) {\n tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)\n arr[L++] = tmp & 0xFF\n } else if (placeHolders === 1) {\n tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)\n arr[L++] = (tmp >> 8) & 0xFF\n arr[L++] = tmp & 0xFF\n }\n\n return arr\n}\n\nfunction tripletToBase64 (num) {\n return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]\n}\n\nfunction encodeChunk (uint8, start, end) {\n var tmp\n var output = []\n for (var i = start; i < end; i += 3) {\n tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])\n output.push(tripletToBase64(tmp))\n }\n return output.join('')\n}\n\nfunction fromByteArray (uint8) {\n var tmp\n var len = uint8.length\n var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes\n var output = ''\n var parts = []\n var maxChunkLength = 16383 // must be multiple of 3\n\n // go through the array every three bytes, we'll deal with trailing stuff later\n for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))\n }\n\n // pad the end with zeros, but make sure to not forget the extra bytes\n if (extraBytes === 1) {\n tmp = uint8[len - 1]\n output += lookup[tmp >> 2]\n output += lookup[(tmp << 4) & 0x3F]\n output += '=='\n } else if (extraBytes === 2) {\n tmp = (uint8[len - 2] << 8) + (uint8[len - 1])\n output += lookup[tmp >> 10]\n output += lookup[(tmp >> 4) & 0x3F]\n output += lookup[(tmp << 2) & 0x3F]\n output += '='\n }\n\n parts.push(output)\n\n return parts.join('')\n}\n"]} +>>>>>>> dms3-version diff --git a/package.json b/package.json index 7b724a94..1e340583 100644 --- a/package.json +++ b/package.json @@ -9,23 +9,24 @@ "devDependencies": { "browserify-istanbul": "^2.0.0", "growl": "^1.8.1", - "grunt": "^0.4.5", + "grunt": "^1.0.1", "grunt-browserify": "^5.0.0", - "grunt-bump": "0.0.15", + "grunt-bump": "^0.8.0", + "grunt-contrib-copy": "^1.0.0", "grunt-contrib-jshint": "1.0.0", - "grunt-contrib-uglify": "^0.7.0", - "grunt-contrib-watch": "^0.6.1", - "grunt-conventional-changelog": "^1.1.0", - "grunt-jscs": "^2.3.0", + "grunt-contrib-uglify": "^2.0.0", + "grunt-contrib-watch": "^1.0.0", + "grunt-conventional-changelog": "^6.1.0", + "grunt-jscs": "^3.0.1", "grunt-markdox": "^1.2.1", "grunt-mocha-phantom-istanbul": "^0.1.1", - "husky": "^0.10.2", - "istanbul": "^0.4.3", - "jshint-stylish": "2.2.0", - "minifyify": "^6.1.3", - "uglify-js": "^2.4.15", - "grunt-contrib-copy": "^0.8.0", - "grunt-template-module": "^0.5.0" + "grunt-template-module": "^0.5.0", + "husky": "^0.11.7", + "istanbul": "^0.4.5", + "jshint-stylish": "^2.2.1", + "minifyify": "^7.3.3", + "object-assign": "^4.1.0", + "uglify-js": "^2.7.3" }, "scripts": { "prepush": "grunt validate" diff --git a/readme.md b/readme.md index f666942d..c66a0dca 100644 --- a/readme.md +++ b/readme.md @@ -22,6 +22,48 @@ grunt test or grunt documentation ``` This will create an ```epicenter-edge.js``` file in ```dist/```. When you're happy with your changes do ```grunt production``` and make a pull-request to `master`. +## Development guide +Current code might not be aligned with the guide since is hard to do a library-wide refactor but we should be refactoring current code when is possible. + +### Options +Options are passed and merged in most of the "layers": +- Manager constructors and/or methods +- Service constructors and/or methods +- Transport layer (with the `transport` property) + +All Managers/Services constructors accept an options object but some methods do not allow override, it should be cleary documented when the method does not allow options override. + +Use the `SessionManager` to automatically get the merged session and library-wide options. + +### Services +Use `serviceUtils` for misc service utilities. Like generating the `serviceOptions` using the `SessionManager` and setting the `Authorization` header. Eventually all boilerplate code in the services should be removed in favor of using the `serviceUtils`. + +### Tools +New code should: +- Use `require('object-assign')` "ponyfill" and avoid deep object merges as is very slow +- When deep assign needed use: `deep-assign` +- Avoid using jQuery utils methods + +### Future +Eventually (maybe v2) we should try to: +- Add library-wide options that we plug into `SessionManager` (all services/managers are using it) +```javascript +F.init({ options: { account: 'acme', version: 'v2' }}); +``` +- Make the sync call in [configuration-service.js](src/service/configuration-service.js) async as default and add an option to make it sync (so it will be easier to older sims to update): +```javascript +F.init({ config: { syncFetch: true }, options: {...} }); +``` +- Remove `jQuery` as a global dependency and just require $.ajax (if possible) or replace with another node/browser library (may not be worth the effort $.ajax works fine) +- Use ES6 promises +- Be able to use ES6 imports +```javascript +import F, { RunManager } from 'epicenter-js'; +import { DataService } from 'epicenter-js'; +import { AuthManager } from 'epicenter-js'; +``` +- Try not to break documented service or manager methods + © Forio Corporation, 2014-2016. All rights reserved. diff --git a/src/app.js b/src/app.js index 12aa0bac..0b082ea1 100644 --- a/src/app.js +++ b/src/app.js @@ -20,7 +20,6 @@ F.load = require('./env-load'); F.load(); F.util.query = require('./util/query-util'); -F.util.makeSequence = require('./util/make-sequence'); F.util.run = require('./util/run-util'); F.util.classFrom = require('./util/inherit'); @@ -39,6 +38,7 @@ F.service.State = require('./service/state-api-adapter'); F.service.User = require('./service/user-api-adapter'); F.service.Member = require('./service/member-api-adapter'); F.service.Asset = require('./service/asset-api-adapter'); +F.service.Group = require('./service/group-api-service'); F.service.Introspect = require('./service/introspection-api-service'); F.store.Cookie = require('./store/cookie-store'); diff --git a/src/components/assignment/index.html b/src/components/assignment/index.html index 1ac536db..2d3ae940 100644 --- a/src/components/assignment/index.html +++ b/src/components/assignment/index.html @@ -8,7 +8,7 @@ - + diff --git a/src/components/assignment/js/assignment.js b/src/components/assignment/js/assignment.js index ce672176..b69c9189 100644 --- a/src/components/assignment/js/assignment.js +++ b/src/components/assignment/js/assignment.js @@ -70,7 +70,7 @@ Assignment.prototype = { this._showUpdating(); var maxUsers = +this.$('#max-users').val(); return this.worlds.autoAssignAll({ maxUsers: maxUsers }) - .done(this._hideUpdating) + .then(this._hideUpdating) .fail(this._hideUpdating) .then(function () { this.worlds.joinUsers(); diff --git a/src/components/assignment/js/users-collection.js b/src/components/assignment/js/users-collection.js index 67c2e7d6..078fe3a6 100644 --- a/src/components/assignment/js/users-collection.js +++ b/src/components/assignment/js/users-collection.js @@ -70,7 +70,7 @@ module.exports = classFrom(Base, { .then(function (users) { users = _.map(users, function (u) { return _.extend(u, { groupId: groupId }); }); _this.set(users); - dtd.resolve(users, _this); + dtd.resolve(users); }); return dtd.promise(); diff --git a/src/components/login/index.html b/src/components/login/index.html index 431e42e6..e80f30db 100644 --- a/src/components/login/index.html +++ b/src/components/login/index.html @@ -14,7 +14,7 @@ - + diff --git a/src/components/login/login.js b/src/components/login/login.js index 743bbf26..98cd82b0 100644 --- a/src/components/login/login.js +++ b/src/components/login/login.js @@ -92,8 +92,6 @@ $(function () { }) .then(function () { window.location = action; - }) - .done(function () { $('.group-selection-dialog').hide(); }); }); diff --git a/src/env-load.js b/src/env-load.js index 7f8b60ba..35cd968d 100644 --- a/src/env-load.js +++ b/src/env-load.js @@ -14,7 +14,7 @@ var envLoad = function (callback) { } var infoUrl = host + envPath; envPromise = $.ajax({ url: infoUrl, async: false }); - envPromise.done(function (res) { + envPromise.then(function (res) { var api = res.api; $.extend(urlConfigService, api); }).fail(function (res) { @@ -22,7 +22,7 @@ var envLoad = function (callback) { // fallback to api.forio.com $.extend(urlConfigService, { protocol: 'https', host: 'api.forio.com' }); }); - return envPromise.done(callback).fail(callback); + return envPromise.then(callback).fail(callback); }; module.exports = envLoad; diff --git a/src/managers/auth-manager.js b/src/managers/auth-manager.js index bbc72d01..aaa1ab56 100644 --- a/src/managers/auth-manager.js +++ b/src/managers/auth-manager.js @@ -33,9 +33,11 @@ 'use strict'; var AuthAdapter = require('../service/auth-api-service'); var MemberAdapter = require('../service/member-api-adapter'); +var GroupService = require('../service/group-api-service'); var SessionManager = require('../store/session-manager'); var Buffer = require('buffer').Buffer; var _pick = require('../util/object-util')._pick; +var objectAssign = require('object-assign'); var defaults = { requiresGroup: true @@ -153,19 +155,19 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { return; } - _this.getUserGroups({ userId: userInfo.user_id, token: token }, userGroupOpts).done(function (memberInfo) { - data.userGroups = memberInfo; + var handleGroupList = function (groupList) { + data.userGroups = groupList; var group = null; - if (memberInfo.length === 0) { + if (groupList.length === 0) { handleGroupError('The user has no groups associated in this account', 401, data); return; - } else if (memberInfo.length === 1) { + } else if (groupList.length === 1) { // Select the only group - group = memberInfo[0]; - } else if (memberInfo.length > 1) { + group = groupList[0]; + } else if (groupList.length > 1) { if (groupId) { - var filteredGroups = $.grep(memberInfo, function (resGroup) { + var filteredGroups = $.grep(groupList, function (resGroup) { return resGroup.groupId === groupId; }); group = filteredGroups.length === 1 ? filteredGroups[0] : null; @@ -173,12 +175,15 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { } if (group) { + // A team member does not get the group members because is calling the Group API + // but it's automatically a fac user + var isFac = isTeamMember ? true : _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator'; var groupData = { - 'groupId': group.groupId, - 'groupName': group.name, - 'isFac': _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator' + groupId: group.groupId, + groupName: group.name, + isFac: isFac }; - var sessionInfoWithGroup = $.extend({}, sessionInfo, groupData); + var sessionInfoWithGroup = objectAssign({}, sessionInfo, groupData); sessionInfo.groups[project] = groupData; _this.sessionManager.saveSession(sessionInfoWithGroup, adapterOptions); outSuccess.apply(this, [data]); @@ -186,7 +191,23 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { } else { handleGroupError('This user is associated with more than one group. Please specify a group id to log into and try again', 403, data); } - }).fail($d.reject); + }; + + if (!isTeamMember) { + _this.getUserGroups({ userId: userInfo.user_id, token: token }, userGroupOpts) + .then(handleGroupList, $d.reject); + } else { + var opts = objectAssign({}, userGroupOpts, { token: token }); + var groupService = new GroupService(opts); + groupService.getGroups({ account: adapterOptions.account, project: project }) + .then(function (groups) { + // Group API returns id instead of groupId + groups.forEach(function (group) { + group.groupId = group.id; + }); + handleGroupList(groups); + }, $d.reject); + } }; adapterOptions.success = handleSuccess; @@ -230,7 +251,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { _this.sessionManager.removeSession(); }; - return this.authAdapter.logout(adapterOptions).done(removeCookieFn); + return this.authAdapter.logout(adapterOptions).then(removeCookieFn); }, /** @@ -325,24 +346,23 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { return this.sessionManager.getSession(options); }, - // (replace with /* */ comment block, to make visible in docs, once EPICENTER-1939 is complete) - // - // Add one or more groups to the current session. - // - // This method assumes that the project and group exist and the user specified in the session is part of this project and group. - // - // Returns the new session object. - // - // **Example** - // - // authMgr.addGroups({ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' }); - // authMgr.addGroups([{ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' }, { project: ... }]); - // - // **Parameters** - // @param {object|array} `groups` (Required) The group object must contain the `project` (**Project ID**) and `groupName` properties. - // @param {string} `group.isFac` (optional) Defaults to `false`. Set to `true` if the user in the session should be a facilitator in this group. - // @param {string} `group.groupId` (optional) Defaults to undefined. Needed mostly for the Members API. - // + /* + * Adds one or more groups to the current session. + * + * This method assumes that the project and group exist and the user specified in the session is part of this project and group. + * + * Returns the new session object. + * + * **Example** + * + * authMgr.addGroups({ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' }); + * authMgr.addGroups([{ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' }, { project: 'hello-world', groupName: '...' }]); + * + * **Parameters** + * @param {object|array} `groups` (Required) The group object must contain the `project` (**Project ID**) and `groupName` properties. If passing an array of such objects, all of the objects must contain *different* `project` (**Project ID**) values: although end users may be logged in to multiple projects at once, they may only be logged in to one group per project at a time. + * @param {string} `group.isFac` (optional) Defaults to `false`. Set to `true` if the user in the session should be a facilitator in this group. + * @param {string} `group.groupId` (optional) Defaults to undefined. Needed mostly for the Members API. + */ addGroups: function (groups) { var session = this.getCurrentUserSessionInfo(); var isArray = Array.isArray(groups); diff --git a/src/managers/run-strategies/conditional-creation-strategy.js b/src/managers/run-strategies/conditional-creation-strategy.js index 3590154c..2ab88a1c 100644 --- a/src/managers/run-strategies/conditional-creation-strategy.js +++ b/src/managers/run-strategies/conditional-creation-strategy.js @@ -1,14 +1,10 @@ 'use strict'; -var makeSeq = require('../../util/make-sequence'); var Base = require('./identity-strategy'); -var SessionStore = require('../../store/store-factory'); +var SessionManager = require('../../store/session-manager'); var classFrom = require('../../util/inherit'); -var UrlService = require('../../service/url-config-service'); var AuthManager = require('../auth-manager'); -var sessionStore = new SessionStore({}); -var urlService = new UrlService(); var keyNames = require('../key-names'); var defaults = { @@ -16,18 +12,8 @@ var defaults = { path: '' }; -function setRunInSession(sessionKey, run, path) { - if (!path) { - if (!urlService.isLocalhost()) { - path = '/' + [urlService.appPath, urlService.accountPath, urlService.projectPath].join('/'); - // make sure we don't get consecuteive '/' so we have a valid path for the session - path = path.replace(/\/{2,}/g,'/'); - } else { - path = ''; - } - } - // set the seesionKey for the run - sessionStore.set(sessionKey, JSON.stringify({ runId: run.id }), { root: path }); +function setRunInSession(sessionKey, run, sessionManager) { + sessionManager.getStore().set(sessionKey, JSON.stringify({ runId: run.id })); } /** @@ -45,9 +31,10 @@ var Strategy = classFrom(Base, { } this._auth = new AuthManager(); - this.run = makeSeq(runService); + this.run = runService; this.condition = typeof condition !== 'function' ? function () { return condition; } : condition; this.options = $.extend(true, {}, defaults, options); + this.sessionManager = new SessionManager(options); this.runOptions = this.options.run; }, @@ -65,18 +52,20 @@ var Strategy = classFrom(Base, { return this.run .create(opt, runServiceOptions) .then(function (run) { - setRunInSession(_this.options.sessionKey, run, _this.options.path); + setRunInSession(_this.options.sessionKey, run, _this.sessionManager); run.freshlyCreated = true; return run; - }) - .start(); + }); }, getRun: function () { + var sessionStore = this.sessionManager.getStore(); var runSession = JSON.parse(sessionStore.get(this.options.sessionKey)); - + var me = this; if (runSession && runSession.runId) { - return this._loadAndCheck(runSession); + return this._loadAndCheck(runSession).fail(function () { + return me.reset(); //if it got the wrong cookie for e.g. + }); } else { return this.reset(); } @@ -95,19 +84,15 @@ var Strategy = classFrom(Base, { .then(function (run) { if (shouldCreate) { var opt = _this.runOptionsWithScope(); - // we need to do this, on the original runService (ie not sequencialized) - // so we don't get in the middle of the queue - return _this.run.original.create(opt) + return _this.run.create(opt) .then(function (run) { - setRunInSession(_this.options.sessionKey, run); + setRunInSession(_this.options.sessionKey, run, _this.sessionManager); run.freshlyCreated = true; return run; }); } - return run; - }) - .start(); + }); } }); diff --git a/src/managers/run-strategies/multiplayer-strategy.js b/src/managers/run-strategies/multiplayer-strategy.js index cb118a6c..9bd4afb1 100644 --- a/src/managers/run-strategies/multiplayer-strategy.js +++ b/src/managers/run-strategies/multiplayer-strategy.js @@ -49,7 +49,7 @@ var Strategy = classFrom(IdentityStrategy, { var loadRunFromWorld = function (world) { if (!world) { - return dtd.reject({ statusCode: 404, error: 'The user is not in any world.' }, { options: this.options, session: session }); + return dtd.reject({ statusCode: 404, error: 'The user is not in any world.' }, { options: _this.options, session: session }); } return worldApi.getCurrentRunId({ model: model, filter: world.id }) @@ -60,7 +60,7 @@ var Strategy = classFrom(IdentityStrategy, { var serverError = function (error) { // is this possible? - dtd.reject(error, session, this.options); + dtd.reject(error, session, _this.options); }; this.worldApi diff --git a/src/managers/world-manager.js b/src/managers/world-manager.js index 4ef9e7a3..7601cd02 100644 --- a/src/managers/world-manager.js +++ b/src/managers/world-manager.js @@ -70,7 +70,7 @@ function buildStrategy(worldId, dtd) { return _this.runService.load(runId); }) .then(function (run) { - dtd.resolve.call(this, run, _this.runService); + dtd.resolveWith(_this, [run]); }) .fail(dtd.reject); } diff --git a/src/service/asset-api-adapter.js b/src/service/asset-api-adapter.js index 4d552453..bf18d560 100644 --- a/src/service/asset-api-adapter.js +++ b/src/service/asset-api-adapter.js @@ -302,7 +302,7 @@ module.exports = function (config) { var fullPathFiles = $.map(files, function (file) { return buildUrl(file, urlOptions); }); - dtd.resolve(fullPathFiles, me); + dtd.resolveWith(me, [fullPathFiles]); }) .fail(dtd.reject); diff --git a/src/service/group-api-service.js b/src/service/group-api-service.js new file mode 100644 index 00000000..53e02d91 --- /dev/null +++ b/src/service/group-api-service.js @@ -0,0 +1,72 @@ +/** + * + * ## Group API Adapter + * + * The Group API Adapter provides methods to look up, create, change or remove information about groups in a project. It is based on query capabilities of the underlying RESTful [Group API](../../../rest_apis/user_management/group/). + * + * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/). + * + * var ma = new F.service.Group({ token: 'user-or-project-access-token' }); + * ma.getGroupsForProject({ account: 'acme', project: 'sample' }); + */ + +'use strict'; + +var serviceUtils = require('./service-utils'); +var TransportFactory = require('../transport/http-transport-factory'); +var objectAssign = require('object-assign'); + +var apiEndpoint = 'group/local'; + +var GroupService = function (config) { + var defaults = { + /** + * Epicenter account name. Defaults to undefined. + * @type {string} + */ + account: undefined, + + /** + * Epicenter project name. Defaults to undefined. + * @type {string} + */ + project: undefined, + + /** + * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object. + * @type {object} + */ + transport: {} + }; + var serviceOptions = serviceUtils.getDefaultOptions(defaults, config, { apiEndpoint: apiEndpoint }); + var transportOptions = serviceOptions.transport; + delete serviceOptions.transport; + var http = new TransportFactory(transportOptions, serviceOptions); + var publicAPI = { + /* + * Gets information for a group or multiple groups. + * @param {string} `params` the groupId of the target group + * @param {Object} `params` object with query parameters + * @patam {string} `params.q` partial match for name, organization or event. + * @patam {string} `params.account` Epicenter's Team ID + * @patam {string} `params.project` Epicenter's Project ID + * @patam {string} `params.name` Epicenter's Group Name + * @param {Object} `options` (Optional) Overrides for configuration options. + */ + getGroups: function (params, options) { + //groupID is part of the URL + //q, account and project are part of the query string + var finalOpts = objectAssign({}, serviceOptions, options); + var finalParams; + if (typeof params === 'string') { + finalOpts.url = serviceUtils.getApiUrl(apiEndpoint + '/' + params, finalOpts); + } else { + finalParams = params; + } + return http.get(finalParams, finalOpts); + } + }; + objectAssign(this, publicAPI); +}; + +module.exports = GroupService; diff --git a/src/service/run-api-service.js b/src/service/run-api-service.js index a6537ee4..5b8bfbc2 100644 --- a/src/service/run-api-service.js +++ b/src/service/run-api-service.js @@ -463,7 +463,7 @@ module.exports = function (config) { ); } $.when.apply(this, queue) - .done(function () { + .then(function () { $d.resolve.apply(this, arguments); postOptions.success.apply(this.arguments); }) diff --git a/src/service/service-utils.js b/src/service/service-utils.js new file mode 100644 index 00000000..edcf5c71 --- /dev/null +++ b/src/service/service-utils.js @@ -0,0 +1,40 @@ +'use strict'; + +var ConfigService = require('./configuration-service'); +var SessionManager = require('../store/session-manager'); +var objectAssign = require('object-assign'); + +var serviceUtils = { + /* + * Gets the default options for a api service. + * It will merge: + * - The Session options (Using the Session Manager) + * - The Authorization Header from the token option + * - The full url from the endpoint option + * With the supplied overrides and defaults + * + */ + getDefaultOptions: function (defaults) { + var rest = Array.prototype.slice.call(arguments, 1); + var sessionManager = new SessionManager(); + var serviceOptions = sessionManager.getMergedOptions.apply(sessionManager, [defaults].concat(rest)); + + serviceOptions.transport = objectAssign({}, serviceOptions.transport, { + url: this.getApiUrl(serviceOptions.apiEndpoint, serviceOptions) + }); + + if (serviceOptions.token) { + serviceOptions.transport.headers = { + 'Authorization': 'Bearer ' + serviceOptions.token + }; + } + return serviceOptions; + }, + + getApiUrl: function (apiEndpoint, serviceOptions) { + var urlConfig = new ConfigService(serviceOptions).get('server'); + return urlConfig.getAPIPath(apiEndpoint); + } +}; + +module.exports = serviceUtils; \ No newline at end of file diff --git a/src/service/world-api-adapter.js b/src/service/world-api-adapter.js index af1b07eb..89bdee36 100644 --- a/src/service/world-api-adapter.js +++ b/src/service/world-api-adapter.js @@ -585,10 +585,10 @@ module.exports = function (config) { var currentWorld = worlds[0]; if (currentWorld) { - serviceOptions.filter = currentWorld.id; + serviceOptions.filter = currentWorld.id; } - dtd.resolve(currentWorld, me); + dtd.resolveWith(me, [currentWorld]); }) .fail(dtd.reject); diff --git a/src/store/cookie-store.js b/src/store/cookie-store.js index a03793f3..4f321b6e 100644 --- a/src/store/cookie-store.js +++ b/src/store/cookie-store.js @@ -24,6 +24,9 @@ var Cookie = function () { module.exports = function (config) { var host = window.location.hostname; + var validHost = host.split('.').length > 1; + var domain = validHost ? '.' + host : null; + var defaults = { /** * Name of collection @@ -31,7 +34,7 @@ module.exports = function (config) { */ root: '/', - domain: '.' + host, + domain: domain, cookie: new Cookie() }; this.serviceOptions = $.extend({}, defaults, config); diff --git a/src/store/session-manager.js b/src/store/session-manager.js index 737125c5..17b5630c 100644 --- a/src/store/session-manager.js +++ b/src/store/session-manager.js @@ -60,7 +60,12 @@ var SessionManager = function (managerOptions) { return session; }, removeSession: function (options) { - return getStore(options).remove(EPI_SESSION_KEY); + var store = getStore(options); + Object.keys(keyNames).forEach(function (cookieKey) { + var cookieName = keyNames[cookieKey]; + store.remove(cookieName); + }); + return true; }, getStore: function (options) { return getStore(options); diff --git a/src/util/make-sequence.js b/src/util/make-sequence.js deleted file mode 100644 index 25567ce6..00000000 --- a/src/util/make-sequence.js +++ /dev/null @@ -1,81 +0,0 @@ -'use strict'; -/*jshint loopfunc:false */ - -function _w(val) { - if (val && val.then) { - return val; - } - var p = $.Deferred(); - p.resolve(val); - - return p.promise(); -} - -function seq() { - var list = Array.prototype.slice.apply(arguments); - - function next(p) { - var cur = list.splice(0,1)[0]; - - if (!cur) { - return p; - } - - return _w(cur(p)).then(next); - } - - return function (seed) { - return next(seed).fail(seq.fail); - }; -} - -function MakeSeq(obj) { - var res = { - __calls: [], - - original: obj, - - then: function (fn) { - this.__calls.push(fn); - return this; - }, - - start: function () { - var _this = this; - - // clean up - this.then(function (run) { - _this.__calls.length = 0; - return run; - }); - - return seq.apply(null, this.__calls)(); - }, - - fail: function (fn) { - seq.fail = fn; - return this; - } - }; - - var funcMaker = function (p, obj) { - var fn = obj[p].bind(obj); - return function () { - var args = Array.prototype.slice.apply(arguments); - this.__calls.push(Function.bind.apply(fn, [null].concat(args))); - return this; - }; - }; - - for (var prop in obj) { - if (typeof obj[prop] === 'function') { - res[prop] = funcMaker(prop, obj); - } else { - res[prop] = obj[prop]; - } - } - - return res; -} - -module.exports = MakeSeq; diff --git a/tests/index.html b/tests/index.html index e62795fb..35fc036d 100644 --- a/tests/index.html +++ b/tests/index.html @@ -84,6 +84,7 @@ + diff --git a/tests/integration/assets/assets-test.js b/tests/integration/assets/assets-test.js index d13e2d36..4c83cb56 100644 --- a/tests/integration/assets/assets-test.js +++ b/tests/integration/assets/assets-test.js @@ -51,7 +51,7 @@ $(function() { am.login({ userName: $('#txtUsername').val(), password: $('#txtPassword').val(), - }).done(function (response) { + }).then(function (response) { $loginEl.modal('hide'); $('.status').append('
Logged in as: ' + credentials.userName + '
'); _this.assetAdapter = new F.service.Asset(server); @@ -66,7 +66,7 @@ $(function() { var imageExtensions = ['png', 'jpg', 'jpeg', 'gif', 'svg', 'bmp']; $('.images').empty(); - this.assetAdapter.list({ scope: scope }).done(function (response) { + this.assetAdapter.list({ scope: scope }).then(function (response) { $.each(response, function () { var url = this; var filename = url.substring(url.lastIndexOf('/') + 1); @@ -103,7 +103,7 @@ $(function() { try { // filename will be ignored if it's a multipart/form-data request - this.assetAdapter.create(filename, data, { scope: scope }).done(function () { + this.assetAdapter.create(filename, data, { scope: scope }).then(function () { $('.status').html('
File uploaded! Reloading assets...
'); $('.list [name=scope]').val(scope); _this.listAssets(); @@ -130,7 +130,7 @@ $(function() { // var aa = new F.service.Asset($.extend(server, extra)); // aa.create('test.txt', { encoding: 'BASE_64', data: 'VGhpcyBpcyBhIHRlc3QgZmlsZS4=' }, { scope: 'user' }); //aa.delete('test1.txt', { scope: 'user' }); - // aa.list({ scope: 'user', fullUrl: true }).done(function (response) { + // aa.list({ scope: 'user', fullUrl: true }).then(function (response) { // console.log(response); // }); }); diff --git a/tests/integration/multiplayer/test-script.js b/tests/integration/multiplayer/test-script.js index da394356..a3962e2e 100644 --- a/tests/integration/multiplayer/test-script.js +++ b/tests/integration/multiplayer/test-script.js @@ -24,7 +24,7 @@ $(function () { password: $('#txtPassword').val(), account: $('#txtAccount').val(), project: $('#txtProject').val() - }).done(function () { + }).then(function () { window.alert('login successful'); }); }); diff --git a/tests/playground.html b/tests/playground.html new file mode 100644 index 00000000..c499a325 --- /dev/null +++ b/tests/playground.html @@ -0,0 +1,117 @@ + + + + + + Epicenter JS libs Playground + + + + + + + + + + + + + + diff --git a/tests/spec/test-ajax-http-transport.js b/tests/spec/test-ajax-http-transport.js index ba636417..f08041cd 100644 --- a/tests/spec/test-ajax-http-transport.js +++ b/tests/spec/test-ajax-http-transport.js @@ -13,7 +13,7 @@ server.respondWith('GET', /api\.fail/, function (xhr, id) { xhr.respond(500, { 'Content-Type': 'application/json' }, JSON.stringify({ url: xhr.url })); }); - //server.autoRespond = true; + server.respondImmediately = true; }); @@ -96,7 +96,6 @@ ajax.get({ a:2,b:3 }, { success: callback }); - server.respond(); callback.called.should.equal(true); }); it('should call fail callback on success', function () { @@ -106,7 +105,6 @@ ajax.get({ a:2,b:3 }, { error: callback }); - server.respond(); callback.called.should.equal(true); }); diff --git a/tests/spec/test-asset-api-adapter.js b/tests/spec/test-asset-api-adapter.js index fe85d04f..b5bc9020 100644 --- a/tests/spec/test-asset-api-adapter.js +++ b/tests/spec/test-asset-api-adapter.js @@ -25,7 +25,7 @@ server.respondWith('POST', /(.*)\/asset\/(.*)\/(.*)/, function (xhr, id) { xhr.respond(204); }); - server.autoRespond = true; + server.respondImmediately = true; }); after(function () { @@ -177,29 +177,27 @@ it('should get the list of the assets for the user', function () { var callback = sinon.spy(); var aa = new F.service.Asset(defaults); - aa.list({ scope: 'user', fullUrl: false }).done(callback); - - server.respond(); - var req = server.requests.pop(); - req.url.should.equal(baseURL + 'user/forio/js-libs/asset-group/myUserId'); - req.method.should.equal('GET'); - callback.should.have.been.called; - callback.should.have.been.calledWith(['file.txt', 'file2.txt']); + return aa.list({ scope: 'user', fullUrl: false }).then(callback).then(function () { + var req = server.requests.pop(); + req.url.should.equal(baseURL + 'user/forio/js-libs/asset-group/myUserId'); + req.method.should.equal('GET'); + callback.should.have.been.called; + callback.should.have.been.calledWith(['file.txt', 'file2.txt']); + }); }); it('should get the list of the assets for the user with the full URL', function () { var callback = sinon.spy(); var aa = new F.service.Asset(defaults); - aa.list({ scope: 'user' }).done(callback); - - server.respond(); - var req = server.requests.pop(); - req.url.should.equal(baseURL + 'user/forio/js-libs/asset-group/myUserId'); - req.method.should.equal('GET'); - callback.should.have.been.called; - callback.should.have.been.calledWith([ - baseURL + 'user/forio/js-libs/asset-group/myUserId/file.txt', - baseURL + 'user/forio/js-libs/asset-group/myUserId/file2.txt']); + return aa.list({ scope: 'user' }).then(callback).then(function () { + var req = server.requests.pop(); + req.url.should.equal(baseURL + 'user/forio/js-libs/asset-group/myUserId'); + req.method.should.equal('GET'); + callback.should.have.been.called; + callback.should.have.been.calledWith([ + baseURL + 'user/forio/js-libs/asset-group/myUserId/file.txt', + baseURL + 'user/forio/js-libs/asset-group/myUserId/file2.txt']); + }); }); }); diff --git a/tests/spec/test-auth-api-service.js b/tests/spec/test-auth-api-service.js index aff4d0b6..c92803cf 100644 --- a/tests/spec/test-auth-api-service.js +++ b/tests/spec/test-auth-api-service.js @@ -14,7 +14,7 @@ { 'refresh_token':'snip-refresh','access_token': token,'expires':43199 } )); }); - server.autoRespond = true; + server.respondImmediately = true; }); after(function () { @@ -27,7 +27,6 @@ var as = new AuthService({ transport: { beforeSend: callback } }); as.login({ userName: 'john', password: 'y' }); - server.respond(); server.requests.pop(); callback.should.have.been.called; }); diff --git a/tests/spec/test-auth-manager.js b/tests/spec/test-auth-manager.js index 649c4892..efc11c1e 100644 --- a/tests/spec/test-auth-manager.js +++ b/tests/spec/test-auth-manager.js @@ -1,8 +1,10 @@ (function () { 'use strict'; describe('Auth Manager', function () { - var server, token, userInfo, cookie, multipleGroupsResponse; + var server, token, userInfo, cookie, multipleGroupsResponse, teamMemberResponse; before(function () { + teamMemberResponse = false; + multipleGroupsResponse = false; var cookieStr = ''; cookie = { get: function () { @@ -38,10 +40,13 @@ }; token = 'eyJhbGciOiJSUzI1NiJ9.' + btoa(JSON.stringify(userInfo)) + '.yYIKw_eWYXAoqPR9aKXs4_'; + var tmUserInfo = $.extend({ 'parent_account_id': null }, userInfo); + var teamMemberToken = 'eyJhbGciOiJSUzI1NiJ9.' + btoa(JSON.stringify(tmUserInfo)) + '.yYIKw_eWYXAoqPR9aKXs4_'; server = sinon.fakeServer.create(); server.respondWith(/(.*)\/authentication/, function (xhr, id) { + var response = teamMemberResponse ? teamMemberToken : token; xhr.respond(201, { 'Content-Type': 'application/json' }, JSON.stringify( - { 'refresh_token':'snip-refresh','access_token': token,'expires':43199 } + { 'refresh_token':'snip-refresh','access_token': response,'expires':43199 } )); }); var groupMembers = [ @@ -77,31 +82,38 @@ var response = multipleGroupsResponse ? multipleGroups : singleGroup; xhr.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify(response)); }); - server.autoRespond = true; + server.respondWith(/(.*)\/group\/local/, function (xhr, id) { + var response = multipleGroupsResponse ? multipleGroups : singleGroup; + xhr.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify(response)); + }); + server.respondImmediately = true; }); + afterEach(function () { + server.requests = []; + }); after(function () { server.restore(); }); describe('Login', function () { - it ('It should construct the right authenticaton request', function () { + it('It should construct the right authenticaton request', function () { var am = new F.manager.AuthManager({ account: 'accountName', project: 'projectName', }); am.login({ userName: 'test', password: 'test' }); - var req = server.requests.pop(); + var req = server.requests[0]; req.method.toUpperCase().should.equal('POST'); req.url.should.match(/https:\/\/api\.forio\.com\/(.*)\/authentication\/?/); }); - it ('It should call members API on sucessful login', function (done) { + it('It should call members API on sucessful login', function (done) { var am = new F.manager.AuthManager({ account: 'accountName', project: 'projectName', }); - am.login({ userName: 'test', password: 'test' }).done(function (response) { + am.login({ userName: 'test', password: 'test' }).then(function (response) { //jshint camelcase: false //jscs:disable response.auth.access_token.should.equal(token); @@ -112,12 +124,12 @@ }); }); - it ('it should set the session', function (done) { + it('it should set the session', function (done) { var am = new F.manager.AuthManager({ account: 'accountName', project: 'projectName', }); - am.login({ userName: 'test', password: 'test' }).done(function (response) { + am.login({ userName: 'test', password: 'test' }).then(function (response) { var session = am.getCurrentUserSessionInfo(); session.groupName.should.equal('rv-test'); session.groupId.should.equal('111efcc9-726c-47b8-ba94-2895f110bd39'); @@ -132,13 +144,13 @@ }); }); - it ('it should fail when the user has multiple groups', function (done) { + it('it should fail when the user has multiple groups', function (done) { multipleGroupsResponse = true; var am = new F.manager.AuthManager({ account: 'accountName', project: 'projectName', }); - am.login({ userName: 'test', password: 'test' }).done(function (response) { + am.login({ userName: 'test', password: 'test' }).then(function (response) { multipleGroupsResponse = false; done(new Error('Login should not work')); }).fail(function (data) { @@ -148,13 +160,13 @@ }); }); - it ('it should work when a group is specified', function (done) { + it('it should work when a group is specified', function (done) { multipleGroupsResponse = true; var am = new F.manager.AuthManager({ account: 'accountName', project: 'projectName', }); - am.login({ userName: 'test', password: 'test', groupId: '111efcc9-726c-47b8-ba94-2895f110bd32' }).done(function (response) { + am.login({ userName: 'test', password: 'test', groupId: '111efcc9-726c-47b8-ba94-2895f110bd32' }).then(function (response) { var session = am.getCurrentUserSessionInfo(); session.groupName.should.equal('rv-test2'); multipleGroupsResponse = false; @@ -166,13 +178,13 @@ }); }); - it ('it should not work when a wrong group is used', function (done) { + it('it should not work when a wrong group is used', function (done) { multipleGroupsResponse = true; var am = new F.manager.AuthManager({ account: 'accountName', project: 'projectName', }); - am.login({ userName: 'test', password: 'test', groupId: 'wrong-id' }).done(function (response) { + am.login({ userName: 'test', password: 'test', groupId: 'wrong-id' }).then(function (response) { multipleGroupsResponse = false; done(new Error('Login should not work')); }).fail(function (data) { @@ -181,10 +193,54 @@ done(); }); }); + + it('should log a team member and get all the groups in the project', function (done) { + teamMemberResponse = true; + var am = new F.manager.AuthManager({ + account: 'accountName', + project: 'projectName', + }); + am.login({ userName: 'test', password: 'test' }).then(function (response) { + var req = server.requests.pop(); + req.method.toUpperCase().should.equal('GET'); + req.url.should.match(/https:\/\/api\.forio\.com\/(.*)\/group\/local\/?/); + + var session = am.getCurrentUserSessionInfo(); + session.groupName.should.equal('rv-test'); + am.sessionManager.removeSession(); + done(); + }).fail(function (data) { + done(new Error('Login should work')); + }); + + }); + + it('it should fail with the list of groups on a team member login with no group', function (done) { + multipleGroupsResponse = true; + teamMemberResponse = true; + var am = new F.manager.AuthManager({ + account: 'accountName', + project: 'projectName', + }); + am.login({ userName: 'test', password: 'test' }).then(function (response) { + multipleGroupsResponse = false; + teamMemberResponse = false; + done(new Error('Login should not work')); + }).fail(function (data) { + var req = server.requests.pop(); + req.method.toUpperCase().should.equal('GET'); + req.url.should.match(/https:\/\/api\.forio\.com\/(.*)\/group\/local\/?/); + + multipleGroupsResponse = false; + teamMemberResponse = false; + data.userGroups.should.have.lengthOf(2); + done(); + }); + }); }); describe('Logout', function () { - it ('It should remove the epicenter cookie', function (done) { + it('It should remove the epicenter cookie', function (done) { sinon.spy(cookie, 'set'); var am = new F.manager.AuthManager({ account: 'accountName', @@ -195,9 +251,11 @@ domain: '.forio.com' } }); - am.logout().done(function (response) { + am.logout().then(function (response) { var spyCall = cookie.set.getCall(0); spyCall.args[0].should.match(/epicenterjs\.session=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=\.forio\.com; path=\/app\/accountName\/projectName/); + spyCall = cookie.set.getCall(1); + spyCall.args[0].should.match(/epicenter-scenario=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=\.forio\.com; path=\/app\/accountName\/projectName/); done(); }).fail(function () { done(new Error('Login should not fail')); @@ -206,7 +264,7 @@ }); describe('#setting cookies', function () { - it ('creates cookie with the correct path name when passing in account info in consructor', function () { + it('creates cookie with the correct path name when passing in account info in consructor', function () { var am = new F.manager.AuthManager({ account: 'accountName', project: 'projectName', @@ -216,7 +274,7 @@ var store = am.sessionManager.getStore(); store.serviceOptions.root.should.equal('/app/accountName/projectName'); }); - it ('creates cookie with the root path in local mode', function () { + it('creates cookie with the root path in local mode', function () { var am = new F.manager.AuthManager({ account: 'accountName', project: 'projectName', @@ -225,7 +283,7 @@ var store = am.sessionManager.getStore(); store.serviceOptions.root.should.equal('/'); }); - it ('creates cookie with the correct path name when passing in account info in login', function (done) { + it('creates cookie with the correct path name when passing in account info in login', function (done) { var am = new F.manager.AuthManager({ isLocal: false, store: { @@ -237,7 +295,7 @@ project: 'projectName', userName: 'test', password: 'test', - }).done(function (response) { + }).then(function (response) { var pathIdx = cookie.get().indexOf('path=/app/accountName/projectName'); pathIdx.should.not.equal(-1); done(); @@ -250,12 +308,12 @@ }); describe('#addGroups', function () { - it ('it should have one group on login', function (done) { + it('it should have one group on login', function (done) { var am = new F.manager.AuthManager({ account: 'accountName', project: 'projectName', }); - am.login({ userName: 'test', password: 'test' }).done(function (response) { + am.login({ userName: 'test', password: 'test' }).then(function (response) { var session = am.getCurrentUserSessionInfo(); Object.keys(session.groups).should.have.lengthOf(1); am.sessionManager.removeSession(); @@ -265,12 +323,12 @@ }); }); - it ('it should accept an object', function (done) { + it('it should accept an object', function (done) { var am = new F.manager.AuthManager({ account: 'accountName', project: 'projectName', }); - am.login({ userName: 'test', password: 'test' }).done(function (response) { + am.login({ userName: 'test', password: 'test' }).then(function (response) { am.addGroups({ project: 'test-project', groupName: 'rv-test2', @@ -288,12 +346,12 @@ }); }); - it ('it should accept an array', function (done) { + it('it should accept an array', function (done) { var am = new F.manager.AuthManager({ account: 'accountName', project: 'projectName', }); - am.login({ userName: 'test', password: 'test' }).done(function (response) { + am.login({ userName: 'test', password: 'test' }).then(function (response) { am.addGroups([{ project: 'test-project', groupName: 'rv-test2', @@ -316,12 +374,12 @@ }); }); - it ('it should override a project\'s group', function (done) { + it('it should override a project\'s group', function (done) { var am = new F.manager.AuthManager({ account: 'accountName', project: 'projectName', }); - am.login({ userName: 'test', password: 'test' }).done(function (response) { + am.login({ userName: 'test', password: 'test' }).then(function (response) { am.addGroups([{ project: 'projectName', groupName: 'rv-test2', diff --git a/tests/spec/test-conditional-creation-strategy.js b/tests/spec/test-conditional-creation-strategy.js index f4862be8..a42826f5 100644 --- a/tests/spec/test-conditional-creation-strategy.js +++ b/tests/spec/test-conditional-creation-strategy.js @@ -33,10 +33,8 @@ var setupServer = function () { server = sinon.fakeServer.create(); - setupResponse('GET', /run\/forio-dev\/js-libs/, 200, runs || []); - - server.autorespond = true; + server.respondImmediately = true; }; var teardownServer = function () { @@ -44,15 +42,6 @@ }; describe('Conditional Creation Strategy', function () { - - before(function () { - - }); - - after(function () { - - }); - beforeEach(function () { setupServer(); }); diff --git a/tests/spec/test-env-load.js b/tests/spec/test-env-load.js index dc060f0f..137f06db 100644 --- a/tests/spec/test-env-load.js +++ b/tests/spec/test-env-load.js @@ -10,7 +10,7 @@ var server; beforeEach(function () { server = sinon.fakeServer.create(); - server.autoRespond = true; + server.respondImmediately = true; }); afterEach(function () { @@ -39,7 +39,6 @@ delete F.service.URL.host; //done(); }); - //server.respond(); }); it('it should set protocol and host to api.forio.com when the config request fails', function () { @@ -54,8 +53,9 @@ F.service.URL.host.should.equal('api.forio.com'); delete F.service.URL.protocol; delete F.service.URL.host; - }).fail(callback); - callback.should.have.been.called; + }).then(null, callback).then(function () { + callback.should.have.been.called; + }); }); }); }); diff --git a/tests/spec/test-group-api-service.js b/tests/spec/test-group-api-service.js new file mode 100644 index 00000000..e2783ac5 --- /dev/null +++ b/tests/spec/test-group-api-service.js @@ -0,0 +1,43 @@ +(function () { + 'use strict'; + + var server; + describe('Group API Service', function () { + before(function () { + server = sinon.fakeServer.create(); + server.respondImmediately = true; + }); + + after(function () { + server.restore(); + }); + + function createUserAdapter(options) { + return new F.service.Group(_.extend({ + token: 'some-token' + }, options)); + } + + it('should use token as authorization header if passed', function () { + createUserAdapter().getGroups(); + + var req = server.requests.pop(); + req.requestHeaders.Authorization.should.equal('Bearer some-token'); + }); + + it('should GET the group api with account and project', function () { + createUserAdapter().getGroups({ account: 'forio', project: 'project' }); + + var req = server.requests.pop(); + req.url.should.match(/account=forio/); + req.url.should.match(/project=project/); + }); + + it('should GET the group api with groupID as the string', function () { + createUserAdapter().getGroups('my-group-id'); + + var req = server.requests.pop(); + req.url.should.match(/group\/local\/my-group-id/); + }); + }); +})(); diff --git a/tests/spec/test-member-api-service.js b/tests/spec/test-member-api-service.js index 366977c1..9bb46595 100644 --- a/tests/spec/test-member-api-service.js +++ b/tests/spec/test-member-api-service.js @@ -15,7 +15,7 @@ xhr.respond(201, { 'Content-Type': 'application/json' }, JSON.stringify({ })); }); - server.autoRespond = true; + server.respondImmediately = true; }); after(function () { diff --git a/tests/spec/test-multiplayer-strategy.js b/tests/spec/test-multiplayer-strategy.js index e148fb28..cdbd467c 100644 --- a/tests/spec/test-multiplayer-strategy.js +++ b/tests/spec/test-multiplayer-strategy.js @@ -25,7 +25,8 @@ var setupResponse = function (verb, endpoint, statusCode, resp, respHeaders) { server.respondWith(verb, endpoint, function (xhr, id) { - var headers = _.extend({}, { 'Content-Type': 'application/json' }, respHeaders); + var ct = typeof resp === 'string' ? {} : { 'Content-Type': 'application/json' }; + var headers = _.extend({}, ct, respHeaders); var body = typeof resp === 'object' ? JSON.stringify(resp) : resp; xhr.respond(statusCode, headers, body); }); @@ -49,26 +50,25 @@ var setupServer = function (worlds) { server = sinon.fakeServer.create(); - + server.respondWith('GET', /(.*)\/run\/(.*)\/(.*)/, function (xhr, id) { + xhr.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify({ url: xhr.url })); + return true; + }); setupResponse('GET', queryMatchers.worldEndpoint, 200, worlds || []); - setupResponse('POST', /multiplayer\/world\/worldid1\/run/, 201, 'run1'); setupResponse('POST', /multiplayer\/world\/worldid2\/run/, 201, 'run2'); - server.autorespond = true; + server.respondImmediately = true; }; var teardownServer = function () { server.restore(); }; - - describe('Multiplayer strategy', function () { beforeEach(_.partial(setupServer, worldSet)); afterEach(teardownServer); - function createRunManager(options) { var rm = new F.manager.RunManager(_.extend({ strategy: 'multiplayer', @@ -82,42 +82,34 @@ // this is briddle, it knows too much about the internals of the run manager // but replace the cookie store with a stub rm.strategy._auth = fakeAuth; - return rm; } describe('with world/users setup correctly', function () { it('should get the list of worlds for the current user first', function () { - createRunManager().getRun(); - - var req = server.requests.pop(); - req.method.toUpperCase().should.equal('GET'); - - req.url.should.match(queryMatchers.getWorlds); + return createRunManager().getRun().then(function () { + var req = server.requests[0]; + req.method.toUpperCase().should.equal('GET'); + req.url.should.match(queryMatchers.getWorlds); + }); }); it('should post to the run endpoint after getting the world', function () { - createRunManager().getRun(); - - server.respond(); - var req = server.requests.pop(); - - req.method.toUpperCase().should.equal('POST'); - req.url.should.match(/multiplayer\/world\/worldid2\/run/); - + return createRunManager().getRun().then(function () { + var req = server.requests[1]; + req.method.toUpperCase().should.equal('POST'); + req.url.should.match(/multiplayer\/world\/worldid2\/run/); + }); }); }); describe('with two worlds for the user', function () { it('should use the latest world to retore the run', function () { - createRunManager().getRun(); - - server.respond(); - var req = server.requests.pop(); - - req.method.toUpperCase().should.equal('POST'); - - req.url.should.match(/multiplayer\/world\/worldid2/); + return createRunManager().getRun().then(function () { + var req = server.requests[1]; + req.method.toUpperCase().should.equal('POST'); + req.url.should.match(/multiplayer\/world\/worldid2/); + }); }); }); @@ -125,14 +117,12 @@ beforeEach(_.partial(setupServer, [])); it('should fail the getRun request with proper error', function () { var callback = sinon.spy(); - createRunManager().getRun() - .fail(callback); - - server.respond(); - - callback.called.should.be.true; + return createRunManager().getRun() + .then(null, callback) + .then(function () { + callback.called.should.be.true; + }); }); }); - }); })(); diff --git a/tests/spec/test-run-api-service-callbacks.js b/tests/spec/test-run-api-service-callbacks.js index 1d83c8cb..8a5b7432 100644 --- a/tests/spec/test-run-api-service-callbacks.js +++ b/tests/spec/test-run-api-service-callbacks.js @@ -30,7 +30,7 @@ xhr.respond(400, { 'Content-Type': 'application/json' }, JSON.stringify({ url: xhr.url })); }); - server.autoRespond = true; + server.respondImmediately = true; }); after(function () { @@ -43,11 +43,10 @@ var cb2 = sinon.spy(); var rs = new RunService({ account: 'forio', project: 'js-libs', filter: { saved: true } }); - rs.do('add', [1,2], { success: cb1 }).then(cb2); - server.respond(); - - cb1.should.have.been.called; - cb2.should.have.been.called; + return rs.do('add', [1,2], { success: cb1 }).then(cb2).then(function () { + cb1.should.have.been.called; + cb2.should.have.been.called; + }); }); it('passes error callbacks', function () { var cb1 = sinon.spy(); @@ -56,12 +55,11 @@ var rs = new RunService({ account: 'failure', project: 'js-libs', filter: { saved: true } }); - rs.do('add', [1,2], { error: cb1 }).fail(cb3); - server.respond(); - - cb1.should.have.been.called; - cb2.should.not.have.been.called; - cb3.should.have.been.called; + return rs.do('add', [1,2], { error: cb1 }).then(null, cb3).then(null, function () { + cb1.should.have.been.called; + cb2.should.not.have.been.called; + cb3.should.have.been.called; + }); }); }); describe('#serial', function () { @@ -70,12 +68,10 @@ var cb2 = sinon.spy(); var rs = new RunService({ account: 'forio', project: 'js-libs', filter: { saved: true } }); - rs.serial([{ first: [1,2] }, { second: [2,3] }], null, { success: cb1 }).then(cb2); - server.respond(); - server.respond(); - - cb1.should.have.been.called; - cb2.should.have.been.called; + return rs.serial([{ first: [1,2] }, { second: [2,3] }], null, { success: cb1 }).then(cb2).then(function () { + cb1.should.have.been.called; + cb2.should.have.been.called; + }); }); it('passes error callbacks', function () { var cb1 = sinon.spy(); @@ -83,12 +79,11 @@ var cb3 = sinon.spy(); var rs = new RunService({ account: 'failure', project: 'js-libs', filter: { saved: true } }); - rs.serial([{ first: [1,2] }, { second: [2,3] }], null, { error: cb1 }).fail(cb3); - server.respond(); - - cb1.should.have.been.called; - cb2.should.not.have.been.called; - cb3.should.have.been.called; + return rs.serial([{ first: [1,2] }, { second: [2,3] }], null, { error: cb1 }).then(null, cb3).then(function () { + cb1.should.have.been.called; + cb2.should.not.have.been.called; + cb3.should.have.been.called; + }); }); }); describe('#parallel', function () { @@ -98,11 +93,10 @@ var rs = new RunService({ account: 'forio', project: 'js-libs', filter: { saved: true } }); - rs.parallel([{ first: [1,2] }, { second: [2,3] }], null, { success: cb1 }).then(cb2); - server.respond(); - - cb1.should.have.been.called; - cb2.should.have.been.called; + return rs.parallel([{ first: [1,2] }, { second: [2,3] }], null, { success: cb1 }).then(cb2).then(function () { + cb1.should.have.been.called; + cb2.should.have.been.called; + }); }); it('passes error callbacks', function () { var cb1 = sinon.spy(); @@ -111,12 +105,11 @@ var rs = new RunService({ account: 'failure', project: 'js-libs', filter: { saved: true } }); - rs.parallel([{ first: [1,2] }, { second: [2,3] }], null, { error: cb1 }).fail(cb3); - server.respond(); - - cb1.should.have.been.called; - cb2.should.not.have.been.called; - cb3.should.have.been.called; + return rs.parallel([{ first: [1,2] }, { second: [2,3] }], null, { error: cb1 }).then(null, cb3).then(function () { + cb1.should.have.been.called; + cb2.should.not.have.been.called; + cb3.should.have.been.called; + }); }); }); @@ -126,11 +119,10 @@ var cb2 = sinon.spy(); var rs = new RunService({ account: 'forio', project: 'js-libs' }); - rs.create('model.jl', { success: cb1 }).then(cb2); - server.respond(); - - cb1.should.have.been.called; - cb2.should.have.been.called; + return rs.create('model.jl', { success: cb1 }).then(cb2).then(function () { + cb1.should.have.been.called; + cb2.should.have.been.called; + }); }); it('passes error callbacks', function () { var cb1 = sinon.spy(); @@ -139,12 +131,11 @@ var rs = new RunService({ account: 'failure', project: 'js-libs' }); - rs.create('model.jl', { error: cb1 }).fail(cb3); - server.respond(); - - cb1.should.have.been.called; - cb2.should.not.have.been.called; - cb3.should.have.been.called; + return rs.create('model.jl', { error: cb1 }).then(null, cb3).then(function () { + cb1.should.have.been.called; + cb2.should.not.have.been.called; + cb3.should.have.been.called; + }); }); }); describe('#query', function () { @@ -153,10 +144,10 @@ var cb2 = sinon.spy(); var rs = new RunService({ account: 'forio', project: 'js-libs' }); - rs.query({ saved: true, '.price': '>1' }, { page: 1 }, { success: cb1 }).then(cb2); - server.respond(); + return rs.query({ saved: true, '.price': '>1' }, { page: 1 }, { success: cb1 }).then(cb2).then(function () { + cb1.should.have.been.called; - cb1.should.have.been.called; + }); }); it('passes error callbacks', function () { var cb1 = sinon.spy(); @@ -165,12 +156,11 @@ var rs = new RunService({ account: 'failure', project: 'js-libs' }); - rs.query({ saved: true, '.price': '>1' }, { page: 1 }, { error: cb1 }).fail(cb3); - server.respond(); - - cb1.should.have.been.called; - cb2.should.not.have.been.called; - cb3.should.have.been.called; + return rs.query({ saved: true, '.price': '>1' }, { page: 1 }, { error: cb1 }).then(null, cb3).then(function () { + cb1.should.have.been.called; + cb2.should.not.have.been.called; + cb3.should.have.been.called; + }); }); }); describe('#filter', function () { @@ -179,10 +169,9 @@ var cb2 = sinon.spy(); var rs = new RunService({ account: 'forio', project: 'js-libs' }); - rs.filter({ saved: true, '.price': '>1' }, { page: 1 }, { success: cb1 }).then(cb2); - server.respond(); - - cb1.should.have.been.called; + return rs.filter({ saved: true, '.price': '>1' }, { page: 1 }, { success: cb1 }).then(cb2).then(function () { + cb1.should.have.been.called; + }); }); it('passes error callbacks', function () { var cb1 = sinon.spy(); @@ -191,12 +180,11 @@ var rs = new RunService({ account: 'failure', project: 'js-libs' }); - rs.filter({ saved: true, '.price': '>1' }, { page: 1 }, { error: cb1 }).fail(cb3); - server.respond(); - - cb1.should.have.been.called; - cb2.should.not.have.been.called; - cb3.should.have.been.called; + return rs.filter({ saved: true, '.price': '>1' }, { page: 1 }, { error: cb1 }).then(null, cb3).then(function () { + cb1.should.have.been.called; + cb2.should.not.have.been.called; + cb3.should.have.been.called; + }); }); }); describe('#load', function () { @@ -204,11 +192,10 @@ var cb1 = sinon.spy(); var cb2 = sinon.spy(); var rs = new RunService({ account: 'forio', project: 'js-libs' }); - rs.load('myfancyrunid', { include: 'score' }, { success: cb1 }).then(cb2); - server.respond(); - - cb1.should.have.been.called; - cb2.should.have.been.called; + return rs.load('myfancyrunid', { include: 'score' }, { success: cb1 }).then(cb2).then(function () { + cb1.should.have.been.called; + cb2.should.have.been.called; + }); }); it('passes error callbacks', function () { var cb1 = sinon.spy(); @@ -217,12 +204,11 @@ var rs = new RunService({ account: 'failure', project: 'js-libs' }); - rs.load('myfancyrunid', { include: 'score' }, { error: cb1 }).fail(cb3); - server.respond(); - - cb1.should.have.been.called; - cb2.should.not.have.been.called; - cb3.should.have.been.called; + return rs.load('myfancyrunid', { include: 'score' }, { error: cb1 }).then(null, cb3).then(function () { + cb1.should.have.been.called; + cb2.should.not.have.been.called; + cb3.should.have.been.called; + }); }); }); describe('#save', function () { @@ -231,11 +217,10 @@ var cb2 = sinon.spy(); var rs = new RunService({ account: 'forio', project: 'js-libs', filter: { saved: true } }); - rs.save({ completed: true }, { success: cb1 }).then(cb2); - server.respond(); - - cb1.should.have.been.called; - cb2.should.have.been.called; + return rs.save({ completed: true }, { success: cb1 }).then(cb2).then(function () { + cb1.should.have.been.called; + cb2.should.have.been.called; + }); }); it('passes error callbacks', function () { var cb1 = sinon.spy(); @@ -244,14 +229,12 @@ var rs = new RunService({ account: 'failure', project: 'js-libs', filter: { saved: true } }); - rs.save({ completed: true }, { error: cb1 }).fail(cb3); - server.respond(); - - cb1.should.have.been.called; - cb2.should.not.have.been.called; - cb3.should.have.been.called; + return rs.save({ completed: true }, { error: cb1 }).then(null, cb3).then(function () { + cb1.should.have.been.called; + cb2.should.not.have.been.called; + cb3.should.have.been.called; + }); }); }); - }); })(); diff --git a/tests/spec/test-run-api-service.js b/tests/spec/test-run-api-service.js index dfa45ec2..3b04f2d9 100644 --- a/tests/spec/test-run-api-service.js +++ b/tests/spec/test-run-api-service.js @@ -133,9 +133,12 @@ xhr.respond(500, { 'Content-Type': 'application/json' }, JSON.stringify({ message: 'Internal server error' })); return true; }); - server.autoRespond = true; + server.respondImmediately = true; }); + afterEach(function () { + server.requests = []; + }); after(function () { server.restore(); }); @@ -165,24 +168,22 @@ it('should return promiseables', function () { var callback = sinon.spy(); var rs = new RunService({ account: account, project: project }); - rs + return rs .create('model.jl') - .then(callback); - - server.respond(); - - callback.should.have.been.called; - callback.should.have.been.calledWith({ - 'id': '065dfe50-d29d-4b55-a0fd-30868d7dd26c', - 'model': 'model.vmf', - 'account': 'mit', - 'project': 'afv', - 'saved': false, - 'lastModified': '2014-06-20T04:09:45.738Z', - 'created': '2014-06-20T04:09:45.738Z' + .then(callback) + .then(function () { + callback.should.have.been.called; + callback.should.have.been.calledWith({ + 'id': '065dfe50-d29d-4b55-a0fd-30868d7dd26c', + 'model': 'model.vmf', + 'account': 'mit', + 'project': 'afv', + 'saved': false, + 'lastModified': '2014-06-20T04:09:45.738Z', + 'created': '2014-06-20T04:09:45.738Z' + }); }); // callback.should.have.been.calledOn(rs); - }); describe('transport.options', function () { @@ -192,7 +193,6 @@ var rs = new RunService({ account: account, project: 'js-libs', transport: { beforeSend: beforeSend, complete: complete } }); rs.create('model.jl'); - server.respond(); beforeSend.should.have.been.called; complete.should.have.been.called; }); @@ -203,7 +203,6 @@ var rs = new RunService({ account: account, project: 'js-libs', transport: { complete: originalComplete } }); rs.create('model.jl', { complete: complete }); - server.respond(); originalComplete.should.not.have.been.called; complete.should.have.been.called; }); @@ -214,7 +213,6 @@ var rs = new RunService({ account: account, project: 'js-libs', transport: { complete: originalComplete } }); rs.create('model.jl', { complete: complete }); - server.respond(); originalComplete.should.not.have.been.called; complete.should.have.been.called; }); @@ -225,7 +223,6 @@ var rs = new RunService({ account: account, project: 'js-libs', success: originalSuccess, transport: { complete: transportSuccess } }); rs.create('model.jl'); - server.respond(); originalSuccess.should.have.been.called; transportSuccess.should.have.been.called; }); @@ -312,20 +309,13 @@ }); it('should be idempotent across multiple queries', function () { - server.requests = []; var rs = new RunService({ account: account, project: project }); - rs.query({ saved: true, '.price': '>1' }); - server.respond(); - - server.requests[0].url.should.equal(baseURL + ';saved=true;.price>1/'); - - - rs.query({ saved: false, '.sales': '<4' }); - server.respond(); - - server.requests[1].url.should.equal(baseURL + ';saved=false;.sales<4/'); - server.requests = []; - + return rs.query({ saved: true, '.price': '>1' }).then(function () { + return rs.query({ saved: false, '.sales': '<4' }).then(function () { + server.requests[0].url.should.equal(baseURL + ';saved=true;.price>1/'); + server.requests[1].url.should.equal(baseURL + ';saved=false;.sales<4/'); + }); + }); }); it('should convert op modifiers to query strings', function () { var rs = new RunService({ account: account, project: project }); @@ -335,94 +325,86 @@ req.url.should.equal(baseURL + ';/?page=1&limit=2'); }); it('should split the get in multiple GETs', function () { - server.requests = []; var rs = new RunService({ account: account, project: project }); var include = createLargeInclude(); rs.query({}, { include: include }); - //server.respond(); + server.respond(); server.requests.length.should.be.above(1); server.requests.forEach(function (xhr) { xhr.url.length.should.be.below(2049); }); - server.requests = []; }); it('should fail if one or more of the multiple GETs fail', function () { - server.requests = []; - var done = sinon.spy(); + var success = sinon.spy(); var fail = sinon.spy(); var rs = new RunService({ account: account, project: project }); var include = createLargeInclude(); include.push('internal_server_error'); - rs.query({}, { include: include }).then(done, fail); - server.respond(); - fail.should.have.been.called; - done.should.not.have.been.called; - server.requests = []; + return rs.query({}, { include: include }).then(success, fail).then(function () { + fail.should.have.been.called; + success.should.not.have.been.called; + }); }); it('should aggregate the response from the multiple GETs for a single run', function () { - server.requests = []; - var done = sinon.spy(); + var success = sinon.spy(); var fail = sinon.spy(); var rs = new RunService({ account: account, project: project }); var include = createLargeInclude(); include.push('single_variables_c_d'); include = ['single_variables_a_b'].concat(include); - rs.query({}, { include: include }).done(done).fail(fail); - server.respond(); - done.should.have.been.calledWith({ - 'id': '065dfe50-d29d-4b55-a0fd-30868d7dd26c', - 'model': 'model.vmf', - 'account': account, - 'project': 'js-libs', - 'saved': false, - 'lastModified': '2014-06-20T04:09:45.738Z', - 'created': '2014-06-20T04:09:45.738Z', - 'variables': { - 'varA': 9999.99, - 'varB': 'A string', - 'varC': 'Another string', - 'varD': 10.22, - } + return rs.query({}, { include: include }).then(success, fail).then(function () { + success.should.have.been.calledWith({ + 'id': '065dfe50-d29d-4b55-a0fd-30868d7dd26c', + 'model': 'model.vmf', + 'account': account, + 'project': 'js-libs', + 'saved': false, + 'lastModified': '2014-06-20T04:09:45.738Z', + 'created': '2014-06-20T04:09:45.738Z', + 'variables': { + 'varA': 9999.99, + 'varB': 'A string', + 'varC': 'Another string', + 'varD': 10.22, + } + }); + fail.should.not.have.been.called; }); - fail.should.not.have.been.called; - server.requests = []; }); it('should aggregate the reponse from the multiple GETs for a multiple runs', function () { - server.requests = []; - var done = sinon.spy(); + var success = sinon.spy(); var fail = sinon.spy(); var rs = new RunService({ account: account, project: project }); var include = createLargeInclude(); include.push('multiple_variables_c_d'); include = ['multiple_variables_a_b'].concat(include); - rs.query({}, { include: include }).done(done).fail(fail); - server.respond(); - done.should.have.been.calledWith([ - { - 'id': 'run1', - 'variables': { - 'varA': 1111.11, - 'varB': 'A string for run1', - 'varC': 'Another string for run1', - 'varD': '2015-11-16 10:10:10' - } - }, - { - 'id': 'run2', - 'variables': { - 'varA': 2222.22, - 'varB': 'A string for run2', - 'varC': 'Another string for run2', - 'varD': '2015-11-16 20:20:20' - } - }, - ]); - fail.should.not.have.been.called; - server.requests = []; + return rs.query({}, { include: include }).then(success, fail).then(function () { + success.should.have.been.calledWith([ + { + 'id': 'run1', + 'variables': { + 'varA': 1111.11, + 'varB': 'A string for run1', + 'varC': 'Another string for run1', + 'varD': '2015-11-16 10:10:10' + } + }, + { + 'id': 'run2', + 'variables': { + 'varA': 2222.22, + 'varB': 'A string for run2', + 'varC': 'Another string for run2', + 'varD': '2015-11-16 20:20:20' + } + }, + ]); + fail.should.not.have.been.called; + }); }); }); @@ -449,20 +431,16 @@ req.url.should.equal(baseURL + ';/?page=1&limit=2'); }); it('should pass through options across multiple queries', function () { - server.requests = []; var rs = new RunService({ account: account, project: project }); rs.filter({ saved: true, '.price': '>1' }); - server.respond(); server.requests[0].url.should.equal(baseURL + ';saved=true;.price>1/'); rs.filter({ saved: false, '.sales': '<4' }); - server.respond(); server.requests[1].url.should.equal(baseURL + ';saved=false;.price>1;.sales<4/'); - server.requests = []; }); it('should not include the AutoRestore header', function () { @@ -609,7 +587,6 @@ var rs = new RunService({ account: account, project: 'js-libs', filter: { saved: true } }); rs.do('init'); - server.respond(); var req = server.requests.pop(); req.url.should.equal(baseURL + ';saved=true/operations/init/'); req.requestBody.should.equal(JSON.stringify({ arguments: [] })); @@ -623,25 +600,21 @@ ret.should.throw(Error); }); - it('should send multiple operations calls once by one', function () { - server.requests = []; - + it('should send multiple operations calls one by one', function () { var rs = new RunService({ account: account, project: 'js-libs', filter: { saved: true } }); - rs.serial([{ first: [1,2] }, { second: [2,3] }]); - server.respond(); - - server.requests.length.should.equal(2); - server.requests[0].url.should.equal(baseURL + ';saved=true/operations/first/'); - server.requests[0].requestBody.should.equal(JSON.stringify({ arguments: [1,2] })); - - server.requests[1].url.should.equal(baseURL + ';saved=true/operations/second/'); - server.requests[1].requestBody.should.equal(JSON.stringify({ arguments: [2,3] })); + return rs.serial([{ first: [1, 2] }, { second: [2, 3] }]).then(function () { + server.requests.length.should.equal(2); + server.requests[0].url.should.equal(baseURL + ';saved=true/operations/first/'); + server.requests[0].requestBody.should.equal(JSON.stringify({ arguments: [1,2] })); + + server.requests[1].url.should.equal(baseURL + ';saved=true/operations/second/'); + server.requests[1].requestBody.should.equal(JSON.stringify({ arguments: [2,3] })); + }); }); it('should send operations without any parameters', function () { var rs = new RunService({ account: account, project: 'js-libs', filter: { saved: true } }); rs.serial(['init']); - server.respond(); var req = server.requests.pop(); req.url.should.equal(baseURL + ';saved=true/operations/init/'); @@ -657,11 +630,9 @@ }); it('should send multiple operations calls once by one', function () { - server.requests = []; var rs = new RunService({ account: account, project: 'js-libs', filter: { saved: true } }); rs.parallel([{ first: [1,2] }, { second: [2,3] }]); - server.respond(); server.requests.length.should.equal(2); }); diff --git a/tests/spec/test-user-api-adapter.js b/tests/spec/test-user-api-adapter.js index b1098bec..1dbfe5f7 100644 --- a/tests/spec/test-user-api-adapter.js +++ b/tests/spec/test-user-api-adapter.js @@ -12,7 +12,7 @@ describe('User API Service', function () { before(function () { server = sinon.fakeServer.create(); - server.autoRespond = true; + server.respondImmediately = true; }); after(function () { diff --git a/tests/spec/test-variables-api-service.js b/tests/spec/test-variables-api-service.js index 23d69893..fc1b172c 100644 --- a/tests/spec/test-variables-api-service.js +++ b/tests/spec/test-variables-api-service.js @@ -47,7 +47,7 @@ xhr.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify(variablesCD)); return true; }); - server.autoRespond = true; + server.respondImmediately = true; rs = new RunService({ account: account, project: project }); vs = rs.variables(); @@ -68,14 +68,14 @@ }); it('should use the right url', function () { vs.load('price'); - server.respond(); + // server.respond(); var req = server.requests.pop(); req.url.should.equal(baseURL + ';/variables/price/'); }); it('should not add the autorestore run flag', function () { vs.load('price'); - server.respond(); + // server.respond(); var req = server.requests.pop(); req.requestHeaders.should.not.have.property('X-AutoRestore'); @@ -84,7 +84,7 @@ var rs = new RunService({ account: account, project: 'js-libs', filter: 'myfancyrunid' }); var vs = rs.variables(); vs.load('price'); - server.respond(); + // server.respond(); var req = server.requests.pop(); req.requestHeaders.should.have.property('X-AutoRestore', true); @@ -93,7 +93,7 @@ var rs = new RunService({ account: account, project: 'js-libs', filter: 'myfancyrunid', autoRestore: false }); var vs = rs.variables(); vs.load('price'); - server.respond(); + // server.respond(); var req = server.requests.pop(); req.requestHeaders.should.not.have.property('X-AutoRestore'); @@ -103,28 +103,28 @@ describe('#query()', function () { it('should do a GET', function () { vs.query(['price', 'sales']); - server.respond(); + // server.respond(); var req = server.requests.pop(); req.method.toUpperCase().should.equal('GET'); }); it('should convert includes', function () { vs.query({ include: ['price', 'sales'] }); - server.respond(); + // server.respond(); var req = server.requests.pop(); req.url.should.equal(baseURL + ';/variables/?include=price,sales'); }); it('should convert sets', function () { vs.query({ set: 'a' }); - server.respond(); + // server.respond(); var req = server.requests.pop(); req.url.should.equal(baseURL + ';/variables/?set=a'); }); it('should convert sets & includes', function () { vs.query({ set: ['a', 'b'], include: 'price' }); - server.respond(); + // server.respond(); var req = server.requests.pop(); req.url.should.equal(baseURL + ';/variables/?set=a,b&include=price'); @@ -134,7 +134,7 @@ var include = createLargeInclude(); vs.query(include); - server.respond(); + // server.respond(); server.requests.length.should.be.above(1); server.requests.forEach(function (xhr) { xhr.url.length.should.be.below(2048); @@ -142,24 +142,27 @@ server.requests = []; }); it('should aggregate the response from the multiple GETs from the variables API', function () { - server.requests = []; - var done = sinon.spy(); - var fail = sinon.spy(); + var success = sinon.spy(); + var fail = sinon.spy(function () { + console.log('failll'); + }); var rs = new RunService({ account: account, project: project }); var include = createLargeInclude(); include.push('variables_c_d'); include = ['variables_a_b'].concat(include); - rs.query({}, { include: include }).done(done).fail(fail); - server.respond(); - done.should.have.been.calledWith({ - 'varA': 'Value A', - 'varB': 0.0001, - 'varC': 'Another string for run1', - 'varD': '2015-11-16 10:10:10' - }); - fail.should.not.have.been.called; - server.requests = []; + return rs.query({}, { include: include }) + .then(success) + .fail(fail) + .then(function () { + success.should.have.been.calledWith({ + varA: 'Value A', + varB: 0.0001, + varC: 'Another string for run1', + varD: '2015-11-16 10:10:10' + }); + fail.should.not.have.been.called; + }); }); it('the multiple GETs encoded urls length should not be larger than 2048', function () { server.requests = []; @@ -174,7 +177,7 @@ }); it('should not add the autorestore run flag', function () { vs.query({ set: ['a', 'b'], include: 'price' }); - server.respond(); + // server.respond(); var req = server.requests.pop(); req.requestHeaders.should.not.have.property('X-AutoRestore'); @@ -183,7 +186,7 @@ var rs = new RunService({ account: account, project: 'js-libs', filter: 'myfancyrunid' }); var vs = rs.variables(); vs.query({ set: ['a', 'b'], include: 'price' }); - server.respond(); + // server.respond(); var req = server.requests.pop(); req.requestHeaders.should.have.property('X-AutoRestore', true); @@ -192,7 +195,7 @@ var rs = new RunService({ account: account, project: 'js-libs', filter: 'myfancyrunid', autoRestore: false }); var vs = rs.variables(); vs.query({ set: ['a', 'b'], include: 'price' }); - server.respond(); + // server.respond(); var req = server.requests.pop(); req.requestHeaders.should.not.have.property('X-AutoRestore'); @@ -204,7 +207,7 @@ // Temporarily using PATCH to mean PUT // it('should do a PUT', function () { // vs.save({ a: 1, b: 2 }); - // server.respond(); + // server.respond(); // var req = server.requests.pop(); @@ -213,7 +216,7 @@ it('should do a PATCH', function () { vs.save({ a: 1, b: 2 }); - server.respond(); + // server.respond(); var req = server.requests.pop(); @@ -223,7 +226,7 @@ it('should send requests in the body', function () { var params = { a: 1, b: 2 }; vs.save(params); - server.respond(); + // server.respond(); var req = server.requests.pop(); @@ -232,7 +235,7 @@ }); it('should support setting key, value syntax', function () { vs.save('a', 1); - server.respond(); + // server.respond(); var req = server.requests.pop(); req.url.should.equal(baseURL + ';/variables/'); @@ -243,7 +246,7 @@ // describe('#merge()', function () { // it('should do a PATCH', function () { // vs.merge({ a: 1, b: 2 }); - // server.respond(); + // server.respond(); // var req = server.requests.pop(); // req.method.toUpperCase().should.equal('PATCH'); @@ -252,7 +255,7 @@ // it('should send requests in the body', function () { // var params = { a: 1, b: 2 }; // vs.merge(params); - // server.respond(); + // server.respond(); // var req = server.requests.pop(); // req.url.should.equal(baseURL + ';/variables/'); @@ -261,7 +264,7 @@ // it('should support setting key, value syntax', function () { // vs.merge('a', 1); - // server.respond(); + // server.respond(); // var req = server.requests.pop(); // req.url.should.equal(baseURL + ';/variables/'); @@ -275,7 +278,7 @@ var cb1 = sinon.spy(); vs.load('sales', null, { success: cb1 }); - server.respond(); + // server.respond(); cb1.called.should.equal(true); }); }); @@ -284,7 +287,7 @@ var cb1 = sinon.spy(); vs.query({ include: ['price', 'sales'] }, null, { success: cb1 }); - server.respond(); + // server.respond(); cb1.called.should.equal(true); }); }); @@ -295,7 +298,7 @@ vs.save({ a: 1, b: 2 }, { success: cb1 }); vs.save('a', 1, { success: cb2 }); - server.respond(); + // server.respond(); cb1.called.should.equal(true); cb2.called.should.equal(true); }); @@ -307,7 +310,7 @@ // vs.merge({ a: 1, b: 2 }, { success: cb1 }); // vs.merge('a', 1, { success: cb2 }); - // server.respond(); + // server.respond(); // cb1.called.should.equal(true); // cb2.called.should.equal(true); // }); diff --git a/tests/spec/test-world-api-service.js b/tests/spec/test-world-api-service.js index fc61a6ed..abdd9e1c 100644 --- a/tests/spec/test-world-api-service.js +++ b/tests/spec/test-world-api-service.js @@ -13,7 +13,7 @@ xhr.respond(204, { 'Content-Type': 'application/json' }, null); }); - server.autoRespond = true; + server.respondImmediately = true; }); afterEach(function () { diff --git a/tests/spec/test-world-manager.js b/tests/spec/test-world-manager.js index 0793148f..290dddc0 100644 --- a/tests/spec/test-world-manager.js +++ b/tests/spec/test-world-manager.js @@ -62,10 +62,7 @@ lastModified: '123' })); }); - - - - server.autoRespond = true; + server.respondImmediately = true; }); afterEach(function () { @@ -140,12 +137,9 @@ describe('getCurrentRun', function (done) { it('should return the current run object and runService of the run of the current world', function (done) { createWorldManager().getCurrentRun('model.py') - .then(function (run, runService) { + .then(function (run) { run.should.not.be.null; run.id.should.be.equal('run2'); - - runService.should.not.be.null; - done(); }) .fail(function () {