diff --git a/dist/epicenter.js b/dist/epicenter.js index df5e4ff3..9ea89f31 100644 --- a/dist/epicenter.js +++ b/dist/epicenter.js @@ -1918,11 +1918,10 @@ var defaults = { var EPI_COOKIE_KEY = keyNames.EPI_COOKIE_KEY; var EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY; -var store; var token; var session; -function saveSession(userInfo) { +function saveSession(userInfo, store) { var serialized = JSON.stringify(userInfo); store.set(EPI_SESSION_KEY, serialized); @@ -1931,7 +1930,7 @@ function saveSession(userInfo) { store.set(EPI_COOKIE_KEY, userInfo.auth_token); } -function getSession() { +function getSession(store) { var session = store.get(EPI_SESSION_KEY) || '{}'; return JSON.parse(session); } @@ -1940,6 +1939,8 @@ function AuthManager(options) { this.options = $.extend(true, {}, defaults, options); var urlConfig = new ConfigService(this.options).get('server'); + this.isLocal = urlConfig.isLocalhost(); + if (!this.options.account) { this.options.account = urlConfig.accountPath; } @@ -1949,9 +1950,9 @@ function AuthManager(options) { this.options.project = urlConfig.projectPath; } - store = new StorageFactory(this.options.store); - session = getSession(); - token = store.get(EPI_COOKIE_KEY) || ''; + this.store = new StorageFactory(this.options.store); + session = getSession(this.store); + token = this.store.get(EPI_COOKIE_KEY) || ''; //jshint camelcase: false //jscs:disable this.authAdapter = new AuthAdapter(this.options, { token: session.auth_token }); @@ -1977,9 +1978,9 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * * authMgr.login({ * account: 'acme-simulations', - * project: 'supply-chain-game', + * project: 'supply-chain-game', * userName: 'enduser1', - * password: 'passw0rd' + * password: 'passw0rd' * }) * .then(function(statusObj) { * // if enduser1 belongs to exactly one group @@ -1987,8 +1988,8 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * // continue here * }) * .fail(function(statusObj) { - * // if enduser1 belongs to multiple groups, - * // the login() call fails + * // if enduser1 belongs to multiple groups, + * // the login() call fails * // and returns all groups of which the user is a member * for (var i=0; i < statusObj.userGroups.length; i++) { * console.log(statusObj.userGroups[i].name, statusObj.userGroups[i].groupId); @@ -1997,12 +1998,12 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * * **Parameters** * - * @param {Object} `options` (Optional) Overrides for configuration options. If not passed in when creating an instance of the manager (`F.manager.AuthManager()`), these options should include: + * @param {Object} `options` (Optional) Overrides for configuration options. If not passed in when creating an instance of the manager (`F.manager.AuthManager()`), these options should include: * @param {string} `options.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). * @param {string} `options.userName` Email or username to use for logging in. * @param {string} `options.password` Password for specified `userName`. * @param {string} `options.project` (Optional) The **Project ID** for the project to log this user into. - * @param {string} `options.groupId` The id of the group to which `userName` belongs. Required for [end users](../../../glossary/#users) if the `project` is specified and if the end users are members of multiple [groups](../../../glossary/#groups), otherwise optional. + * @param {string} `options.groupId` The id of the group to which `userName` belongs. Required for [end users](../../../glossary/#users) if the `project` is specified and if the end users are members of multiple [groups](../../../glossary/#groups), otherwise optional. */ login: function (options) { var _this = this; @@ -2012,6 +2013,13 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { var outError = adapterOptions.error; var groupId = adapterOptions.groupId; + var accountName = (options && options.account) ? options.account : this.options.account; + var projectName = (options && options.project) ? options.project : this.options.project; + + if (this.options.store.root === undefined && accountName && projectName) { + this.store.serviceOptions.root = this.isLocal ? '/' : '/app/' + accountName + '/' + projectName; + } + var decodeToken = function (token) { var encoded = token.split('.')[1]; while (encoded.length % 4 !== 0) { @@ -2035,7 +2043,6 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { //jshint camelcase: false //jscs:disable token = response.access_token; - var userInfo = decodeToken(token); var userGroupOpts = $.extend(true, {}, adapterOptions, { success: $.noop, token: token }); _this.getUserGroups({ userId: userInfo.user_id, token: token }, userGroupOpts).done( function (memberInfo) { @@ -2049,7 +2056,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { }; // The group is not required if the user is not logging into a project if (!adapterOptions.project) { - saveSession(sessionInfo); + saveSession(sessionInfo, _this.store); outSuccess.apply(this, [data]); $d.resolve(data); return; @@ -2079,7 +2086,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { 'groupName': group.name, 'isFac': _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator' }); - saveSession(sessionInfoWithGroup); + saveSession(sessionInfoWithGroup, _this.store); outSuccess.apply(this, [data]); $d.resolve(data); } else { @@ -2122,11 +2129,12 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * @param {Object} `options` (Optional) Overrides for configuration options. */ logout: function (options) { + var _this = this; var adapterOptions = $.extend(true, { token: token }, this.options, options); var removeCookieFn = function (response) { - store.remove(EPI_COOKIE_KEY, adapterOptions); - store.remove(EPI_SESSION_KEY, adapterOptions); + _this.store.remove(EPI_COOKIE_KEY, adapterOptions); + _this.store.remove(EPI_SESSION_KEY, adapterOptions); token = ''; }; @@ -2139,8 +2147,8 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * **Example** * * authMgr.getToken() - * .then(function (token) { - * console.log('My token is ', token); + * .then(function (token) { + * console.log('My token is ', token); * }); * * **Parameters** @@ -2168,8 +2176,8 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * // get groups for current user * var sessionObj = authMgr.getCurrentUserSessionInfo(); * authMgr.getUserGroups({ userId: sessionObj.userId, token: sessionObj.auth_token }) - * .then(function (groups) { - * for (var i=0; i < groups.length; i++) + * .then(function (groups) { + * for (var i=0; i < groups.length; i++) * { console.log(groups[i].name); } * }); * @@ -2209,7 +2217,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * * *Important*: This method is synchronous. The session information is returned immediately in an object; no callbacks or promises are needed. * - * By default, session information is stored in a cookie in the browser. You can change this with the `store` configuration option. + * By default, session information is stored in a cookie in the browser. You can change this with the `store` configuration option. * * **Example** * @@ -2219,7 +2227,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * @param {Object} `options` (Optional) Overrides for configuration options. */ getCurrentUserSessionInfo: function (options) { - return getSession(options); + return getSession(this.store, options); } }); @@ -6722,7 +6730,7 @@ module.exports = function (config) { domain: '.forio.com' }; - var serviceOptions = $.extend({}, defaults, config); + this.serviceOptions = $.extend({}, defaults, config); var publicAPI = { // * TBD @@ -6755,7 +6763,7 @@ module.exports = function (config) { * cs.set({ name:'smith', age:'32' }); */ set: function (key, value, options) { - var setOptions = $.extend(true, {}, serviceOptions, options); + var setOptions = $.extend(true, {}, this.serviceOptions, options); var domain = setOptions.domain; var path = setOptions.root; @@ -6792,7 +6800,7 @@ module.exports = function (config) { * cs.remove('person'); */ remove: function (key, options) { - var remOptions = $.extend(true, {}, serviceOptions, options); + var remOptions = $.extend(true, {}, this.serviceOptions, options); var domain = remOptions.domain; var path = remOptions.root; @@ -7443,4 +7451,4 @@ module.exports = (function () { }()); },{"./query-util":44}]},{},[6]) -//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9ncnVudC1icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvZ3J1bnQtYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvYmFzZTY0LWpzL2xpYi9iNjQuanMiLCJub2RlX21vZHVsZXMvZ3J1bnQtYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL25vZGVfbW9kdWxlcy9pZWVlNzU0L2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvaXMtYXJyYXkvaW5kZXguanMiLCJzcmMvYXBpLXZlcnNpb24uanNvbiIsInNyYy9hcHAuanMiLCJzcmMvbWFuYWdlcnMvYXV0aC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2NoYW5uZWwtbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2tleS1uYW1lcy5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9hbHdheXMtbmV3LXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2lkZW50aXR5LXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL211bHRpcGxheWVyLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9zdHJhdGVnaWVzLW1hcC5qcyIsInNyYy9tYW5hZ2Vycy9zY2VuYXJpby1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL3NwZWNpYWwtb3BlcmF0aW9ucy5qcyIsInNyYy9tYW5hZ2Vycy93b3JsZC1tYW5hZ2VyLmpzIiwic3JjL3NlcnZpY2UvYWRtaW4tZmlsZS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvYXNzZXQtYXBpLWFkYXB0ZXIuanMiLCJzcmMvc2VydmljZS9hdXRoLWFwaS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvZGF0YS1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3J1bi1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3N0YXRlLWFwaS1hZGFwdGVyLmpzIiwic3JjL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3ZhcmlhYmxlcy1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyLmpzIiwic3JjL3N0b3JlL2Nvb2tpZS1zdG9yZS5qcyIsInNyYy9zdG9yZS9zdG9yZS1mYWN0b3J5LmpzIiwic3JjL3RyYW5zcG9ydC9hamF4LWh0dHAtdHJhbnNwb3J0LmpzIiwic3JjL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5LmpzIiwic3JjL3V0aWwvaW5oZXJpdC5qcyIsInNyYy91dGlsL21ha2Utc2VxdWVuY2UuanMiLCJzcmMvdXRpbC9vYmplY3QtdXRpbC5qcyIsInNyYy91dGlsL3F1ZXJ5LXV0aWwuanMiLCJzcmMvdXRpbC9ydW4tdXRpbC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUN4Z0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDL0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwV0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMVRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ05BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9FQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN1hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0UUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hmQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4SEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0VBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25LQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzdUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNkQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiLyohXG4gKiBUaGUgYnVmZmVyIG1vZHVsZSBmcm9tIG5vZGUuanMsIGZvciB0aGUgYnJvd3Nlci5cbiAqXG4gKiBAYXV0aG9yICAgRmVyb3NzIEFib3VraGFkaWplaCA8ZmVyb3NzQGZlcm9zcy5vcmc+IDxodHRwOi8vZmVyb3NzLm9yZz5cbiAqIEBsaWNlbnNlICBNSVRcbiAqL1xuLyogZXNsaW50LWRpc2FibGUgbm8tcHJvdG8gKi9cblxudmFyIGJhc2U2NCA9IHJlcXVpcmUoJ2Jhc2U2NC1qcycpXG52YXIgaWVlZTc1NCA9IHJlcXVpcmUoJ2llZWU3NTQnKVxudmFyIGlzQXJyYXkgPSByZXF1aXJlKCdpcy1hcnJheScpXG5cbmV4cG9ydHMuQnVmZmVyID0gQnVmZmVyXG5leHBvcnRzLlNsb3dCdWZmZXIgPSBTbG93QnVmZmVyXG5leHBvcnRzLklOU1BFQ1RfTUFYX0JZVEVTID0gNTBcbkJ1ZmZlci5wb29sU2l6ZSA9IDgxOTIgLy8gbm90IHVzZWQgYnkgdGhpcyBpbXBsZW1lbnRhdGlvblxuXG52YXIgcm9vdFBhcmVudCA9IHt9XG5cbi8qKlxuICogSWYgYEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUYDpcbiAqICAgPT09IHRydWUgICAgVXNlIFVpbnQ4QXJyYXkgaW1wbGVtZW50YXRpb24gKGZhc3Rlc3QpXG4gKiAgID09PSBmYWxzZSAgIFVzZSBPYmplY3QgaW1wbGVtZW50YXRpb24gKG1vc3QgY29tcGF0aWJsZSwgZXZlbiBJRTYpXG4gKlxuICogQnJvd3NlcnMgdGhhdCBzdXBwb3J0IHR5cGVkIGFycmF5cyBhcmUgSUUgMTArLCBGaXJlZm94IDQrLCBDaHJvbWUgNyssIFNhZmFyaSA1LjErLFxuICogT3BlcmEgMTEuNissIGlPUyA0LjIrLlxuICpcbiAqIER1ZSB0byB2YXJpb3VzIGJyb3dzZXIgYnVncywgc29tZXRpbWVzIHRoZSBPYmplY3QgaW1wbGVtZW50YXRpb24gd2lsbCBiZSB1c2VkIGV2ZW5cbiAqIHdoZW4gdGhlIGJyb3dzZXIgc3VwcG9ydHMgdHlwZWQgYXJyYXlzLlxuICpcbiAqIE5vdGU6XG4gKlxuICogICAtIEZpcmVmb3ggNC0yOSBsYWNrcyBzdXBwb3J0IGZvciBhZGRpbmcgbmV3IHByb3BlcnRpZXMgdG8gYFVpbnQ4QXJyYXlgIGluc3RhbmNlcyxcbiAqICAgICBTZWU6IGh0dHBzOi8vYnVnemlsbGEubW96aWxsYS5vcmcvc2hvd19idWcuY2dpP2lkPTY5NTQzOC5cbiAqXG4gKiAgIC0gU2FmYXJpIDUtNyBsYWNrcyBzdXBwb3J0IGZvciBjaGFuZ2luZyB0aGUgYE9iamVjdC5wcm90b3R5cGUuY29uc3RydWN0b3JgIHByb3BlcnR5XG4gKiAgICAgb24gb2JqZWN0cy5cbiAqXG4gKiAgIC0gQ2hyb21lIDktMTAgaXMgbWlzc2luZyB0aGUgYFR5cGVkQXJyYXkucHJvdG90eXBlLnN1YmFycmF5YCBmdW5jdGlvbi5cbiAqXG4gKiAgIC0gSUUxMCBoYXMgYSBicm9rZW4gYFR5cGVkQXJyYXkucHJvdG90eXBlLnN1YmFycmF5YCBmdW5jdGlvbiB3aGljaCByZXR1cm5zIGFycmF5cyBvZlxuICogICAgIGluY29ycmVjdCBsZW5ndGggaW4gc29tZSBzaXR1YXRpb25zLlxuXG4gKiBXZSBkZXRlY3QgdGhlc2UgYnVnZ3kgYnJvd3NlcnMgYW5kIHNldCBgQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRgIHRvIGBmYWxzZWAgc28gdGhleVxuICogZ2V0IHRoZSBPYmplY3QgaW1wbGVtZW50YXRpb24sIHdoaWNoIGlzIHNsb3dlciBidXQgYmVoYXZlcyBjb3JyZWN0bHkuXG4gKi9cbkJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUID0gZ2xvYmFsLlRZUEVEX0FSUkFZX1NVUFBPUlQgIT09IHVuZGVmaW5lZFxuICA/IGdsb2JhbC5UWVBFRF9BUlJBWV9TVVBQT1JUXG4gIDogdHlwZWRBcnJheVN1cHBvcnQoKVxuXG5mdW5jdGlvbiB0eXBlZEFycmF5U3VwcG9ydCAoKSB7XG4gIGZ1bmN0aW9uIEJhciAoKSB7fVxuICB0cnkge1xuICAgIHZhciBhcnIgPSBuZXcgVWludDhBcnJheSgxKVxuICAgIGFyci5mb28gPSBmdW5jdGlvbiAoKSB7IHJldHVybiA0MiB9XG4gICAgYXJyLmNvbnN0cnVjdG9yID0gQmFyXG4gICAgcmV0dXJuIGFyci5mb28oKSA9PT0gNDIgJiYgLy8gdHlwZWQgYXJyYXkgaW5zdGFuY2VzIGNhbiBiZSBhdWdtZW50ZWRcbiAgICAgICAgYXJyLmNvbnN0cnVjdG9yID09PSBCYXIgJiYgLy8gY29uc3RydWN0b3IgY2FuIGJlIHNldFxuICAgICAgICB0eXBlb2YgYXJyLnN1YmFycmF5ID09PSAnZnVuY3Rpb24nICYmIC8vIGNocm9tZSA5LTEwIGxhY2sgYHN1YmFycmF5YFxuICAgICAgICBhcnIuc3ViYXJyYXkoMSwgMSkuYnl0ZUxlbmd0aCA9PT0gMCAvLyBpZTEwIGhhcyBicm9rZW4gYHN1YmFycmF5YFxuICB9IGNhdGNoIChlKSB7XG4gICAgcmV0dXJuIGZhbHNlXG4gIH1cbn1cblxuZnVuY3Rpb24ga01heExlbmd0aCAoKSB7XG4gIHJldHVybiBCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVFxuICAgID8gMHg3ZmZmZmZmZlxuICAgIDogMHgzZmZmZmZmZlxufVxuXG4vKipcbiAqIENsYXNzOiBCdWZmZXJcbiAqID09PT09PT09PT09PT1cbiAqXG4gKiBUaGUgQnVmZmVyIGNvbnN0cnVjdG9yIHJldHVybnMgaW5zdGFuY2VzIG9mIGBVaW50OEFycmF5YCB0aGF0IGFyZSBhdWdtZW50ZWRcbiAqIHdpdGggZnVuY3Rpb24gcHJvcGVydGllcyBmb3IgYWxsIHRoZSBub2RlIGBCdWZmZXJgIEFQSSBmdW5jdGlvbnMuIFdlIHVzZVxuICogYFVpbnQ4QXJyYXlgIHNvIHRoYXQgc3F1YXJlIGJyYWNrZXQgbm90YXRpb24gd29ya3MgYXMgZXhwZWN0ZWQgLS0gaXQgcmV0dXJuc1xuICogYSBzaW5nbGUgb2N0ZXQuXG4gKlxuICogQnkgYXVnbWVudGluZyB0aGUgaW5zdGFuY2VzLCB3ZSBjYW4gYXZvaWQgbW9kaWZ5aW5nIHRoZSBgVWludDhBcnJheWBcbiAqIHByb3RvdHlwZS5cbiAqL1xuZnVuY3Rpb24gQnVmZmVyIChhcmcpIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIEJ1ZmZlcikpIHtcbiAgICAvLyBBdm9pZCBnb2luZyB0aHJvdWdoIGFuIEFyZ3VtZW50c0FkYXB0b3JUcmFtcG9saW5lIGluIHRoZSBjb21tb24gY2FzZS5cbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+IDEpIHJldHVybiBuZXcgQnVmZmVyKGFyZywgYXJndW1lbnRzWzFdKVxuICAgIHJldHVybiBuZXcgQnVmZmVyKGFyZylcbiAgfVxuXG4gIHRoaXMubGVuZ3RoID0gMFxuICB0aGlzLnBhcmVudCA9IHVuZGVmaW5lZFxuXG4gIC8vIENvbW1vbiBjYXNlLlxuICBpZiAodHlwZW9mIGFyZyA9PT0gJ251bWJlcicpIHtcbiAgICByZXR1cm4gZnJvbU51bWJlcih0aGlzLCBhcmcpXG4gIH1cblxuICAvLyBTbGlnaHRseSBsZXNzIGNvbW1vbiBjYXNlLlxuICBpZiAodHlwZW9mIGFyZyA9PT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gZnJvbVN0cmluZyh0aGlzLCBhcmcsIGFyZ3VtZW50cy5sZW5ndGggPiAxID8gYXJndW1lbnRzWzFdIDogJ3V0ZjgnKVxuICB9XG5cbiAgLy8gVW51c3VhbC5cbiAgcmV0dXJuIGZyb21PYmplY3QodGhpcywgYXJnKVxufVxuXG5mdW5jdGlvbiBmcm9tTnVtYmVyICh0aGF0LCBsZW5ndGgpIHtcbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aCA8IDAgPyAwIDogY2hlY2tlZChsZW5ndGgpIHwgMClcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgIHRoYXRbaV0gPSAwXG4gICAgfVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21TdHJpbmcgKHRoYXQsIHN0cmluZywgZW5jb2RpbmcpIHtcbiAgaWYgKHR5cGVvZiBlbmNvZGluZyAhPT0gJ3N0cmluZycgfHwgZW5jb2RpbmcgPT09ICcnKSBlbmNvZGluZyA9ICd1dGY4J1xuXG4gIC8vIEFzc3VtcHRpb246IGJ5dGVMZW5ndGgoKSByZXR1cm4gdmFsdWUgaXMgYWx3YXlzIDwga01heExlbmd0aC5cbiAgdmFyIGxlbmd0aCA9IGJ5dGVMZW5ndGgoc3RyaW5nLCBlbmNvZGluZykgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG5cbiAgdGhhdC53cml0ZShzdHJpbmcsIGVuY29kaW5nKVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tT2JqZWN0ICh0aGF0LCBvYmplY3QpIHtcbiAgaWYgKEJ1ZmZlci5pc0J1ZmZlcihvYmplY3QpKSByZXR1cm4gZnJvbUJ1ZmZlcih0aGF0LCBvYmplY3QpXG5cbiAgaWYgKGlzQXJyYXkob2JqZWN0KSkgcmV0dXJuIGZyb21BcnJheSh0aGF0LCBvYmplY3QpXG5cbiAgaWYgKG9iamVjdCA9PSBudWxsKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignbXVzdCBzdGFydCB3aXRoIG51bWJlciwgYnVmZmVyLCBhcnJheSBvciBzdHJpbmcnKVxuICB9XG5cbiAgaWYgKHR5cGVvZiBBcnJheUJ1ZmZlciAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBpZiAob2JqZWN0LmJ1ZmZlciBpbnN0YW5jZW9mIEFycmF5QnVmZmVyKSB7XG4gICAgICByZXR1cm4gZnJvbVR5cGVkQXJyYXkodGhhdCwgb2JqZWN0KVxuICAgIH1cbiAgICBpZiAob2JqZWN0IGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHtcbiAgICAgIHJldHVybiBmcm9tQXJyYXlCdWZmZXIodGhhdCwgb2JqZWN0KVxuICAgIH1cbiAgfVxuXG4gIGlmIChvYmplY3QubGVuZ3RoKSByZXR1cm4gZnJvbUFycmF5TGlrZSh0aGF0LCBvYmplY3QpXG5cbiAgcmV0dXJuIGZyb21Kc29uT2JqZWN0KHRoYXQsIG9iamVjdClcbn1cblxuZnVuY3Rpb24gZnJvbUJ1ZmZlciAodGhhdCwgYnVmZmVyKSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGJ1ZmZlci5sZW5ndGgpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuICBidWZmZXIuY29weSh0aGF0LCAwLCAwLCBsZW5ndGgpXG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheSAodGhhdCwgYXJyYXkpIHtcbiAgdmFyIGxlbmd0aCA9IGNoZWNrZWQoYXJyYXkubGVuZ3RoKSB8IDBcbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aClcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoYXRbaV0gPSBhcnJheVtpXSAmIDI1NVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbi8vIER1cGxpY2F0ZSBvZiBmcm9tQXJyYXkoKSB0byBrZWVwIGZyb21BcnJheSgpIG1vbm9tb3JwaGljLlxuZnVuY3Rpb24gZnJvbVR5cGVkQXJyYXkgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG4gIC8vIFRydW5jYXRpbmcgdGhlIGVsZW1lbnRzIGlzIHByb2JhYmx5IG5vdCB3aGF0IHBlb3BsZSBleHBlY3QgZnJvbSB0eXBlZFxuICAvLyBhcnJheXMgd2l0aCBCWVRFU19QRVJfRUxFTUVOVCA+IDEgYnV0IGl0J3MgY29tcGF0aWJsZSB3aXRoIHRoZSBiZWhhdmlvclxuICAvLyBvZiB0aGUgb2xkIEJ1ZmZlciBjb25zdHJ1Y3Rvci5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoYXRbaV0gPSBhcnJheVtpXSAmIDI1NVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheUJ1ZmZlciAodGhhdCwgYXJyYXkpIHtcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gUmV0dXJuIGFuIGF1Z21lbnRlZCBgVWludDhBcnJheWAgaW5zdGFuY2UsIGZvciBiZXN0IHBlcmZvcm1hbmNlXG4gICAgYXJyYXkuYnl0ZUxlbmd0aFxuICAgIHRoYXQgPSBCdWZmZXIuX2F1Z21lbnQobmV3IFVpbnQ4QXJyYXkoYXJyYXkpKVxuICB9IGVsc2Uge1xuICAgIC8vIEZhbGxiYWNrOiBSZXR1cm4gYW4gb2JqZWN0IGluc3RhbmNlIG9mIHRoZSBCdWZmZXIgY2xhc3NcbiAgICB0aGF0ID0gZnJvbVR5cGVkQXJyYXkodGhhdCwgbmV3IFVpbnQ4QXJyYXkoYXJyYXkpKVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheUxpa2UgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGF0W2ldID0gYXJyYXlbaV0gJiAyNTVcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG4vLyBEZXNlcmlhbGl6ZSB7IHR5cGU6ICdCdWZmZXInLCBkYXRhOiBbMSwyLDMsLi4uXSB9IGludG8gYSBCdWZmZXIgb2JqZWN0LlxuLy8gUmV0dXJucyBhIHplcm8tbGVuZ3RoIGJ1ZmZlciBmb3IgaW5wdXRzIHRoYXQgZG9uJ3QgY29uZm9ybSB0byB0aGUgc3BlYy5cbmZ1bmN0aW9uIGZyb21Kc29uT2JqZWN0ICh0aGF0LCBvYmplY3QpIHtcbiAgdmFyIGFycmF5XG4gIHZhciBsZW5ndGggPSAwXG5cbiAgaWYgKG9iamVjdC50eXBlID09PSAnQnVmZmVyJyAmJiBpc0FycmF5KG9iamVjdC5kYXRhKSkge1xuICAgIGFycmF5ID0gb2JqZWN0LmRhdGFcbiAgICBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIH1cbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aClcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSArPSAxKSB7XG4gICAgdGhhdFtpXSA9IGFycmF5W2ldICYgMjU1XG4gIH1cbiAgcmV0dXJuIHRoYXRcbn1cblxuaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gIEJ1ZmZlci5wcm90b3R5cGUuX19wcm90b19fID0gVWludDhBcnJheS5wcm90b3R5cGVcbiAgQnVmZmVyLl9fcHJvdG9fXyA9IFVpbnQ4QXJyYXlcbn1cblxuZnVuY3Rpb24gYWxsb2NhdGUgKHRoYXQsIGxlbmd0aCkge1xuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICAvLyBSZXR1cm4gYW4gYXVnbWVudGVkIGBVaW50OEFycmF5YCBpbnN0YW5jZSwgZm9yIGJlc3QgcGVyZm9ybWFuY2VcbiAgICB0aGF0ID0gQnVmZmVyLl9hdWdtZW50KG5ldyBVaW50OEFycmF5KGxlbmd0aCkpXG4gICAgdGhhdC5fX3Byb3RvX18gPSBCdWZmZXIucHJvdG90eXBlXG4gIH0gZWxzZSB7XG4gICAgLy8gRmFsbGJhY2s6IFJldHVybiBhbiBvYmplY3QgaW5zdGFuY2Ugb2YgdGhlIEJ1ZmZlciBjbGFzc1xuICAgIHRoYXQubGVuZ3RoID0gbGVuZ3RoXG4gICAgdGhhdC5faXNCdWZmZXIgPSB0cnVlXG4gIH1cblxuICB2YXIgZnJvbVBvb2wgPSBsZW5ndGggIT09IDAgJiYgbGVuZ3RoIDw9IEJ1ZmZlci5wb29sU2l6ZSA+Pj4gMVxuICBpZiAoZnJvbVBvb2wpIHRoYXQucGFyZW50ID0gcm9vdFBhcmVudFxuXG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGNoZWNrZWQgKGxlbmd0aCkge1xuICAvLyBOb3RlOiBjYW5ub3QgdXNlIGBsZW5ndGggPCBrTWF4TGVuZ3RoYCBoZXJlIGJlY2F1c2UgdGhhdCBmYWlscyB3aGVuXG4gIC8vIGxlbmd0aCBpcyBOYU4gKHdoaWNoIGlzIG90aGVyd2lzZSBjb2VyY2VkIHRvIHplcm8uKVxuICBpZiAobGVuZ3RoID49IGtNYXhMZW5ndGgoKSkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdBdHRlbXB0IHRvIGFsbG9jYXRlIEJ1ZmZlciBsYXJnZXIgdGhhbiBtYXhpbXVtICcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICdzaXplOiAweCcgKyBrTWF4TGVuZ3RoKCkudG9TdHJpbmcoMTYpICsgJyBieXRlcycpXG4gIH1cbiAgcmV0dXJuIGxlbmd0aCB8IDBcbn1cblxuZnVuY3Rpb24gU2xvd0J1ZmZlciAoc3ViamVjdCwgZW5jb2RpbmcpIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIFNsb3dCdWZmZXIpKSByZXR1cm4gbmV3IFNsb3dCdWZmZXIoc3ViamVjdCwgZW5jb2RpbmcpXG5cbiAgdmFyIGJ1ZiA9IG5ldyBCdWZmZXIoc3ViamVjdCwgZW5jb2RpbmcpXG4gIGRlbGV0ZSBidWYucGFyZW50XG4gIHJldHVybiBidWZcbn1cblxuQnVmZmVyLmlzQnVmZmVyID0gZnVuY3Rpb24gaXNCdWZmZXIgKGIpIHtcbiAgcmV0dXJuICEhKGIgIT0gbnVsbCAmJiBiLl9pc0J1ZmZlcilcbn1cblxuQnVmZmVyLmNvbXBhcmUgPSBmdW5jdGlvbiBjb21wYXJlIChhLCBiKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGEpIHx8ICFCdWZmZXIuaXNCdWZmZXIoYikpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudHMgbXVzdCBiZSBCdWZmZXJzJylcbiAgfVxuXG4gIGlmIChhID09PSBiKSByZXR1cm4gMFxuXG4gIHZhciB4ID0gYS5sZW5ndGhcbiAgdmFyIHkgPSBiLmxlbmd0aFxuXG4gIHZhciBpID0gMFxuICB2YXIgbGVuID0gTWF0aC5taW4oeCwgeSlcbiAgd2hpbGUgKGkgPCBsZW4pIHtcbiAgICBpZiAoYVtpXSAhPT0gYltpXSkgYnJlYWtcblxuICAgICsraVxuICB9XG5cbiAgaWYgKGkgIT09IGxlbikge1xuICAgIHggPSBhW2ldXG4gICAgeSA9IGJbaV1cbiAgfVxuXG4gIGlmICh4IDwgeSkgcmV0dXJuIC0xXG4gIGlmICh5IDwgeCkgcmV0dXJuIDFcbiAgcmV0dXJuIDBcbn1cblxuQnVmZmVyLmlzRW5jb2RpbmcgPSBmdW5jdGlvbiBpc0VuY29kaW5nIChlbmNvZGluZykge1xuICBzd2l0Y2ggKFN0cmluZyhlbmNvZGluZykudG9Mb3dlckNhc2UoKSkge1xuICAgIGNhc2UgJ2hleCc6XG4gICAgY2FzZSAndXRmOCc6XG4gICAgY2FzZSAndXRmLTgnOlxuICAgIGNhc2UgJ2FzY2lpJzpcbiAgICBjYXNlICdiaW5hcnknOlxuICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgY2FzZSAncmF3JzpcbiAgICBjYXNlICd1Y3MyJzpcbiAgICBjYXNlICd1Y3MtMic6XG4gICAgY2FzZSAndXRmMTZsZSc6XG4gICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgcmV0dXJuIHRydWVcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIGZhbHNlXG4gIH1cbn1cblxuQnVmZmVyLmNvbmNhdCA9IGZ1bmN0aW9uIGNvbmNhdCAobGlzdCwgbGVuZ3RoKSB7XG4gIGlmICghaXNBcnJheShsaXN0KSkgdGhyb3cgbmV3IFR5cGVFcnJvcignbGlzdCBhcmd1bWVudCBtdXN0IGJlIGFuIEFycmF5IG9mIEJ1ZmZlcnMuJylcblxuICBpZiAobGlzdC5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gbmV3IEJ1ZmZlcigwKVxuICB9XG5cbiAgdmFyIGlcbiAgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgbGVuZ3RoID0gMFxuICAgIGZvciAoaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICBsZW5ndGggKz0gbGlzdFtpXS5sZW5ndGhcbiAgICB9XG4gIH1cblxuICB2YXIgYnVmID0gbmV3IEJ1ZmZlcihsZW5ndGgpXG4gIHZhciBwb3MgPSAwXG4gIGZvciAoaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIGl0ZW0gPSBsaXN0W2ldXG4gICAgaXRlbS5jb3B5KGJ1ZiwgcG9zKVxuICAgIHBvcyArPSBpdGVtLmxlbmd0aFxuICB9XG4gIHJldHVybiBidWZcbn1cblxuZnVuY3Rpb24gYnl0ZUxlbmd0aCAoc3RyaW5nLCBlbmNvZGluZykge1xuICBpZiAodHlwZW9mIHN0cmluZyAhPT0gJ3N0cmluZycpIHN0cmluZyA9ICcnICsgc3RyaW5nXG5cbiAgdmFyIGxlbiA9IHN0cmluZy5sZW5ndGhcbiAgaWYgKGxlbiA9PT0gMCkgcmV0dXJuIDBcblxuICAvLyBVc2UgYSBmb3IgbG9vcCB0byBhdm9pZCByZWN1cnNpb25cbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcbiAgZm9yICg7Oykge1xuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICAvLyBEZXByZWNhdGVkXG4gICAgICBjYXNlICdyYXcnOlxuICAgICAgY2FzZSAncmF3cyc6XG4gICAgICAgIHJldHVybiBsZW5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgICByZXR1cm4gdXRmOFRvQnl0ZXMoc3RyaW5nKS5sZW5ndGhcbiAgICAgIGNhc2UgJ3VjczInOlxuICAgICAgY2FzZSAndWNzLTInOlxuICAgICAgY2FzZSAndXRmMTZsZSc6XG4gICAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICAgIHJldHVybiBsZW4gKiAyXG4gICAgICBjYXNlICdoZXgnOlxuICAgICAgICByZXR1cm4gbGVuID4+PiAxXG4gICAgICBjYXNlICdiYXNlNjQnOlxuICAgICAgICByZXR1cm4gYmFzZTY0VG9CeXRlcyhzdHJpbmcpLmxlbmd0aFxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGxvd2VyZWRDYXNlKSByZXR1cm4gdXRmOFRvQnl0ZXMoc3RyaW5nKS5sZW5ndGggLy8gYXNzdW1lIHV0ZjhcbiAgICAgICAgZW5jb2RpbmcgPSAoJycgKyBlbmNvZGluZykudG9Mb3dlckNhc2UoKVxuICAgICAgICBsb3dlcmVkQ2FzZSA9IHRydWVcbiAgICB9XG4gIH1cbn1cbkJ1ZmZlci5ieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aFxuXG4vLyBwcmUtc2V0IGZvciB2YWx1ZXMgdGhhdCBtYXkgZXhpc3QgaW4gdGhlIGZ1dHVyZVxuQnVmZmVyLnByb3RvdHlwZS5sZW5ndGggPSB1bmRlZmluZWRcbkJ1ZmZlci5wcm90b3R5cGUucGFyZW50ID0gdW5kZWZpbmVkXG5cbmZ1bmN0aW9uIHNsb3dUb1N0cmluZyAoZW5jb2RpbmcsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcblxuICBzdGFydCA9IHN0YXJ0IHwgMFxuICBlbmQgPSBlbmQgPT09IHVuZGVmaW5lZCB8fCBlbmQgPT09IEluZmluaXR5ID8gdGhpcy5sZW5ndGggOiBlbmQgfCAwXG5cbiAgaWYgKCFlbmNvZGluZykgZW5jb2RpbmcgPSAndXRmOCdcbiAgaWYgKHN0YXJ0IDwgMCkgc3RhcnQgPSAwXG4gIGlmIChlbmQgPiB0aGlzLmxlbmd0aCkgZW5kID0gdGhpcy5sZW5ndGhcbiAgaWYgKGVuZCA8PSBzdGFydCkgcmV0dXJuICcnXG5cbiAgd2hpbGUgKHRydWUpIHtcbiAgICBzd2l0Y2ggKGVuY29kaW5nKSB7XG4gICAgICBjYXNlICdoZXgnOlxuICAgICAgICByZXR1cm4gaGV4U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAndXRmOCc6XG4gICAgICBjYXNlICd1dGYtOCc6XG4gICAgICAgIHJldHVybiB1dGY4U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnYXNjaWknOlxuICAgICAgICByZXR1cm4gYXNjaWlTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICdiaW5hcnknOlxuICAgICAgICByZXR1cm4gYmluYXJ5U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgcmV0dXJuIGJhc2U2NFNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ3VjczInOlxuICAgICAgY2FzZSAndWNzLTInOlxuICAgICAgY2FzZSAndXRmMTZsZSc6XG4gICAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICAgIHJldHVybiB1dGYxNmxlU2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGxvd2VyZWRDYXNlKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdVbmtub3duIGVuY29kaW5nOiAnICsgZW5jb2RpbmcpXG4gICAgICAgIGVuY29kaW5nID0gKGVuY29kaW5nICsgJycpLnRvTG93ZXJDYXNlKClcbiAgICAgICAgbG93ZXJlZENhc2UgPSB0cnVlXG4gICAgfVxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUudG9TdHJpbmcgPSBmdW5jdGlvbiB0b1N0cmluZyAoKSB7XG4gIHZhciBsZW5ndGggPSB0aGlzLmxlbmd0aCB8IDBcbiAgaWYgKGxlbmd0aCA9PT0gMCkgcmV0dXJuICcnXG4gIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAwKSByZXR1cm4gdXRmOFNsaWNlKHRoaXMsIDAsIGxlbmd0aClcbiAgcmV0dXJuIHNsb3dUb1N0cmluZy5hcHBseSh0aGlzLCBhcmd1bWVudHMpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuZXF1YWxzID0gZnVuY3Rpb24gZXF1YWxzIChiKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGIpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudCBtdXN0IGJlIGEgQnVmZmVyJylcbiAgaWYgKHRoaXMgPT09IGIpIHJldHVybiB0cnVlXG4gIHJldHVybiBCdWZmZXIuY29tcGFyZSh0aGlzLCBiKSA9PT0gMFxufVxuXG5CdWZmZXIucHJvdG90eXBlLmluc3BlY3QgPSBmdW5jdGlvbiBpbnNwZWN0ICgpIHtcbiAgdmFyIHN0ciA9ICcnXG4gIHZhciBtYXggPSBleHBvcnRzLklOU1BFQ1RfTUFYX0JZVEVTXG4gIGlmICh0aGlzLmxlbmd0aCA+IDApIHtcbiAgICBzdHIgPSB0aGlzLnRvU3RyaW5nKCdoZXgnLCAwLCBtYXgpLm1hdGNoKC8uezJ9L2cpLmpvaW4oJyAnKVxuICAgIGlmICh0aGlzLmxlbmd0aCA+IG1heCkgc3RyICs9ICcgLi4uICdcbiAgfVxuICByZXR1cm4gJzxCdWZmZXIgJyArIHN0ciArICc+J1xufVxuXG5CdWZmZXIucHJvdG90eXBlLmNvbXBhcmUgPSBmdW5jdGlvbiBjb21wYXJlIChiKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGIpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudCBtdXN0IGJlIGEgQnVmZmVyJylcbiAgaWYgKHRoaXMgPT09IGIpIHJldHVybiAwXG4gIHJldHVybiBCdWZmZXIuY29tcGFyZSh0aGlzLCBiKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLmluZGV4T2YgPSBmdW5jdGlvbiBpbmRleE9mICh2YWwsIGJ5dGVPZmZzZXQpIHtcbiAgaWYgKGJ5dGVPZmZzZXQgPiAweDdmZmZmZmZmKSBieXRlT2Zmc2V0ID0gMHg3ZmZmZmZmZlxuICBlbHNlIGlmIChieXRlT2Zmc2V0IDwgLTB4ODAwMDAwMDApIGJ5dGVPZmZzZXQgPSAtMHg4MDAwMDAwMFxuICBieXRlT2Zmc2V0ID4+PSAwXG5cbiAgaWYgKHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm4gLTFcbiAgaWYgKGJ5dGVPZmZzZXQgPj0gdGhpcy5sZW5ndGgpIHJldHVybiAtMVxuXG4gIC8vIE5lZ2F0aXZlIG9mZnNldHMgc3RhcnQgZnJvbSB0aGUgZW5kIG9mIHRoZSBidWZmZXJcbiAgaWYgKGJ5dGVPZmZzZXQgPCAwKSBieXRlT2Zmc2V0ID0gTWF0aC5tYXgodGhpcy5sZW5ndGggKyBieXRlT2Zmc2V0LCAwKVxuXG4gIGlmICh0eXBlb2YgdmFsID09PSAnc3RyaW5nJykge1xuICAgIGlmICh2YWwubGVuZ3RoID09PSAwKSByZXR1cm4gLTEgLy8gc3BlY2lhbCBjYXNlOiBsb29raW5nIGZvciBlbXB0eSBzdHJpbmcgYWx3YXlzIGZhaWxzXG4gICAgcmV0dXJuIFN0cmluZy5wcm90b3R5cGUuaW5kZXhPZi5jYWxsKHRoaXMsIHZhbCwgYnl0ZU9mZnNldClcbiAgfVxuICBpZiAoQnVmZmVyLmlzQnVmZmVyKHZhbCkpIHtcbiAgICByZXR1cm4gYXJyYXlJbmRleE9mKHRoaXMsIHZhbCwgYnl0ZU9mZnNldClcbiAgfVxuICBpZiAodHlwZW9mIHZhbCA9PT0gJ251bWJlcicpIHtcbiAgICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQgJiYgVWludDhBcnJheS5wcm90b3R5cGUuaW5kZXhPZiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgcmV0dXJuIFVpbnQ4QXJyYXkucHJvdG90eXBlLmluZGV4T2YuY2FsbCh0aGlzLCB2YWwsIGJ5dGVPZmZzZXQpXG4gICAgfVxuICAgIHJldHVybiBhcnJheUluZGV4T2YodGhpcywgWyB2YWwgXSwgYnl0ZU9mZnNldClcbiAgfVxuXG4gIGZ1bmN0aW9uIGFycmF5SW5kZXhPZiAoYXJyLCB2YWwsIGJ5dGVPZmZzZXQpIHtcbiAgICB2YXIgZm91bmRJbmRleCA9IC0xXG4gICAgZm9yICh2YXIgaSA9IDA7IGJ5dGVPZmZzZXQgKyBpIDwgYXJyLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAoYXJyW2J5dGVPZmZzZXQgKyBpXSA9PT0gdmFsW2ZvdW5kSW5kZXggPT09IC0xID8gMCA6IGkgLSBmb3VuZEluZGV4XSkge1xuICAgICAgICBpZiAoZm91bmRJbmRleCA9PT0gLTEpIGZvdW5kSW5kZXggPSBpXG4gICAgICAgIGlmIChpIC0gZm91bmRJbmRleCArIDEgPT09IHZhbC5sZW5ndGgpIHJldHVybiBieXRlT2Zmc2V0ICsgZm91bmRJbmRleFxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZm91bmRJbmRleCA9IC0xXG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiAtMVxuICB9XG5cbiAgdGhyb3cgbmV3IFR5cGVFcnJvcigndmFsIG11c3QgYmUgc3RyaW5nLCBudW1iZXIgb3IgQnVmZmVyJylcbn1cblxuLy8gYGdldGAgaXMgZGVwcmVjYXRlZFxuQnVmZmVyLnByb3RvdHlwZS5nZXQgPSBmdW5jdGlvbiBnZXQgKG9mZnNldCkge1xuICBjb25zb2xlLmxvZygnLmdldCgpIGlzIGRlcHJlY2F0ZWQuIEFjY2VzcyB1c2luZyBhcnJheSBpbmRleGVzIGluc3RlYWQuJylcbiAgcmV0dXJuIHRoaXMucmVhZFVJbnQ4KG9mZnNldClcbn1cblxuLy8gYHNldGAgaXMgZGVwcmVjYXRlZFxuQnVmZmVyLnByb3RvdHlwZS5zZXQgPSBmdW5jdGlvbiBzZXQgKHYsIG9mZnNldCkge1xuICBjb25zb2xlLmxvZygnLnNldCgpIGlzIGRlcHJlY2F0ZWQuIEFjY2VzcyB1c2luZyBhcnJheSBpbmRleGVzIGluc3RlYWQuJylcbiAgcmV0dXJuIHRoaXMud3JpdGVVSW50OCh2LCBvZmZzZXQpXG59XG5cbmZ1bmN0aW9uIGhleFdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgb2Zmc2V0ID0gTnVtYmVyKG9mZnNldCkgfHwgMFxuICB2YXIgcmVtYWluaW5nID0gYnVmLmxlbmd0aCAtIG9mZnNldFxuICBpZiAoIWxlbmd0aCkge1xuICAgIGxlbmd0aCA9IHJlbWFpbmluZ1xuICB9IGVsc2Uge1xuICAgIGxlbmd0aCA9IE51bWJlcihsZW5ndGgpXG4gICAgaWYgKGxlbmd0aCA+IHJlbWFpbmluZykge1xuICAgICAgbGVuZ3RoID0gcmVtYWluaW5nXG4gICAgfVxuICB9XG5cbiAgLy8gbXVzdCBiZSBhbiBldmVuIG51bWJlciBvZiBkaWdpdHNcbiAgdmFyIHN0ckxlbiA9IHN0cmluZy5sZW5ndGhcbiAgaWYgKHN0ckxlbiAlIDIgIT09IDApIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBoZXggc3RyaW5nJylcblxuICBpZiAobGVuZ3RoID4gc3RyTGVuIC8gMikge1xuICAgIGxlbmd0aCA9IHN0ckxlbiAvIDJcbiAgfVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIHBhcnNlZCA9IHBhcnNlSW50KHN0cmluZy5zdWJzdHIoaSAqIDIsIDIpLCAxNilcbiAgICBpZiAoaXNOYU4ocGFyc2VkKSkgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGhleCBzdHJpbmcnKVxuICAgIGJ1ZltvZmZzZXQgKyBpXSA9IHBhcnNlZFxuICB9XG4gIHJldHVybiBpXG59XG5cbmZ1bmN0aW9uIHV0ZjhXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKHV0ZjhUb0J5dGVzKHN0cmluZywgYnVmLmxlbmd0aCAtIG9mZnNldCksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIGFzY2lpV3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcihhc2NpaVRvQnl0ZXMoc3RyaW5nKSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gYmluYXJ5V3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYXNjaWlXcml0ZShidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIGJhc2U2NFdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIoYmFzZTY0VG9CeXRlcyhzdHJpbmcpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiB1Y3MyV3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcih1dGYxNmxlVG9CeXRlcyhzdHJpbmcsIGJ1Zi5sZW5ndGggLSBvZmZzZXQpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlID0gZnVuY3Rpb24gd3JpdGUgKHN0cmluZywgb2Zmc2V0LCBsZW5ndGgsIGVuY29kaW5nKSB7XG4gIC8vIEJ1ZmZlciN3cml0ZShzdHJpbmcpXG4gIGlmIChvZmZzZXQgPT09IHVuZGVmaW5lZCkge1xuICAgIGVuY29kaW5nID0gJ3V0ZjgnXG4gICAgbGVuZ3RoID0gdGhpcy5sZW5ndGhcbiAgICBvZmZzZXQgPSAwXG4gIC8vIEJ1ZmZlciN3cml0ZShzdHJpbmcsIGVuY29kaW5nKVxuICB9IGVsc2UgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkICYmIHR5cGVvZiBvZmZzZXQgPT09ICdzdHJpbmcnKSB7XG4gICAgZW5jb2RpbmcgPSBvZmZzZXRcbiAgICBsZW5ndGggPSB0aGlzLmxlbmd0aFxuICAgIG9mZnNldCA9IDBcbiAgLy8gQnVmZmVyI3dyaXRlKHN0cmluZywgb2Zmc2V0WywgbGVuZ3RoXVssIGVuY29kaW5nXSlcbiAgfSBlbHNlIGlmIChpc0Zpbml0ZShvZmZzZXQpKSB7XG4gICAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICAgIGlmIChpc0Zpbml0ZShsZW5ndGgpKSB7XG4gICAgICBsZW5ndGggPSBsZW5ndGggfCAwXG4gICAgICBpZiAoZW5jb2RpbmcgPT09IHVuZGVmaW5lZCkgZW5jb2RpbmcgPSAndXRmOCdcbiAgICB9IGVsc2Uge1xuICAgICAgZW5jb2RpbmcgPSBsZW5ndGhcbiAgICAgIGxlbmd0aCA9IHVuZGVmaW5lZFxuICAgIH1cbiAgLy8gbGVnYWN5IHdyaXRlKHN0cmluZywgZW5jb2RpbmcsIG9mZnNldCwgbGVuZ3RoKSAtIHJlbW92ZSBpbiB2MC4xM1xuICB9IGVsc2Uge1xuICAgIHZhciBzd2FwID0gZW5jb2RpbmdcbiAgICBlbmNvZGluZyA9IG9mZnNldFxuICAgIG9mZnNldCA9IGxlbmd0aCB8IDBcbiAgICBsZW5ndGggPSBzd2FwXG4gIH1cblxuICB2YXIgcmVtYWluaW5nID0gdGhpcy5sZW5ndGggLSBvZmZzZXRcbiAgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkIHx8IGxlbmd0aCA+IHJlbWFpbmluZykgbGVuZ3RoID0gcmVtYWluaW5nXG5cbiAgaWYgKChzdHJpbmcubGVuZ3RoID4gMCAmJiAobGVuZ3RoIDwgMCB8fCBvZmZzZXQgPCAwKSkgfHwgb2Zmc2V0ID4gdGhpcy5sZW5ndGgpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignYXR0ZW1wdCB0byB3cml0ZSBvdXRzaWRlIGJ1ZmZlciBib3VuZHMnKVxuICB9XG5cbiAgaWYgKCFlbmNvZGluZykgZW5jb2RpbmcgPSAndXRmOCdcblxuICB2YXIgbG93ZXJlZENhc2UgPSBmYWxzZVxuICBmb3IgKDs7KSB7XG4gICAgc3dpdGNoIChlbmNvZGluZykge1xuICAgICAgY2FzZSAnaGV4JzpcbiAgICAgICAgcmV0dXJuIGhleFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgICByZXR1cm4gdXRmOFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgICAgcmV0dXJuIGFzY2lpV3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAnYmluYXJ5JzpcbiAgICAgICAgcmV0dXJuIGJpbmFyeVdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgICAgIC8vIFdhcm5pbmc6IG1heExlbmd0aCBub3QgdGFrZW4gaW50byBhY2NvdW50IGluIGJhc2U2NFdyaXRlXG4gICAgICAgIHJldHVybiBiYXNlNjRXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICd1Y3MyJzpcbiAgICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgICByZXR1cm4gdWNzMldyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGlmIChsb3dlcmVkQ2FzZSkgdGhyb3cgbmV3IFR5cGVFcnJvcignVW5rbm93biBlbmNvZGluZzogJyArIGVuY29kaW5nKVxuICAgICAgICBlbmNvZGluZyA9ICgnJyArIGVuY29kaW5nKS50b0xvd2VyQ2FzZSgpXG4gICAgICAgIGxvd2VyZWRDYXNlID0gdHJ1ZVxuICAgIH1cbiAgfVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnRvSlNPTiA9IGZ1bmN0aW9uIHRvSlNPTiAoKSB7XG4gIHJldHVybiB7XG4gICAgdHlwZTogJ0J1ZmZlcicsXG4gICAgZGF0YTogQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwodGhpcy5fYXJyIHx8IHRoaXMsIDApXG4gIH1cbn1cblxuZnVuY3Rpb24gYmFzZTY0U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICBpZiAoc3RhcnQgPT09IDAgJiYgZW5kID09PSBidWYubGVuZ3RoKSB7XG4gICAgcmV0dXJuIGJhc2U2NC5mcm9tQnl0ZUFycmF5KGJ1ZilcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gYmFzZTY0LmZyb21CeXRlQXJyYXkoYnVmLnNsaWNlKHN0YXJ0LCBlbmQpKVxuICB9XG59XG5cbmZ1bmN0aW9uIHV0ZjhTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIGVuZCA9IE1hdGgubWluKGJ1Zi5sZW5ndGgsIGVuZClcbiAgdmFyIHJlcyA9IFtdXG5cbiAgdmFyIGkgPSBzdGFydFxuICB3aGlsZSAoaSA8IGVuZCkge1xuICAgIHZhciBmaXJzdEJ5dGUgPSBidWZbaV1cbiAgICB2YXIgY29kZVBvaW50ID0gbnVsbFxuICAgIHZhciBieXRlc1BlclNlcXVlbmNlID0gKGZpcnN0Qnl0ZSA+IDB4RUYpID8gNFxuICAgICAgOiAoZmlyc3RCeXRlID4gMHhERikgPyAzXG4gICAgICA6IChmaXJzdEJ5dGUgPiAweEJGKSA/IDJcbiAgICAgIDogMVxuXG4gICAgaWYgKGkgKyBieXRlc1BlclNlcXVlbmNlIDw9IGVuZCkge1xuICAgICAgdmFyIHNlY29uZEJ5dGUsIHRoaXJkQnl0ZSwgZm91cnRoQnl0ZSwgdGVtcENvZGVQb2ludFxuXG4gICAgICBzd2l0Y2ggKGJ5dGVzUGVyU2VxdWVuY2UpIHtcbiAgICAgICAgY2FzZSAxOlxuICAgICAgICAgIGlmIChmaXJzdEJ5dGUgPCAweDgwKSB7XG4gICAgICAgICAgICBjb2RlUG9pbnQgPSBmaXJzdEJ5dGVcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAyOlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgaWYgKChzZWNvbmRCeXRlICYgMHhDMCkgPT09IDB4ODApIHtcbiAgICAgICAgICAgIHRlbXBDb2RlUG9pbnQgPSAoZmlyc3RCeXRlICYgMHgxRikgPDwgMHg2IHwgKHNlY29uZEJ5dGUgJiAweDNGKVxuICAgICAgICAgICAgaWYgKHRlbXBDb2RlUG9pbnQgPiAweDdGKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAzOlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgdGhpcmRCeXRlID0gYnVmW2kgKyAyXVxuICAgICAgICAgIGlmICgoc2Vjb25kQnl0ZSAmIDB4QzApID09PSAweDgwICYmICh0aGlyZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCkge1xuICAgICAgICAgICAgdGVtcENvZGVQb2ludCA9IChmaXJzdEJ5dGUgJiAweEYpIDw8IDB4QyB8IChzZWNvbmRCeXRlICYgMHgzRikgPDwgMHg2IHwgKHRoaXJkQnl0ZSAmIDB4M0YpXG4gICAgICAgICAgICBpZiAodGVtcENvZGVQb2ludCA+IDB4N0ZGICYmICh0ZW1wQ29kZVBvaW50IDwgMHhEODAwIHx8IHRlbXBDb2RlUG9pbnQgPiAweERGRkYpKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSA0OlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgdGhpcmRCeXRlID0gYnVmW2kgKyAyXVxuICAgICAgICAgIGZvdXJ0aEJ5dGUgPSBidWZbaSArIDNdXG4gICAgICAgICAgaWYgKChzZWNvbmRCeXRlICYgMHhDMCkgPT09IDB4ODAgJiYgKHRoaXJkQnl0ZSAmIDB4QzApID09PSAweDgwICYmIChmb3VydGhCeXRlICYgMHhDMCkgPT09IDB4ODApIHtcbiAgICAgICAgICAgIHRlbXBDb2RlUG9pbnQgPSAoZmlyc3RCeXRlICYgMHhGKSA8PCAweDEyIHwgKHNlY29uZEJ5dGUgJiAweDNGKSA8PCAweEMgfCAodGhpcmRCeXRlICYgMHgzRikgPDwgMHg2IHwgKGZvdXJ0aEJ5dGUgJiAweDNGKVxuICAgICAgICAgICAgaWYgKHRlbXBDb2RlUG9pbnQgPiAweEZGRkYgJiYgdGVtcENvZGVQb2ludCA8IDB4MTEwMDAwKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGNvZGVQb2ludCA9PT0gbnVsbCkge1xuICAgICAgLy8gd2UgZGlkIG5vdCBnZW5lcmF0ZSBhIHZhbGlkIGNvZGVQb2ludCBzbyBpbnNlcnQgYVxuICAgICAgLy8gcmVwbGFjZW1lbnQgY2hhciAoVStGRkZEKSBhbmQgYWR2YW5jZSBvbmx5IDEgYnl0ZVxuICAgICAgY29kZVBvaW50ID0gMHhGRkZEXG4gICAgICBieXRlc1BlclNlcXVlbmNlID0gMVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50ID4gMHhGRkZGKSB7XG4gICAgICAvLyBlbmNvZGUgdG8gdXRmMTYgKHN1cnJvZ2F0ZSBwYWlyIGRhbmNlKVxuICAgICAgY29kZVBvaW50IC09IDB4MTAwMDBcbiAgICAgIHJlcy5wdXNoKGNvZGVQb2ludCA+Pj4gMTAgJiAweDNGRiB8IDB4RDgwMClcbiAgICAgIGNvZGVQb2ludCA9IDB4REMwMCB8IGNvZGVQb2ludCAmIDB4M0ZGXG4gICAgfVxuXG4gICAgcmVzLnB1c2goY29kZVBvaW50KVxuICAgIGkgKz0gYnl0ZXNQZXJTZXF1ZW5jZVxuICB9XG5cbiAgcmV0dXJuIGRlY29kZUNvZGVQb2ludHNBcnJheShyZXMpXG59XG5cbi8vIEJhc2VkIG9uIGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9hLzIyNzQ3MjcyLzY4MDc0MiwgdGhlIGJyb3dzZXIgd2l0aFxuLy8gdGhlIGxvd2VzdCBsaW1pdCBpcyBDaHJvbWUsIHdpdGggMHgxMDAwMCBhcmdzLlxuLy8gV2UgZ28gMSBtYWduaXR1ZGUgbGVzcywgZm9yIHNhZmV0eVxudmFyIE1BWF9BUkdVTUVOVFNfTEVOR1RIID0gMHgxMDAwXG5cbmZ1bmN0aW9uIGRlY29kZUNvZGVQb2ludHNBcnJheSAoY29kZVBvaW50cykge1xuICB2YXIgbGVuID0gY29kZVBvaW50cy5sZW5ndGhcbiAgaWYgKGxlbiA8PSBNQVhfQVJHVU1FTlRTX0xFTkdUSCkge1xuICAgIHJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KFN0cmluZywgY29kZVBvaW50cykgLy8gYXZvaWQgZXh0cmEgc2xpY2UoKVxuICB9XG5cbiAgLy8gRGVjb2RlIGluIGNodW5rcyB0byBhdm9pZCBcImNhbGwgc3RhY2sgc2l6ZSBleGNlZWRlZFwiLlxuICB2YXIgcmVzID0gJydcbiAgdmFyIGkgPSAwXG4gIHdoaWxlIChpIDwgbGVuKSB7XG4gICAgcmVzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkoXG4gICAgICBTdHJpbmcsXG4gICAgICBjb2RlUG9pbnRzLnNsaWNlKGksIGkgKz0gTUFYX0FSR1VNRU5UU19MRU5HVEgpXG4gICAgKVxuICB9XG4gIHJldHVybiByZXNcbn1cblxuZnVuY3Rpb24gYXNjaWlTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciByZXQgPSAnJ1xuICBlbmQgPSBNYXRoLm1pbihidWYubGVuZ3RoLCBlbmQpXG5cbiAgZm9yICh2YXIgaSA9IHN0YXJ0OyBpIDwgZW5kOyBpKyspIHtcbiAgICByZXQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShidWZbaV0gJiAweDdGKVxuICB9XG4gIHJldHVybiByZXRcbn1cblxuZnVuY3Rpb24gYmluYXJ5U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgcmV0ID0gJydcbiAgZW5kID0gTWF0aC5taW4oYnVmLmxlbmd0aCwgZW5kKVxuXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgcmV0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYnVmW2ldKVxuICB9XG4gIHJldHVybiByZXRcbn1cblxuZnVuY3Rpb24gaGV4U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgbGVuID0gYnVmLmxlbmd0aFxuXG4gIGlmICghc3RhcnQgfHwgc3RhcnQgPCAwKSBzdGFydCA9IDBcbiAgaWYgKCFlbmQgfHwgZW5kIDwgMCB8fCBlbmQgPiBsZW4pIGVuZCA9IGxlblxuXG4gIHZhciBvdXQgPSAnJ1xuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgIG91dCArPSB0b0hleChidWZbaV0pXG4gIH1cbiAgcmV0dXJuIG91dFxufVxuXG5mdW5jdGlvbiB1dGYxNmxlU2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgYnl0ZXMgPSBidWYuc2xpY2Uoc3RhcnQsIGVuZClcbiAgdmFyIHJlcyA9ICcnXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgYnl0ZXMubGVuZ3RoOyBpICs9IDIpIHtcbiAgICByZXMgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShieXRlc1tpXSArIGJ5dGVzW2kgKyAxXSAqIDI1NilcbiAgfVxuICByZXR1cm4gcmVzXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuc2xpY2UgPSBmdW5jdGlvbiBzbGljZSAoc3RhcnQsIGVuZCkge1xuICB2YXIgbGVuID0gdGhpcy5sZW5ndGhcbiAgc3RhcnQgPSB+fnN0YXJ0XG4gIGVuZCA9IGVuZCA9PT0gdW5kZWZpbmVkID8gbGVuIDogfn5lbmRcblxuICBpZiAoc3RhcnQgPCAwKSB7XG4gICAgc3RhcnQgKz0gbGVuXG4gICAgaWYgKHN0YXJ0IDwgMCkgc3RhcnQgPSAwXG4gIH0gZWxzZSBpZiAoc3RhcnQgPiBsZW4pIHtcbiAgICBzdGFydCA9IGxlblxuICB9XG5cbiAgaWYgKGVuZCA8IDApIHtcbiAgICBlbmQgKz0gbGVuXG4gICAgaWYgKGVuZCA8IDApIGVuZCA9IDBcbiAgfSBlbHNlIGlmIChlbmQgPiBsZW4pIHtcbiAgICBlbmQgPSBsZW5cbiAgfVxuXG4gIGlmIChlbmQgPCBzdGFydCkgZW5kID0gc3RhcnRcblxuICB2YXIgbmV3QnVmXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIG5ld0J1ZiA9IEJ1ZmZlci5fYXVnbWVudCh0aGlzLnN1YmFycmF5KHN0YXJ0LCBlbmQpKVxuICB9IGVsc2Uge1xuICAgIHZhciBzbGljZUxlbiA9IGVuZCAtIHN0YXJ0XG4gICAgbmV3QnVmID0gbmV3IEJ1ZmZlcihzbGljZUxlbiwgdW5kZWZpbmVkKVxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2xpY2VMZW47IGkrKykge1xuICAgICAgbmV3QnVmW2ldID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9XG5cbiAgaWYgKG5ld0J1Zi5sZW5ndGgpIG5ld0J1Zi5wYXJlbnQgPSB0aGlzLnBhcmVudCB8fCB0aGlzXG5cbiAgcmV0dXJuIG5ld0J1ZlxufVxuXG4vKlxuICogTmVlZCB0byBtYWtlIHN1cmUgdGhhdCBidWZmZXIgaXNuJ3QgdHJ5aW5nIHRvIHdyaXRlIG91dCBvZiBib3VuZHMuXG4gKi9cbmZ1bmN0aW9uIGNoZWNrT2Zmc2V0IChvZmZzZXQsIGV4dCwgbGVuZ3RoKSB7XG4gIGlmICgob2Zmc2V0ICUgMSkgIT09IDAgfHwgb2Zmc2V0IDwgMCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ29mZnNldCBpcyBub3QgdWludCcpXG4gIGlmIChvZmZzZXQgKyBleHQgPiBsZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdUcnlpbmcgdG8gYWNjZXNzIGJleW9uZCBidWZmZXIgbGVuZ3RoJylcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludExFID0gZnVuY3Rpb24gcmVhZFVJbnRMRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldF1cbiAgdmFyIG11bCA9IDFcbiAgdmFyIGkgPSAwXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgaV0gKiBtdWxcbiAgfVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludEJFID0gZnVuY3Rpb24gcmVhZFVJbnRCRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcbiAgfVxuXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldCArIC0tYnl0ZUxlbmd0aF1cbiAgdmFyIG11bCA9IDFcbiAgd2hpbGUgKGJ5dGVMZW5ndGggPiAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgLS1ieXRlTGVuZ3RoXSAqIG11bFxuICB9XG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50OCA9IGZ1bmN0aW9uIHJlYWRVSW50OCAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDEsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gdGhpc1tvZmZzZXRdXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQxNkxFID0gZnVuY3Rpb24gcmVhZFVJbnQxNkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiB0aGlzW29mZnNldF0gfCAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MTZCRSA9IGZ1bmN0aW9uIHJlYWRVSW50MTZCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSA8PCA4KSB8IHRoaXNbb2Zmc2V0ICsgMV1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDMyTEUgPSBmdW5jdGlvbiByZWFkVUludDMyTEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKCh0aGlzW29mZnNldF0pIHxcbiAgICAgICh0aGlzW29mZnNldCArIDFdIDw8IDgpIHxcbiAgICAgICh0aGlzW29mZnNldCArIDJdIDw8IDE2KSkgK1xuICAgICAgKHRoaXNbb2Zmc2V0ICsgM10gKiAweDEwMDAwMDApXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQzMkJFID0gZnVuY3Rpb24gcmVhZFVJbnQzMkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0gKiAweDEwMDAwMDApICtcbiAgICAoKHRoaXNbb2Zmc2V0ICsgMV0gPDwgMTYpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCA4KSB8XG4gICAgdGhpc1tvZmZzZXQgKyAzXSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50TEUgPSBmdW5jdGlvbiByZWFkSW50TEUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcblxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXRdXG4gIHZhciBtdWwgPSAxXG4gIHZhciBpID0gMFxuICB3aGlsZSAoKytpIDwgYnl0ZUxlbmd0aCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIGldICogbXVsXG4gIH1cbiAgbXVsICo9IDB4ODBcblxuICBpZiAodmFsID49IG11bCkgdmFsIC09IE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50QkUgPSBmdW5jdGlvbiByZWFkSW50QkUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcblxuICB2YXIgaSA9IGJ5dGVMZW5ndGhcbiAgdmFyIG11bCA9IDFcbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0ICsgLS1pXVxuICB3aGlsZSAoaSA+IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyAtLWldICogbXVsXG4gIH1cbiAgbXVsICo9IDB4ODBcblxuICBpZiAodmFsID49IG11bCkgdmFsIC09IE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50OCA9IGZ1bmN0aW9uIHJlYWRJbnQ4IChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMSwgdGhpcy5sZW5ndGgpXG4gIGlmICghKHRoaXNbb2Zmc2V0XSAmIDB4ODApKSByZXR1cm4gKHRoaXNbb2Zmc2V0XSlcbiAgcmV0dXJuICgoMHhmZiAtIHRoaXNbb2Zmc2V0XSArIDEpICogLTEpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDE2TEUgPSBmdW5jdGlvbiByZWFkSW50MTZMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXRdIHwgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOClcbiAgcmV0dXJuICh2YWwgJiAweDgwMDApID8gdmFsIHwgMHhGRkZGMDAwMCA6IHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQxNkJFID0gZnVuY3Rpb24gcmVhZEludDE2QkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0ICsgMV0gfCAodGhpc1tvZmZzZXRdIDw8IDgpXG4gIHJldHVybiAodmFsICYgMHg4MDAwKSA/IHZhbCB8IDB4RkZGRjAwMDAgOiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MzJMRSA9IGZ1bmN0aW9uIHJlYWRJbnQzMkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0pIHxcbiAgICAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgMTYpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAzXSA8PCAyNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MzJCRSA9IGZ1bmN0aW9uIHJlYWRJbnQzMkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0gPDwgMjQpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAxXSA8PCAxNikgfFxuICAgICh0aGlzW29mZnNldCArIDJdIDw8IDgpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAzXSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRmxvYXRMRSA9IGZ1bmN0aW9uIHJlYWRGbG9hdExFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCB0cnVlLCAyMywgNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRmxvYXRCRSA9IGZ1bmN0aW9uIHJlYWRGbG9hdEJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCBmYWxzZSwgMjMsIDQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZERvdWJsZUxFID0gZnVuY3Rpb24gcmVhZERvdWJsZUxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgOCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCB0cnVlLCA1MiwgOClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRG91YmxlQkUgPSBmdW5jdGlvbiByZWFkRG91YmxlQkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA4LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIGZhbHNlLCA1MiwgOClcbn1cblxuZnVuY3Rpb24gY2hlY2tJbnQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgZXh0LCBtYXgsIG1pbikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihidWYpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdidWZmZXIgbXVzdCBiZSBhIEJ1ZmZlciBpbnN0YW5jZScpXG4gIGlmICh2YWx1ZSA+IG1heCB8fCB2YWx1ZSA8IG1pbikgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3ZhbHVlIGlzIG91dCBvZiBib3VuZHMnKVxuICBpZiAob2Zmc2V0ICsgZXh0ID4gYnVmLmxlbmd0aCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2luZGV4IG91dCBvZiByYW5nZScpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50TEUgPSBmdW5jdGlvbiB3cml0ZVVJbnRMRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpLCAwKVxuXG4gIHZhciBtdWwgPSAxXG4gIHZhciBpID0gMFxuICB0aGlzW29mZnNldF0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKCsraSA8IGJ5dGVMZW5ndGggJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB0aGlzW29mZnNldCArIGldID0gKHZhbHVlIC8gbXVsKSAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50QkUgPSBmdW5jdGlvbiB3cml0ZVVJbnRCRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpLCAwKVxuXG4gIHZhciBpID0gYnl0ZUxlbmd0aCAtIDFcbiAgdmFyIG11bCA9IDFcbiAgdGhpc1tvZmZzZXQgKyBpXSA9IHZhbHVlICYgMHhGRlxuICB3aGlsZSAoLS1pID49IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB0aGlzW29mZnNldCArIGldID0gKHZhbHVlIC8gbXVsKSAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50OCA9IGZ1bmN0aW9uIHdyaXRlVUludDggKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMSwgMHhmZiwgMClcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkgdmFsdWUgPSBNYXRoLmZsb29yKHZhbHVlKVxuICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICByZXR1cm4gb2Zmc2V0ICsgMVxufVxuXG5mdW5jdGlvbiBvYmplY3RXcml0ZVVJbnQxNiAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4pIHtcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmYgKyB2YWx1ZSArIDFcbiAgZm9yICh2YXIgaSA9IDAsIGogPSBNYXRoLm1pbihidWYubGVuZ3RoIC0gb2Zmc2V0LCAyKTsgaSA8IGo7IGkrKykge1xuICAgIGJ1ZltvZmZzZXQgKyBpXSA9ICh2YWx1ZSAmICgweGZmIDw8ICg4ICogKGxpdHRsZUVuZGlhbiA/IGkgOiAxIC0gaSkpKSkgPj4+XG4gICAgICAobGl0dGxlRW5kaWFuID8gaSA6IDEgLSBpKSAqIDhcbiAgfVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDE2TEUgPSBmdW5jdGlvbiB3cml0ZVVJbnQxNkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4ZmZmZiwgMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQxNkJFID0gZnVuY3Rpb24gd3JpdGVVSW50MTZCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweGZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgMlxufVxuXG5mdW5jdGlvbiBvYmplY3RXcml0ZVVJbnQzMiAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4pIHtcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmZmZmZmICsgdmFsdWUgKyAxXG4gIGZvciAodmFyIGkgPSAwLCBqID0gTWF0aC5taW4oYnVmLmxlbmd0aCAtIG9mZnNldCwgNCk7IGkgPCBqOyBpKyspIHtcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSAodmFsdWUgPj4+IChsaXR0bGVFbmRpYW4gPyBpIDogMyAtIGkpICogOCkgJiAweGZmXG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQzMkxFID0gZnVuY3Rpb24gd3JpdGVVSW50MzJMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweGZmZmZmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlID4+PiAyNClcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDMyQkUgPSBmdW5jdGlvbiB3cml0ZVVJbnQzMkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4ZmZmZmZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50TEUgPSBmdW5jdGlvbiB3cml0ZUludExFICh2YWx1ZSwgb2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICB2YXIgbGltaXQgPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aCAtIDEpXG5cbiAgICBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBieXRlTGVuZ3RoLCBsaW1pdCAtIDEsIC1saW1pdClcbiAgfVxuXG4gIHZhciBpID0gMFxuICB2YXIgbXVsID0gMVxuICB2YXIgc3ViID0gdmFsdWUgPCAwID8gMSA6IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICgodmFsdWUgLyBtdWwpID4+IDApIC0gc3ViICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIG9mZnNldCArIGJ5dGVMZW5ndGhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludEJFID0gZnVuY3Rpb24gd3JpdGVJbnRCRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHZhciBzdWIgPSB2YWx1ZSA8IDAgPyAxIDogMFxuICB0aGlzW29mZnNldCArIGldID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgtLWkgPj0gMCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHRoaXNbb2Zmc2V0ICsgaV0gPSAoKHZhbHVlIC8gbXVsKSA+PiAwKSAtIHN1YiAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQ4ID0gZnVuY3Rpb24gd3JpdGVJbnQ4ICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDEsIDB4N2YsIC0weDgwKVxuICBpZiAoIUJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB2YWx1ZSA9IE1hdGguZmxvb3IodmFsdWUpXG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZiArIHZhbHVlICsgMVxuICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICByZXR1cm4gb2Zmc2V0ICsgMVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MTZMRSA9IGZ1bmN0aW9uIHdyaXRlSW50MTZMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweDdmZmYsIC0weDgwMDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQxNkJFID0gZnVuY3Rpb24gd3JpdGVJbnQxNkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4N2ZmZiwgLTB4ODAwMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQzMkxFID0gZnVuY3Rpb24gd3JpdGVJbnQzMkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4N2ZmZmZmZmYsIC0weDgwMDAwMDAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSA+Pj4gMjQpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MzJCRSA9IGZ1bmN0aW9uIHdyaXRlSW50MzJCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweDdmZmZmZmZmLCAtMHg4MDAwMDAwMClcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmZmZmZmICsgdmFsdWUgKyAxXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5mdW5jdGlvbiBjaGVja0lFRUU3NTQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgZXh0LCBtYXgsIG1pbikge1xuICBpZiAodmFsdWUgPiBtYXggfHwgdmFsdWUgPCBtaW4pIHRocm93IG5ldyBSYW5nZUVycm9yKCd2YWx1ZSBpcyBvdXQgb2YgYm91bmRzJylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGJ1Zi5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdpbmRleCBvdXQgb2YgcmFuZ2UnKVxuICBpZiAob2Zmc2V0IDwgMCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2luZGV4IG91dCBvZiByYW5nZScpXG59XG5cbmZ1bmN0aW9uIHdyaXRlRmxvYXQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tJRUVFNzU0KGJ1ZiwgdmFsdWUsIG9mZnNldCwgNCwgMy40MDI4MjM0NjYzODUyODg2ZSszOCwgLTMuNDAyODIzNDY2Mzg1Mjg4NmUrMzgpXG4gIH1cbiAgaWVlZTc1NC53cml0ZShidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgMjMsIDQpXG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVGbG9hdExFID0gZnVuY3Rpb24gd3JpdGVGbG9hdExFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVGbG9hdCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlLCBub0Fzc2VydClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUZsb2F0QkUgPSBmdW5jdGlvbiB3cml0ZUZsb2F0QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZUZsb2F0KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlLCBub0Fzc2VydClcbn1cblxuZnVuY3Rpb24gd3JpdGVEb3VibGUgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tJRUVFNzU0KGJ1ZiwgdmFsdWUsIG9mZnNldCwgOCwgMS43OTc2OTMxMzQ4NjIzMTU3RSszMDgsIC0xLjc5NzY5MzEzNDg2MjMxNTdFKzMwOClcbiAgfVxuICBpZWVlNzU0LndyaXRlKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCA1MiwgOClcbiAgcmV0dXJuIG9mZnNldCArIDhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZURvdWJsZUxFID0gZnVuY3Rpb24gd3JpdGVEb3VibGVMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRG91YmxlKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUsIG5vQXNzZXJ0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlRG91YmxlQkUgPSBmdW5jdGlvbiB3cml0ZURvdWJsZUJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVEb3VibGUodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UsIG5vQXNzZXJ0KVxufVxuXG4vLyBjb3B5KHRhcmdldEJ1ZmZlciwgdGFyZ2V0U3RhcnQ9MCwgc291cmNlU3RhcnQ9MCwgc291cmNlRW5kPWJ1ZmZlci5sZW5ndGgpXG5CdWZmZXIucHJvdG90eXBlLmNvcHkgPSBmdW5jdGlvbiBjb3B5ICh0YXJnZXQsIHRhcmdldFN0YXJ0LCBzdGFydCwgZW5kKSB7XG4gIGlmICghc3RhcnQpIHN0YXJ0ID0gMFxuICBpZiAoIWVuZCAmJiBlbmQgIT09IDApIGVuZCA9IHRoaXMubGVuZ3RoXG4gIGlmICh0YXJnZXRTdGFydCA+PSB0YXJnZXQubGVuZ3RoKSB0YXJnZXRTdGFydCA9IHRhcmdldC5sZW5ndGhcbiAgaWYgKCF0YXJnZXRTdGFydCkgdGFyZ2V0U3RhcnQgPSAwXG4gIGlmIChlbmQgPiAwICYmIGVuZCA8IHN0YXJ0KSBlbmQgPSBzdGFydFxuXG4gIC8vIENvcHkgMCBieXRlczsgd2UncmUgZG9uZVxuICBpZiAoZW5kID09PSBzdGFydCkgcmV0dXJuIDBcbiAgaWYgKHRhcmdldC5sZW5ndGggPT09IDAgfHwgdGhpcy5sZW5ndGggPT09IDApIHJldHVybiAwXG5cbiAgLy8gRmF0YWwgZXJyb3IgY29uZGl0aW9uc1xuICBpZiAodGFyZ2V0U3RhcnQgPCAwKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3RhcmdldFN0YXJ0IG91dCBvZiBib3VuZHMnKVxuICB9XG4gIGlmIChzdGFydCA8IDAgfHwgc3RhcnQgPj0gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdzb3VyY2VTdGFydCBvdXQgb2YgYm91bmRzJylcbiAgaWYgKGVuZCA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdzb3VyY2VFbmQgb3V0IG9mIGJvdW5kcycpXG5cbiAgLy8gQXJlIHdlIG9vYj9cbiAgaWYgKGVuZCA+IHRoaXMubGVuZ3RoKSBlbmQgPSB0aGlzLmxlbmd0aFxuICBpZiAodGFyZ2V0Lmxlbmd0aCAtIHRhcmdldFN0YXJ0IDwgZW5kIC0gc3RhcnQpIHtcbiAgICBlbmQgPSB0YXJnZXQubGVuZ3RoIC0gdGFyZ2V0U3RhcnQgKyBzdGFydFxuICB9XG5cbiAgdmFyIGxlbiA9IGVuZCAtIHN0YXJ0XG4gIHZhciBpXG5cbiAgaWYgKHRoaXMgPT09IHRhcmdldCAmJiBzdGFydCA8IHRhcmdldFN0YXJ0ICYmIHRhcmdldFN0YXJ0IDwgZW5kKSB7XG4gICAgLy8gZGVzY2VuZGluZyBjb3B5IGZyb20gZW5kXG4gICAgZm9yIChpID0gbGVuIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgIHRhcmdldFtpICsgdGFyZ2V0U3RhcnRdID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9IGVsc2UgaWYgKGxlbiA8IDEwMDAgfHwgIUJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gYXNjZW5kaW5nIGNvcHkgZnJvbSBzdGFydFxuICAgIGZvciAoaSA9IDA7IGkgPCBsZW47IGkrKykge1xuICAgICAgdGFyZ2V0W2kgKyB0YXJnZXRTdGFydF0gPSB0aGlzW2kgKyBzdGFydF1cbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdGFyZ2V0Ll9zZXQodGhpcy5zdWJhcnJheShzdGFydCwgc3RhcnQgKyBsZW4pLCB0YXJnZXRTdGFydClcbiAgfVxuXG4gIHJldHVybiBsZW5cbn1cblxuLy8gZmlsbCh2YWx1ZSwgc3RhcnQ9MCwgZW5kPWJ1ZmZlci5sZW5ndGgpXG5CdWZmZXIucHJvdG90eXBlLmZpbGwgPSBmdW5jdGlvbiBmaWxsICh2YWx1ZSwgc3RhcnQsIGVuZCkge1xuICBpZiAoIXZhbHVlKSB2YWx1ZSA9IDBcbiAgaWYgKCFzdGFydCkgc3RhcnQgPSAwXG4gIGlmICghZW5kKSBlbmQgPSB0aGlzLmxlbmd0aFxuXG4gIGlmIChlbmQgPCBzdGFydCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2VuZCA8IHN0YXJ0JylcblxuICAvLyBGaWxsIDAgYnl0ZXM7IHdlJ3JlIGRvbmVcbiAgaWYgKGVuZCA9PT0gc3RhcnQpIHJldHVyblxuICBpZiAodGhpcy5sZW5ndGggPT09IDApIHJldHVyblxuXG4gIGlmIChzdGFydCA8IDAgfHwgc3RhcnQgPj0gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdzdGFydCBvdXQgb2YgYm91bmRzJylcbiAgaWYgKGVuZCA8IDAgfHwgZW5kID4gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdlbmQgb3V0IG9mIGJvdW5kcycpXG5cbiAgdmFyIGlcbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicpIHtcbiAgICBmb3IgKGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgICB0aGlzW2ldID0gdmFsdWVcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdmFyIGJ5dGVzID0gdXRmOFRvQnl0ZXModmFsdWUudG9TdHJpbmcoKSlcbiAgICB2YXIgbGVuID0gYnl0ZXMubGVuZ3RoXG4gICAgZm9yIChpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgICAgdGhpc1tpXSA9IGJ5dGVzW2kgJSBsZW5dXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRoaXNcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgbmV3IGBBcnJheUJ1ZmZlcmAgd2l0aCB0aGUgKmNvcGllZCogbWVtb3J5IG9mIHRoZSBidWZmZXIgaW5zdGFuY2UuXG4gKiBBZGRlZCBpbiBOb2RlIDAuMTIuIE9ubHkgYXZhaWxhYmxlIGluIGJyb3dzZXJzIHRoYXQgc3VwcG9ydCBBcnJheUJ1ZmZlci5cbiAqL1xuQnVmZmVyLnByb3RvdHlwZS50b0FycmF5QnVmZmVyID0gZnVuY3Rpb24gdG9BcnJheUJ1ZmZlciAoKSB7XG4gIGlmICh0eXBlb2YgVWludDhBcnJheSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICAgIHJldHVybiAobmV3IEJ1ZmZlcih0aGlzKSkuYnVmZmVyXG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBidWYgPSBuZXcgVWludDhBcnJheSh0aGlzLmxlbmd0aClcbiAgICAgIGZvciAodmFyIGkgPSAwLCBsZW4gPSBidWYubGVuZ3RoOyBpIDwgbGVuOyBpICs9IDEpIHtcbiAgICAgICAgYnVmW2ldID0gdGhpc1tpXVxuICAgICAgfVxuICAgICAgcmV0dXJuIGJ1Zi5idWZmZXJcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQnVmZmVyLnRvQXJyYXlCdWZmZXIgbm90IHN1cHBvcnRlZCBpbiB0aGlzIGJyb3dzZXInKVxuICB9XG59XG5cbi8vIEhFTFBFUiBGVU5DVElPTlNcbi8vID09PT09PT09PT09PT09PT1cblxudmFyIEJQID0gQnVmZmVyLnByb3RvdHlwZVxuXG4vKipcbiAqIEF1Z21lbnQgYSBVaW50OEFycmF5ICppbnN0YW5jZSogKG5vdCB0aGUgVWludDhBcnJheSBjbGFzcyEpIHdpdGggQnVmZmVyIG1ldGhvZHNcbiAqL1xuQnVmZmVyLl9hdWdtZW50ID0gZnVuY3Rpb24gX2F1Z21lbnQgKGFycikge1xuICBhcnIuY29uc3RydWN0b3IgPSBCdWZmZXJcbiAgYXJyLl9pc0J1ZmZlciA9IHRydWVcblxuICAvLyBzYXZlIHJlZmVyZW5jZSB0byBvcmlnaW5hbCBVaW50OEFycmF5IHNldCBtZXRob2QgYmVmb3JlIG92ZXJ3cml0aW5nXG4gIGFyci5fc2V0ID0gYXJyLnNldFxuXG4gIC8vIGRlcHJlY2F0ZWRcbiAgYXJyLmdldCA9IEJQLmdldFxuICBhcnIuc2V0ID0gQlAuc2V0XG5cbiAgYXJyLndyaXRlID0gQlAud3JpdGVcbiAgYXJyLnRvU3RyaW5nID0gQlAudG9TdHJpbmdcbiAgYXJyLnRvTG9jYWxlU3RyaW5nID0gQlAudG9TdHJpbmdcbiAgYXJyLnRvSlNPTiA9IEJQLnRvSlNPTlxuICBhcnIuZXF1YWxzID0gQlAuZXF1YWxzXG4gIGFyci5jb21wYXJlID0gQlAuY29tcGFyZVxuICBhcnIuaW5kZXhPZiA9IEJQLmluZGV4T2ZcbiAgYXJyLmNvcHkgPSBCUC5jb3B5XG4gIGFyci5zbGljZSA9IEJQLnNsaWNlXG4gIGFyci5yZWFkVUludExFID0gQlAucmVhZFVJbnRMRVxuICBhcnIucmVhZFVJbnRCRSA9IEJQLnJlYWRVSW50QkVcbiAgYXJyLnJlYWRVSW50OCA9IEJQLnJlYWRVSW50OFxuICBhcnIucmVhZFVJbnQxNkxFID0gQlAucmVhZFVJbnQxNkxFXG4gIGFyci5yZWFkVUludDE2QkUgPSBCUC5yZWFkVUludDE2QkVcbiAgYXJyLnJlYWRVSW50MzJMRSA9IEJQLnJlYWRVSW50MzJMRVxuICBhcnIucmVhZFVJbnQzMkJFID0gQlAucmVhZFVJbnQzMkJFXG4gIGFyci5yZWFkSW50TEUgPSBCUC5yZWFkSW50TEVcbiAgYXJyLnJlYWRJbnRCRSA9IEJQLnJlYWRJbnRCRVxuICBhcnIucmVhZEludDggPSBCUC5yZWFkSW50OFxuICBhcnIucmVhZEludDE2TEUgPSBCUC5yZWFkSW50MTZMRVxuICBhcnIucmVhZEludDE2QkUgPSBCUC5yZWFkSW50MTZCRVxuICBhcnIucmVhZEludDMyTEUgPSBCUC5yZWFkSW50MzJMRVxuICBhcnIucmVhZEludDMyQkUgPSBCUC5yZWFkSW50MzJCRVxuICBhcnIucmVhZEZsb2F0TEUgPSBCUC5yZWFkRmxvYXRMRVxuICBhcnIucmVhZEZsb2F0QkUgPSBCUC5yZWFkRmxvYXRCRVxuICBhcnIucmVhZERvdWJsZUxFID0gQlAucmVhZERvdWJsZUxFXG4gIGFyci5yZWFkRG91YmxlQkUgPSBCUC5yZWFkRG91YmxlQkVcbiAgYXJyLndyaXRlVUludDggPSBCUC53cml0ZVVJbnQ4XG4gIGFyci53cml0ZVVJbnRMRSA9IEJQLndyaXRlVUludExFXG4gIGFyci53cml0ZVVJbnRCRSA9IEJQLndyaXRlVUludEJFXG4gIGFyci53cml0ZVVJbnQxNkxFID0gQlAud3JpdGVVSW50MTZMRVxuICBhcnIud3JpdGVVSW50MTZCRSA9IEJQLndyaXRlVUludDE2QkVcbiAgYXJyLndyaXRlVUludDMyTEUgPSBCUC53cml0ZVVJbnQzMkxFXG4gIGFyci53cml0ZVVJbnQzMkJFID0gQlAud3JpdGVVSW50MzJCRVxuICBhcnIud3JpdGVJbnRMRSA9IEJQLndyaXRlSW50TEVcbiAgYXJyLndyaXRlSW50QkUgPSBCUC53cml0ZUludEJFXG4gIGFyci53cml0ZUludDggPSBCUC53cml0ZUludDhcbiAgYXJyLndyaXRlSW50MTZMRSA9IEJQLndyaXRlSW50MTZMRVxuICBhcnIud3JpdGVJbnQxNkJFID0gQlAud3JpdGVJbnQxNkJFXG4gIGFyci53cml0ZUludDMyTEUgPSBCUC53cml0ZUludDMyTEVcbiAgYXJyLndyaXRlSW50MzJCRSA9IEJQLndyaXRlSW50MzJCRVxuICBhcnIud3JpdGVGbG9hdExFID0gQlAud3JpdGVGbG9hdExFXG4gIGFyci53cml0ZUZsb2F0QkUgPSBCUC53cml0ZUZsb2F0QkVcbiAgYXJyLndyaXRlRG91YmxlTEUgPSBCUC53cml0ZURvdWJsZUxFXG4gIGFyci53cml0ZURvdWJsZUJFID0gQlAud3JpdGVEb3VibGVCRVxuICBhcnIuZmlsbCA9IEJQLmZpbGxcbiAgYXJyLmluc3BlY3QgPSBCUC5pbnNwZWN0XG4gIGFyci50b0FycmF5QnVmZmVyID0gQlAudG9BcnJheUJ1ZmZlclxuXG4gIHJldHVybiBhcnJcbn1cblxudmFyIElOVkFMSURfQkFTRTY0X1JFID0gL1teK1xcLzAtOUEtWmEtei1fXS9nXG5cbmZ1bmN0aW9uIGJhc2U2NGNsZWFuIChzdHIpIHtcbiAgLy8gTm9kZSBzdHJpcHMgb3V0IGludmFsaWQgY2hhcmFjdGVycyBsaWtlIFxcbiBhbmQgXFx0IGZyb20gdGhlIHN0cmluZywgYmFzZTY0LWpzIGRvZXMgbm90XG4gIHN0ciA9IHN0cmluZ3RyaW0oc3RyKS5yZXBsYWNlKElOVkFMSURfQkFTRTY0X1JFLCAnJylcbiAgLy8gTm9kZSBjb252ZXJ0cyBzdHJpbmdzIHdpdGggbGVuZ3RoIDwgMiB0byAnJ1xuICBpZiAoc3RyLmxlbmd0aCA8IDIpIHJldHVybiAnJ1xuICAvLyBOb2RlIGFsbG93cyBmb3Igbm9uLXBhZGRlZCBiYXNlNjQgc3RyaW5ncyAobWlzc2luZyB0cmFpbGluZyA9PT0pLCBiYXNlNjQtanMgZG9lcyBub3RcbiAgd2hpbGUgKHN0ci5sZW5ndGggJSA0ICE9PSAwKSB7XG4gICAgc3RyID0gc3RyICsgJz0nXG4gIH1cbiAgcmV0dXJuIHN0clxufVxuXG5mdW5jdGlvbiBzdHJpbmd0cmltIChzdHIpIHtcbiAgaWYgKHN0ci50cmltKSByZXR1cm4gc3RyLnRyaW0oKVxuICByZXR1cm4gc3RyLnJlcGxhY2UoL15cXHMrfFxccyskL2csICcnKVxufVxuXG5mdW5jdGlvbiB0b0hleCAobikge1xuICBpZiAobiA8IDE2KSByZXR1cm4gJzAnICsgbi50b1N0cmluZygxNilcbiAgcmV0dXJuIG4udG9TdHJpbmcoMTYpXG59XG5cbmZ1bmN0aW9uIHV0ZjhUb0J5dGVzIChzdHJpbmcsIHVuaXRzKSB7XG4gIHVuaXRzID0gdW5pdHMgfHwgSW5maW5pdHlcbiAgdmFyIGNvZGVQb2ludFxuICB2YXIgbGVuZ3RoID0gc3RyaW5nLmxlbmd0aFxuICB2YXIgbGVhZFN1cnJvZ2F0ZSA9IG51bGxcbiAgdmFyIGJ5dGVzID0gW11cblxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgY29kZVBvaW50ID0gc3RyaW5nLmNoYXJDb2RlQXQoaSlcblxuICAgIC8vIGlzIHN1cnJvZ2F0ZSBjb21wb25lbnRcbiAgICBpZiAoY29kZVBvaW50ID4gMHhEN0ZGICYmIGNvZGVQb2ludCA8IDB4RTAwMCkge1xuICAgICAgLy8gbGFzdCBjaGFyIHdhcyBhIGxlYWRcbiAgICAgIGlmICghbGVhZFN1cnJvZ2F0ZSkge1xuICAgICAgICAvLyBubyBsZWFkIHlldFxuICAgICAgICBpZiAoY29kZVBvaW50ID4gMHhEQkZGKSB7XG4gICAgICAgICAgLy8gdW5leHBlY3RlZCB0cmFpbFxuICAgICAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgIH0gZWxzZSBpZiAoaSArIDEgPT09IGxlbmd0aCkge1xuICAgICAgICAgIC8vIHVucGFpcmVkIGxlYWRcbiAgICAgICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICAgICAgICBjb250aW51ZVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gdmFsaWQgbGVhZFxuICAgICAgICBsZWFkU3Vycm9nYXRlID0gY29kZVBvaW50XG5cbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgLy8gMiBsZWFkcyBpbiBhIHJvd1xuICAgICAgaWYgKGNvZGVQb2ludCA8IDB4REMwMCkge1xuICAgICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICAgICAgbGVhZFN1cnJvZ2F0ZSA9IGNvZGVQb2ludFxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICAvLyB2YWxpZCBzdXJyb2dhdGUgcGFpclxuICAgICAgY29kZVBvaW50ID0gKGxlYWRTdXJyb2dhdGUgLSAweEQ4MDAgPDwgMTAgfCBjb2RlUG9pbnQgLSAweERDMDApICsgMHgxMDAwMFxuICAgIH0gZWxzZSBpZiAobGVhZFN1cnJvZ2F0ZSkge1xuICAgICAgLy8gdmFsaWQgYm1wIGNoYXIsIGJ1dCBsYXN0IGNoYXIgd2FzIGEgbGVhZFxuICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgfVxuXG4gICAgbGVhZFN1cnJvZ2F0ZSA9IG51bGxcblxuICAgIC8vIGVuY29kZSB1dGY4XG4gICAgaWYgKGNvZGVQb2ludCA8IDB4ODApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gMSkgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChjb2RlUG9pbnQpXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPCAweDgwMCkge1xuICAgICAgaWYgKCh1bml0cyAtPSAyKSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHg2IHwgMHhDMCxcbiAgICAgICAgY29kZVBvaW50ICYgMHgzRiB8IDB4ODBcbiAgICAgIClcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA8IDB4MTAwMDApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gMykgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChcbiAgICAgICAgY29kZVBvaW50ID4+IDB4QyB8IDB4RTAsXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDYgJiAweDNGIHwgMHg4MCxcbiAgICAgICAgY29kZVBvaW50ICYgMHgzRiB8IDB4ODBcbiAgICAgIClcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA8IDB4MTEwMDAwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDQpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDEyIHwgMHhGMCxcbiAgICAgICAgY29kZVBvaW50ID4+IDB4QyAmIDB4M0YgfCAweDgwLFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHg2ICYgMHgzRiB8IDB4ODAsXG4gICAgICAgIGNvZGVQb2ludCAmIDB4M0YgfCAweDgwXG4gICAgICApXG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBjb2RlIHBvaW50JylcbiAgICB9XG4gIH1cblxuICByZXR1cm4gYnl0ZXNcbn1cblxuZnVuY3Rpb24gYXNjaWlUb0J5dGVzIChzdHIpIHtcbiAgdmFyIGJ5dGVBcnJheSA9IFtdXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgaSsrKSB7XG4gICAgLy8gTm9kZSdzIGNvZGUgc2VlbXMgdG8gYmUgZG9pbmcgdGhpcyBhbmQgbm90ICYgMHg3Ri4uXG4gICAgYnl0ZUFycmF5LnB1c2goc3RyLmNoYXJDb2RlQXQoaSkgJiAweEZGKVxuICB9XG4gIHJldHVybiBieXRlQXJyYXlcbn1cblxuZnVuY3Rpb24gdXRmMTZsZVRvQnl0ZXMgKHN0ciwgdW5pdHMpIHtcbiAgdmFyIGMsIGhpLCBsb1xuICB2YXIgYnl0ZUFycmF5ID0gW11cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdHIubGVuZ3RoOyBpKyspIHtcbiAgICBpZiAoKHVuaXRzIC09IDIpIDwgMCkgYnJlYWtcblxuICAgIGMgPSBzdHIuY2hhckNvZGVBdChpKVxuICAgIGhpID0gYyA+PiA4XG4gICAgbG8gPSBjICUgMjU2XG4gICAgYnl0ZUFycmF5LnB1c2gobG8pXG4gICAgYnl0ZUFycmF5LnB1c2goaGkpXG4gIH1cblxuICByZXR1cm4gYnl0ZUFycmF5XG59XG5cbmZ1bmN0aW9uIGJhc2U2NFRvQnl0ZXMgKHN0cikge1xuICByZXR1cm4gYmFzZTY0LnRvQnl0ZUFycmF5KGJhc2U2NGNsZWFuKHN0cikpXG59XG5cbmZ1bmN0aW9uIGJsaXRCdWZmZXIgKHNyYywgZHN0LCBvZmZzZXQsIGxlbmd0aCkge1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKChpICsgb2Zmc2V0ID49IGRzdC5sZW5ndGgpIHx8IChpID49IHNyYy5sZW5ndGgpKSBicmVha1xuICAgIGRzdFtpICsgb2Zmc2V0XSA9IHNyY1tpXVxuICB9XG4gIHJldHVybiBpXG59XG4iLCJ2YXIgbG9va3VwID0gJ0FCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5Ky8nO1xuXG47KGZ1bmN0aW9uIChleHBvcnRzKSB7XG5cdCd1c2Ugc3RyaWN0JztcblxuICB2YXIgQXJyID0gKHR5cGVvZiBVaW50OEFycmF5ICE9PSAndW5kZWZpbmVkJylcbiAgICA/IFVpbnQ4QXJyYXlcbiAgICA6IEFycmF5XG5cblx0dmFyIFBMVVMgICA9ICcrJy5jaGFyQ29kZUF0KDApXG5cdHZhciBTTEFTSCAgPSAnLycuY2hhckNvZGVBdCgwKVxuXHR2YXIgTlVNQkVSID0gJzAnLmNoYXJDb2RlQXQoMClcblx0dmFyIExPV0VSICA9ICdhJy5jaGFyQ29kZUF0KDApXG5cdHZhciBVUFBFUiAgPSAnQScuY2hhckNvZGVBdCgwKVxuXHR2YXIgUExVU19VUkxfU0FGRSA9ICctJy5jaGFyQ29kZUF0KDApXG5cdHZhciBTTEFTSF9VUkxfU0FGRSA9ICdfJy5jaGFyQ29kZUF0KDApXG5cblx0ZnVuY3Rpb24gZGVjb2RlIChlbHQpIHtcblx0XHR2YXIgY29kZSA9IGVsdC5jaGFyQ29kZUF0KDApXG5cdFx0aWYgKGNvZGUgPT09IFBMVVMgfHxcblx0XHQgICAgY29kZSA9PT0gUExVU19VUkxfU0FGRSlcblx0XHRcdHJldHVybiA2MiAvLyAnKydcblx0XHRpZiAoY29kZSA9PT0gU0xBU0ggfHxcblx0XHQgICAgY29kZSA9PT0gU0xBU0hfVVJMX1NBRkUpXG5cdFx0XHRyZXR1cm4gNjMgLy8gJy8nXG5cdFx0aWYgKGNvZGUgPCBOVU1CRVIpXG5cdFx0XHRyZXR1cm4gLTEgLy9ubyBtYXRjaFxuXHRcdGlmIChjb2RlIDwgTlVNQkVSICsgMTApXG5cdFx0XHRyZXR1cm4gY29kZSAtIE5VTUJFUiArIDI2ICsgMjZcblx0XHRpZiAoY29kZSA8IFVQUEVSICsgMjYpXG5cdFx0XHRyZXR1cm4gY29kZSAtIFVQUEVSXG5cdFx0aWYgKGNvZGUgPCBMT1dFUiArIDI2KVxuXHRcdFx0cmV0dXJuIGNvZGUgLSBMT1dFUiArIDI2XG5cdH1cblxuXHRmdW5jdGlvbiBiNjRUb0J5dGVBcnJheSAoYjY0KSB7XG5cdFx0dmFyIGksIGosIGwsIHRtcCwgcGxhY2VIb2xkZXJzLCBhcnJcblxuXHRcdGlmIChiNjQubGVuZ3RoICUgNCA+IDApIHtcblx0XHRcdHRocm93IG5ldyBFcnJvcignSW52YWxpZCBzdHJpbmcuIExlbmd0aCBtdXN0IGJlIGEgbXVsdGlwbGUgb2YgNCcpXG5cdFx0fVxuXG5cdFx0Ly8gdGhlIG51bWJlciBvZiBlcXVhbCBzaWducyAocGxhY2UgaG9sZGVycylcblx0XHQvLyBpZiB0aGVyZSBhcmUgdHdvIHBsYWNlaG9sZGVycywgdGhhbiB0aGUgdHdvIGNoYXJhY3RlcnMgYmVmb3JlIGl0XG5cdFx0Ly8gcmVwcmVzZW50IG9uZSBieXRlXG5cdFx0Ly8gaWYgdGhlcmUgaXMgb25seSBvbmUsIHRoZW4gdGhlIHRocmVlIGNoYXJhY3RlcnMgYmVmb3JlIGl0IHJlcHJlc2VudCAyIGJ5dGVzXG5cdFx0Ly8gdGhpcyBpcyBqdXN0IGEgY2hlYXAgaGFjayB0byBub3QgZG8gaW5kZXhPZiB0d2ljZVxuXHRcdHZhciBsZW4gPSBiNjQubGVuZ3RoXG5cdFx0cGxhY2VIb2xkZXJzID0gJz0nID09PSBiNjQuY2hhckF0KGxlbiAtIDIpID8gMiA6ICc9JyA9PT0gYjY0LmNoYXJBdChsZW4gLSAxKSA/IDEgOiAwXG5cblx0XHQvLyBiYXNlNjQgaXMgNC8zICsgdXAgdG8gdHdvIGNoYXJhY3RlcnMgb2YgdGhlIG9yaWdpbmFsIGRhdGFcblx0XHRhcnIgPSBuZXcgQXJyKGI2NC5sZW5ndGggKiAzIC8gNCAtIHBsYWNlSG9sZGVycylcblxuXHRcdC8vIGlmIHRoZXJlIGFyZSBwbGFjZWhvbGRlcnMsIG9ubHkgZ2V0IHVwIHRvIHRoZSBsYXN0IGNvbXBsZXRlIDQgY2hhcnNcblx0XHRsID0gcGxhY2VIb2xkZXJzID4gMCA/IGI2NC5sZW5ndGggLSA0IDogYjY0Lmxlbmd0aFxuXG5cdFx0dmFyIEwgPSAwXG5cblx0XHRmdW5jdGlvbiBwdXNoICh2KSB7XG5cdFx0XHRhcnJbTCsrXSA9IHZcblx0XHR9XG5cblx0XHRmb3IgKGkgPSAwLCBqID0gMDsgaSA8IGw7IGkgKz0gNCwgaiArPSAzKSB7XG5cdFx0XHR0bXAgPSAoZGVjb2RlKGI2NC5jaGFyQXQoaSkpIDw8IDE4KSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMSkpIDw8IDEyKSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMikpIDw8IDYpIHwgZGVjb2RlKGI2NC5jaGFyQXQoaSArIDMpKVxuXHRcdFx0cHVzaCgodG1wICYgMHhGRjAwMDApID4+IDE2KVxuXHRcdFx0cHVzaCgodG1wICYgMHhGRjAwKSA+PiA4KVxuXHRcdFx0cHVzaCh0bXAgJiAweEZGKVxuXHRcdH1cblxuXHRcdGlmIChwbGFjZUhvbGRlcnMgPT09IDIpIHtcblx0XHRcdHRtcCA9IChkZWNvZGUoYjY0LmNoYXJBdChpKSkgPDwgMikgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDEpKSA+PiA0KVxuXHRcdFx0cHVzaCh0bXAgJiAweEZGKVxuXHRcdH0gZWxzZSBpZiAocGxhY2VIb2xkZXJzID09PSAxKSB7XG5cdFx0XHR0bXAgPSAoZGVjb2RlKGI2NC5jaGFyQXQoaSkpIDw8IDEwKSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMSkpIDw8IDQpIHwgKGRlY29kZShiNjQuY2hhckF0KGkgKyAyKSkgPj4gMilcblx0XHRcdHB1c2goKHRtcCA+PiA4KSAmIDB4RkYpXG5cdFx0XHRwdXNoKHRtcCAmIDB4RkYpXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGFyclxuXHR9XG5cblx0ZnVuY3Rpb24gdWludDhUb0Jhc2U2NCAodWludDgpIHtcblx0XHR2YXIgaSxcblx0XHRcdGV4dHJhQnl0ZXMgPSB1aW50OC5sZW5ndGggJSAzLCAvLyBpZiB3ZSBoYXZlIDEgYnl0ZSBsZWZ0LCBwYWQgMiBieXRlc1xuXHRcdFx0b3V0cHV0ID0gXCJcIixcblx0XHRcdHRlbXAsIGxlbmd0aFxuXG5cdFx0ZnVuY3Rpb24gZW5jb2RlIChudW0pIHtcblx0XHRcdHJldHVybiBsb29rdXAuY2hhckF0KG51bSlcblx0XHR9XG5cblx0XHRmdW5jdGlvbiB0cmlwbGV0VG9CYXNlNjQgKG51bSkge1xuXHRcdFx0cmV0dXJuIGVuY29kZShudW0gPj4gMTggJiAweDNGKSArIGVuY29kZShudW0gPj4gMTIgJiAweDNGKSArIGVuY29kZShudW0gPj4gNiAmIDB4M0YpICsgZW5jb2RlKG51bSAmIDB4M0YpXG5cdFx0fVxuXG5cdFx0Ly8gZ28gdGhyb3VnaCB0aGUgYXJyYXkgZXZlcnkgdGhyZWUgYnl0ZXMsIHdlJ2xsIGRlYWwgd2l0aCB0cmFpbGluZyBzdHVmZiBsYXRlclxuXHRcdGZvciAoaSA9IDAsIGxlbmd0aCA9IHVpbnQ4Lmxlbmd0aCAtIGV4dHJhQnl0ZXM7IGkgPCBsZW5ndGg7IGkgKz0gMykge1xuXHRcdFx0dGVtcCA9ICh1aW50OFtpXSA8PCAxNikgKyAodWludDhbaSArIDFdIDw8IDgpICsgKHVpbnQ4W2kgKyAyXSlcblx0XHRcdG91dHB1dCArPSB0cmlwbGV0VG9CYXNlNjQodGVtcClcblx0XHR9XG5cblx0XHQvLyBwYWQgdGhlIGVuZCB3aXRoIHplcm9zLCBidXQgbWFrZSBzdXJlIHRvIG5vdCBmb3JnZXQgdGhlIGV4dHJhIGJ5dGVzXG5cdFx0c3dpdGNoIChleHRyYUJ5dGVzKSB7XG5cdFx0XHRjYXNlIDE6XG5cdFx0XHRcdHRlbXAgPSB1aW50OFt1aW50OC5sZW5ndGggLSAxXVxuXHRcdFx0XHRvdXRwdXQgKz0gZW5jb2RlKHRlbXAgPj4gMilcblx0XHRcdFx0b3V0cHV0ICs9IGVuY29kZSgodGVtcCA8PCA0KSAmIDB4M0YpXG5cdFx0XHRcdG91dHB1dCArPSAnPT0nXG5cdFx0XHRcdGJyZWFrXG5cdFx0XHRjYXNlIDI6XG5cdFx0XHRcdHRlbXAgPSAodWludDhbdWludDgubGVuZ3RoIC0gMl0gPDwgOCkgKyAodWludDhbdWludDgubGVuZ3RoIC0gMV0pXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUodGVtcCA+PiAxMClcblx0XHRcdFx0b3V0cHV0ICs9IGVuY29kZSgodGVtcCA+PiA0KSAmIDB4M0YpXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUoKHRlbXAgPDwgMikgJiAweDNGKVxuXHRcdFx0XHRvdXRwdXQgKz0gJz0nXG5cdFx0XHRcdGJyZWFrXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG91dHB1dFxuXHR9XG5cblx0ZXhwb3J0cy50b0J5dGVBcnJheSA9IGI2NFRvQnl0ZUFycmF5XG5cdGV4cG9ydHMuZnJvbUJ5dGVBcnJheSA9IHVpbnQ4VG9CYXNlNjRcbn0odHlwZW9mIGV4cG9ydHMgPT09ICd1bmRlZmluZWQnID8gKHRoaXMuYmFzZTY0anMgPSB7fSkgOiBleHBvcnRzKSlcbiIsImV4cG9ydHMucmVhZCA9IGZ1bmN0aW9uIChidWZmZXIsIG9mZnNldCwgaXNMRSwgbUxlbiwgbkJ5dGVzKSB7XG4gIHZhciBlLCBtXG4gIHZhciBlTGVuID0gbkJ5dGVzICogOCAtIG1MZW4gLSAxXG4gIHZhciBlTWF4ID0gKDEgPDwgZUxlbikgLSAxXG4gIHZhciBlQmlhcyA9IGVNYXggPj4gMVxuICB2YXIgbkJpdHMgPSAtN1xuICB2YXIgaSA9IGlzTEUgPyAobkJ5dGVzIC0gMSkgOiAwXG4gIHZhciBkID0gaXNMRSA/IC0xIDogMVxuICB2YXIgcyA9IGJ1ZmZlcltvZmZzZXQgKyBpXVxuXG4gIGkgKz0gZFxuXG4gIGUgPSBzICYgKCgxIDw8ICgtbkJpdHMpKSAtIDEpXG4gIHMgPj49ICgtbkJpdHMpXG4gIG5CaXRzICs9IGVMZW5cbiAgZm9yICg7IG5CaXRzID4gMDsgZSA9IGUgKiAyNTYgKyBidWZmZXJbb2Zmc2V0ICsgaV0sIGkgKz0gZCwgbkJpdHMgLT0gOCkge31cblxuICBtID0gZSAmICgoMSA8PCAoLW5CaXRzKSkgLSAxKVxuICBlID4+PSAoLW5CaXRzKVxuICBuQml0cyArPSBtTGVuXG4gIGZvciAoOyBuQml0cyA+IDA7IG0gPSBtICogMjU2ICsgYnVmZmVyW29mZnNldCArIGldLCBpICs9IGQsIG5CaXRzIC09IDgpIHt9XG5cbiAgaWYgKGUgPT09IDApIHtcbiAgICBlID0gMSAtIGVCaWFzXG4gIH0gZWxzZSBpZiAoZSA9PT0gZU1heCkge1xuICAgIHJldHVybiBtID8gTmFOIDogKChzID8gLTEgOiAxKSAqIEluZmluaXR5KVxuICB9IGVsc2Uge1xuICAgIG0gPSBtICsgTWF0aC5wb3coMiwgbUxlbilcbiAgICBlID0gZSAtIGVCaWFzXG4gIH1cbiAgcmV0dXJuIChzID8gLTEgOiAxKSAqIG0gKiBNYXRoLnBvdygyLCBlIC0gbUxlbilcbn1cblxuZXhwb3J0cy53cml0ZSA9IGZ1bmN0aW9uIChidWZmZXIsIHZhbHVlLCBvZmZzZXQsIGlzTEUsIG1MZW4sIG5CeXRlcykge1xuICB2YXIgZSwgbSwgY1xuICB2YXIgZUxlbiA9IG5CeXRlcyAqIDggLSBtTGVuIC0gMVxuICB2YXIgZU1heCA9ICgxIDw8IGVMZW4pIC0gMVxuICB2YXIgZUJpYXMgPSBlTWF4ID4+IDFcbiAgdmFyIHJ0ID0gKG1MZW4gPT09IDIzID8gTWF0aC5wb3coMiwgLTI0KSAtIE1hdGgucG93KDIsIC03NykgOiAwKVxuICB2YXIgaSA9IGlzTEUgPyAwIDogKG5CeXRlcyAtIDEpXG4gIHZhciBkID0gaXNMRSA/IDEgOiAtMVxuICB2YXIgcyA9IHZhbHVlIDwgMCB8fCAodmFsdWUgPT09IDAgJiYgMSAvIHZhbHVlIDwgMCkgPyAxIDogMFxuXG4gIHZhbHVlID0gTWF0aC5hYnModmFsdWUpXG5cbiAgaWYgKGlzTmFOKHZhbHVlKSB8fCB2YWx1ZSA9PT0gSW5maW5pdHkpIHtcbiAgICBtID0gaXNOYU4odmFsdWUpID8gMSA6IDBcbiAgICBlID0gZU1heFxuICB9IGVsc2Uge1xuICAgIGUgPSBNYXRoLmZsb29yKE1hdGgubG9nKHZhbHVlKSAvIE1hdGguTE4yKVxuICAgIGlmICh2YWx1ZSAqIChjID0gTWF0aC5wb3coMiwgLWUpKSA8IDEpIHtcbiAgICAgIGUtLVxuICAgICAgYyAqPSAyXG4gICAgfVxuICAgIGlmIChlICsgZUJpYXMgPj0gMSkge1xuICAgICAgdmFsdWUgKz0gcnQgLyBjXG4gICAgfSBlbHNlIHtcbiAgICAgIHZhbHVlICs9IHJ0ICogTWF0aC5wb3coMiwgMSAtIGVCaWFzKVxuICAgIH1cbiAgICBpZiAodmFsdWUgKiBjID49IDIpIHtcbiAgICAgIGUrK1xuICAgICAgYyAvPSAyXG4gICAgfVxuXG4gICAgaWYgKGUgKyBlQmlhcyA+PSBlTWF4KSB7XG4gICAgICBtID0gMFxuICAgICAgZSA9IGVNYXhcbiAgICB9IGVsc2UgaWYgKGUgKyBlQmlhcyA+PSAxKSB7XG4gICAgICBtID0gKHZhbHVlICogYyAtIDEpICogTWF0aC5wb3coMiwgbUxlbilcbiAgICAgIGUgPSBlICsgZUJpYXNcbiAgICB9IGVsc2Uge1xuICAgICAgbSA9IHZhbHVlICogTWF0aC5wb3coMiwgZUJpYXMgLSAxKSAqIE1hdGgucG93KDIsIG1MZW4pXG4gICAgICBlID0gMFxuICAgIH1cbiAgfVxuXG4gIGZvciAoOyBtTGVuID49IDg7IGJ1ZmZlcltvZmZzZXQgKyBpXSA9IG0gJiAweGZmLCBpICs9IGQsIG0gLz0gMjU2LCBtTGVuIC09IDgpIHt9XG5cbiAgZSA9IChlIDw8IG1MZW4pIHwgbVxuICBlTGVuICs9IG1MZW5cbiAgZm9yICg7IGVMZW4gPiAwOyBidWZmZXJbb2Zmc2V0ICsgaV0gPSBlICYgMHhmZiwgaSArPSBkLCBlIC89IDI1NiwgZUxlbiAtPSA4KSB7fVxuXG4gIGJ1ZmZlcltvZmZzZXQgKyBpIC0gZF0gfD0gcyAqIDEyOFxufVxuIiwiXG4vKipcbiAqIGlzQXJyYXlcbiAqL1xuXG52YXIgaXNBcnJheSA9IEFycmF5LmlzQXJyYXk7XG5cbi8qKlxuICogdG9TdHJpbmdcbiAqL1xuXG52YXIgc3RyID0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZztcblxuLyoqXG4gKiBXaGV0aGVyIG9yIG5vdCB0aGUgZ2l2ZW4gYHZhbGBcbiAqIGlzIGFuIGFycmF5LlxuICpcbiAqIGV4YW1wbGU6XG4gKlxuICogICAgICAgIGlzQXJyYXkoW10pO1xuICogICAgICAgIC8vID4gdHJ1ZVxuICogICAgICAgIGlzQXJyYXkoYXJndW1lbnRzKTtcbiAqICAgICAgICAvLyA+IGZhbHNlXG4gKiAgICAgICAgaXNBcnJheSgnJyk7XG4gKiAgICAgICAgLy8gPiBmYWxzZVxuICpcbiAqIEBwYXJhbSB7bWl4ZWR9IHZhbFxuICogQHJldHVybiB7Ym9vbH1cbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGlzQXJyYXkgfHwgZnVuY3Rpb24gKHZhbCkge1xuICByZXR1cm4gISEgdmFsICYmICdbb2JqZWN0IEFycmF5XScgPT0gc3RyLmNhbGwodmFsKTtcbn07XG4iLCJtb2R1bGUuZXhwb3J0cz17XG4gICAgXCJ2ZXJzaW9uXCI6IFwiXCJcbn1cbiIsIi8qKlxuICogRXBpY2VudGVyIEphdmFzY3JpcHQgbGlicmFyaWVzXG4gKiB2PCU9IHZlcnNpb24gJT5cbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9mb3Jpby9lcGljZW50ZXItanMtbGlic1xuICovXG5cbnZhciBGID0ge1xuICAgIHV0aWw6IHt9LFxuICAgIGZhY3Rvcnk6IHt9LFxuICAgIHRyYW5zcG9ydDoge30sXG4gICAgc3RvcmU6IHt9LFxuICAgIHNlcnZpY2U6IHt9LFxuICAgIG1hbmFnZXI6IHtcbiAgICAgICAgc3RyYXRlZ3k6IHt9XG4gICAgfSxcblxufTtcblxuRi51dGlsLnF1ZXJ5ID0gcmVxdWlyZSgnLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbkYudXRpbC5tYWtlU2VxdWVuY2UgPSByZXF1aXJlKCcuL3V0aWwvbWFrZS1zZXF1ZW5jZScpO1xuRi51dGlsLnJ1biA9IHJlcXVpcmUoJy4vdXRpbC9ydW4tdXRpbCcpO1xuRi51dGlsLmNsYXNzRnJvbSA9IHJlcXVpcmUoJy4vdXRpbC9pbmhlcml0Jyk7XG5cbkYuZmFjdG9yeS5UcmFuc3BvcnQgPSByZXF1aXJlKCcuL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5GLnRyYW5zcG9ydC5BamF4ID0gcmVxdWlyZSgnLi90cmFuc3BvcnQvYWpheC1odHRwLXRyYW5zcG9ydCcpO1xuXG5GLnNlcnZpY2UuVVJMID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3VybC1jb25maWctc2VydmljZScpO1xuRi5zZXJ2aWNlLkNvbmZpZyA9IHJlcXVpcmUoJy4vc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbkYuc2VydmljZS5SdW4gPSByZXF1aXJlKCcuL3NlcnZpY2UvcnVuLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuRmlsZSA9IHJlcXVpcmUoJy4vc2VydmljZS9hZG1pbi1maWxlLXNlcnZpY2UnKTtcbkYuc2VydmljZS5WYXJpYWJsZXMgPSByZXF1aXJlKCcuL3NlcnZpY2UvdmFyaWFibGVzLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuRGF0YSA9IHJlcXVpcmUoJy4vc2VydmljZS9kYXRhLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuQXV0aCA9IHJlcXVpcmUoJy4vc2VydmljZS9hdXRoLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuV29ybGQgPSByZXF1aXJlKCcuL3NlcnZpY2Uvd29ybGQtYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5TdGF0ZSA9IHJlcXVpcmUoJy4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xuRi5zZXJ2aWNlLlVzZXIgPSByZXF1aXJlKCcuL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlcicpO1xuRi5zZXJ2aWNlLk1lbWJlciA9IHJlcXVpcmUoJy4vc2VydmljZS9tZW1iZXItYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5Bc3NldCA9IHJlcXVpcmUoJy4vc2VydmljZS9hc3NldC1hcGktYWRhcHRlcicpO1xuXG5GLnN0b3JlLkNvb2tpZSA9IHJlcXVpcmUoJy4vc3RvcmUvY29va2llLXN0b3JlJyk7XG5GLmZhY3RvcnkuU3RvcmUgPSByZXF1aXJlKCcuL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcblxuRi5tYW5hZ2VyLlNjZW5hcmlvTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvc2NlbmFyaW8tbWFuYWdlcicpO1xuRi5tYW5hZ2VyLlJ1bk1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1tYW5hZ2VyJyk7XG5GLm1hbmFnZXIuQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL2F1dGgtbWFuYWdlcicpO1xuRi5tYW5hZ2VyLldvcmxkTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvd29ybGQtbWFuYWdlcicpO1xuXG5GLm1hbmFnZXIuc3RyYXRlZ3lbJ2Fsd2F5cy1uZXcnXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvYWx3YXlzLW5ldy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5Wydjb25kaXRpb25hbC1jcmVhdGlvbiddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5LmlkZW50aXR5ID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9pZGVudGl0eS1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtbWlzc2luZyddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtbWlzc2luZyddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtcGVyc2lzdGVkJ10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1wZXJzaXN0ZWQtc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLWluaXRpYWxpemVkJ10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpO1xuXG5GLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXInKTtcbkYuc2VydmljZS5DaGFubmVsID0gcmVxdWlyZSgnLi9zZXJ2aWNlL2NoYW5uZWwtc2VydmljZScpO1xuXG5GLnZlcnNpb24gPSAnPCU9IHZlcnNpb24gJT4nO1xuRi5hcGkgPSByZXF1aXJlKCcuL2FwaS12ZXJzaW9uLmpzb24nKTtcblxuZ2xvYmFsLkYgPSBGO1xubW9kdWxlLmV4cG9ydHMgPSBGO1xuIiwiLyoqXG4qICMjIEF1dGhvcml6YXRpb24gTWFuYWdlclxuKlxuKiBUaGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyIHByb3ZpZGVzIGFuIGVhc3kgd2F5IHRvIG1hbmFnZSB1c2VyIGF1dGhlbnRpY2F0aW9uIChsb2dnaW5nIGluIGFuZCBvdXQpIGFuZCBhdXRob3JpemF0aW9uIChrZWVwaW5nIHRyYWNrIG9mIHRva2Vucywgc2Vzc2lvbnMsIGFuZCBncm91cHMpIGZvciBwcm9qZWN0cy5cbipcbiogVGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBpcyBtb3N0IHVzZWZ1bCBmb3IgW3RlYW0gcHJvamVjdHNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN0ZWFtKSB3aXRoIGFuIGFjY2VzcyBsZXZlbCBvZiBbQXV0aGVudGljYXRlZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2FjY2VzcykuIFRoZXNlIHByb2plY3RzIGFyZSBhY2Nlc3NlZCBieSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiBvbmUgb3IgbW9yZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS5cbipcbiogIyMjI1VzaW5nIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXJcbipcbiogVG8gdXNlIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LiBUaGVuLCBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZDpcbipcbiogICAgICAgdmFyIGF1dGhNZ3IgPSBuZXcgRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyKHtcbiogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgIHVzZXJOYW1lOiAnZW5kdXNlcjEnLFxuKiAgICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCdcbiogICAgICAgfSk7XG4qICAgICAgIGF1dGhNZ3IubG9naW4oKS50aGVuKGZ1bmN0aW9uICgpIHtcbiogICAgICAgICAgIGF1dGhNZ3IuZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuKiAgICAgICB9KTtcbipcbipcbiogVGhlIGBvcHRpb25zYCBvYmplY3QgcGFzc2VkIHRvIHRoZSBgRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyKClgIGNhbGwgY2FuIGluY2x1ZGU6XG4qXG4qICAgKiBgYWNjb3VudGA6IFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuKiAgICogYHVzZXJOYW1lYDogRW1haWwgb3IgdXNlcm5hbWUgdG8gdXNlIGZvciBsb2dnaW5nIGluLlxuKiAgICogYHBhc3N3b3JkYDogUGFzc3dvcmQgZm9yIHNwZWNpZmllZCBgdXNlck5hbWVgLlxuKiAgICogYHByb2plY3RgOiBUaGUgKipQcm9qZWN0IElEKiogZm9yIHRoZSBwcm9qZWN0IHRvIGxvZyB0aGlzIHVzZXIgaW50by4gT3B0aW9uYWwuXG4qICAgKiBgZ3JvdXBJZGA6IElkIG9mIHRoZSBncm91cCB0byB3aGljaCBgdXNlck5hbWVgIGJlbG9uZ3MuIFJlcXVpcmVkIGZvciBlbmQgdXNlcnMgaWYgdGhlIGBwcm9qZWN0YCBpcyBzcGVjaWZpZWQuXG4qXG4qIElmIHlvdSBwcmVmZXIgc3RhcnRpbmcgZnJvbSBhIHRlbXBsYXRlLCB0aGUgRXBpY2VudGVyIEpTIExpYnMgW0xvZ2luIENvbXBvbmVudF0oLi4vLi4vI2NvbXBvbmVudHMpIHVzZXMgdGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBhcyB3ZWxsLiBUaGlzIHNhbXBsZSBIVE1MIHBhZ2UgKGFuZCBhc3NvY2lhdGVkIENTUyBhbmQgSlMgZmlsZXMpIHByb3ZpZGVzIGEgbG9naW4gZm9ybSBmb3IgdGVhbSBtZW1iZXJzIGFuZCBlbmQgdXNlcnMgb2YgeW91ciBwcm9qZWN0LiBJdCBhbHNvIGluY2x1ZGVzIGEgZ3JvdXAgc2VsZWN0b3IgZm9yIGVuZCB1c2VycyB0aGF0IGFyZSBtZW1iZXJzIG9mIG11bHRpcGxlIGdyb3Vwcy5cbiovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBBdXRoQWRhcHRlciA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvYXV0aC1hcGktc2VydmljZScpO1xudmFyIE1lbWJlckFkYXB0ZXIgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlcicpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIEJ1ZmZlciA9IHJlcXVpcmUoJ2J1ZmZlcicpLkJ1ZmZlcjtcbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4va2V5LW5hbWVzJyk7XG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgICAvKipcbiAgICAgKiBXaGVyZSB0byBzdG9yZSB1c2VyIGFjY2VzcyB0b2tlbnMgZm9yIHRlbXBvcmFyeSBhY2Nlc3MuIERlZmF1bHRzIHRvIHN0b3JpbmcgaW4gYSBjb29raWUgaW4gdGhlIGJyb3dzZXIuXG4gICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgKi9cbiAgICBzdG9yZTogeyBzeW5jaHJvbm91czogdHJ1ZSB9XG59O1xuXG52YXIgRVBJX0NPT0tJRV9LRVkgPSBrZXlOYW1lcy5FUElfQ09PS0lFX0tFWTtcbnZhciBFUElfU0VTU0lPTl9LRVkgPSBrZXlOYW1lcy5FUElfU0VTU0lPTl9LRVk7XG52YXIgc3RvcmU7XG52YXIgdG9rZW47XG52YXIgc2Vzc2lvbjtcblxuZnVuY3Rpb24gc2F2ZVNlc3Npb24odXNlckluZm8pIHtcbiAgICB2YXIgc2VyaWFsaXplZCA9IEpTT04uc3RyaW5naWZ5KHVzZXJJbmZvKTtcbiAgICBzdG9yZS5zZXQoRVBJX1NFU1NJT05fS0VZLCBzZXJpYWxpemVkKTtcblxuICAgIC8vanNoaW50IGNhbWVsY2FzZTogZmFsc2VcbiAgICAvL2pzY3M6ZGlzYWJsZVxuICAgIHN0b3JlLnNldChFUElfQ09PS0lFX0tFWSwgdXNlckluZm8uYXV0aF90b2tlbik7XG59XG5cbmZ1bmN0aW9uIGdldFNlc3Npb24oKSB7XG4gICAgdmFyIHNlc3Npb24gPSBzdG9yZS5nZXQoRVBJX1NFU1NJT05fS0VZKSB8fCAne30nO1xuICAgIHJldHVybiBKU09OLnBhcnNlKHNlc3Npb24pO1xufVxuXG5mdW5jdGlvbiBBdXRoTWFuYWdlcihvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZSh0aGlzLm9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgaWYgKCF0aGlzLm9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB0aGlzLm9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICAvLyBudWxsIG1pZ2h0IHNwZWNpZmllZCB0byBkaXNhYmxlIHByb2plY3QgZmlsdGVyaW5nXG4gICAgaWYgKHRoaXMub3B0aW9ucy5wcm9qZWN0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhpcy5vcHRpb25zLnByb2plY3QgPSB1cmxDb25maWcucHJvamVjdFBhdGg7XG4gICAgfVxuXG4gICAgc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkodGhpcy5vcHRpb25zLnN0b3JlKTtcbiAgICBzZXNzaW9uID0gZ2V0U2Vzc2lvbigpO1xuICAgIHRva2VuID0gc3RvcmUuZ2V0KEVQSV9DT09LSUVfS0VZKSB8fCAnJztcbiAgICAvL2pzaGludCBjYW1lbGNhc2U6IGZhbHNlXG4gICAgLy9qc2NzOmRpc2FibGVcbiAgICB0aGlzLmF1dGhBZGFwdGVyID0gbmV3IEF1dGhBZGFwdGVyKHRoaXMub3B0aW9ucywgeyB0b2tlbjogc2Vzc2lvbi5hdXRoX3Rva2VuIH0pO1xufVxuXG52YXIgX2ZpbmRVc2VySW5Hcm91cCA9IGZ1bmN0aW9uIChtZW1iZXJzLCBpZCkge1xuICAgIGZvciAodmFyIGogPSAwOyBqPG1lbWJlcnMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKG1lbWJlcnNbal0udXNlcklkID09PSBpZCkge1xuICAgICAgICAgICAgcmV0dXJuIG1lbWJlcnNbal07XG4gICAgICAgIH1cbiAgICB9XG5cblxuICAgIHJldHVybiBudWxsO1xufTtcblxuQXV0aE1hbmFnZXIucHJvdG90eXBlID0gJC5leHRlbmQoQXV0aE1hbmFnZXIucHJvdG90eXBlLCB7XG5cbiAgICAvKipcbiAgICAqIExvZ3MgdXNlciBpbi5cbiAgICAqXG4gICAgKiAqKkV4YW1wbGUqKlxuICAgICpcbiAgICAqICAgICAgIGF1dGhNZ3IubG9naW4oe1xuICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLCBcbiAgICAqICAgICAgICAgICB1c2VyTmFtZTogJ2VuZHVzZXIxJyxcbiAgICAqICAgICAgICAgICBwYXNzd29yZDogJ3Bhc3N3MHJkJyBcbiAgICAqICAgICAgIH0pXG4gICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oc3RhdHVzT2JqKSB7XG4gICAgKiAgICAgICAgICAgICAgIC8vIGlmIGVuZHVzZXIxIGJlbG9uZ3MgdG8gZXhhY3RseSBvbmUgZ3JvdXBcbiAgICAqICAgICAgICAgICAgICAgLy8gKG9yIGlmIHRoZSBsb2dpbigpIGNhbGwgaXMgbW9kaWZpZWQgdG8gaW5jbHVkZSB0aGUgZ3JvdXAgaWQpXG4gICAgKiAgICAgICAgICAgICAgIC8vIGNvbnRpbnVlIGhlcmVcbiAgICAqICAgICAgICAgICB9KVxuICAgICogICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uKHN0YXR1c09iaikge1xuICAgICogICAgICAgICAgICAgICAvLyBpZiBlbmR1c2VyMSBiZWxvbmdzIHRvIG11bHRpcGxlIGdyb3VwcywgXG4gICAgKiAgICAgICAgICAgICAgIC8vIHRoZSBsb2dpbigpIGNhbGwgZmFpbHMgXG4gICAgKiAgICAgICAgICAgICAgIC8vIGFuZCByZXR1cm5zIGFsbCBncm91cHMgb2Ygd2hpY2ggdGhlIHVzZXIgaXMgYSBtZW1iZXJcbiAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpIDwgc3RhdHVzT2JqLnVzZXJHcm91cHMubGVuZ3RoOyBpKyspIHtcbiAgICAqICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHN0YXR1c09iai51c2VyR3JvdXBzW2ldLm5hbWUsIHN0YXR1c09iai51c2VyR3JvdXBzW2ldLmdyb3VwSWQpO1xuICAgICogICAgICAgICAgICAgICB9XG4gICAgKiAgICAgICAgICAgfSk7XG4gICAgKlxuICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAqXG4gICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuIElmIG5vdCBwYXNzZWQgaW4gd2hlbiBjcmVhdGluZyBhbiBpbnN0YW5jZSBvZiB0aGUgbWFuYWdlciAoYEYubWFuYWdlci5BdXRoTWFuYWdlcigpYCksIHRoZXNlIG9wdGlvbnMgc2hvdWxkIGluY2x1ZGU6IFxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLmFjY291bnRgIFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLnVzZXJOYW1lYCBFbWFpbCBvciB1c2VybmFtZSB0byB1c2UgZm9yIGxvZ2dpbmcgaW4uXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gYG9wdGlvbnMucGFzc3dvcmRgIFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5wcm9qZWN0YCAoT3B0aW9uYWwpIFRoZSAqKlByb2plY3QgSUQqKiBmb3IgdGhlIHByb2plY3QgdG8gbG9nIHRoaXMgdXNlciBpbnRvLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLmdyb3VwSWRgIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggYHVzZXJOYW1lYCBiZWxvbmdzLiBSZXF1aXJlZCBmb3IgW2VuZCB1c2Vyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSBpZiB0aGUgYHByb2plY3RgIGlzIHNwZWNpZmllZCBhbmQgaWYgdGhlIGVuZCB1c2VycyBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSwgb3RoZXJ3aXNlIG9wdGlvbmFsLiBcbiAgICAqL1xuICAgIGxvZ2luOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgIHZhciBhZGFwdGVyT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHsgc3VjY2VzczogJC5ub29wLCBlcnJvcjogJC5ub29wIH0sIHRoaXMub3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgIHZhciBvdXRTdWNjZXNzID0gYWRhcHRlck9wdGlvbnMuc3VjY2VzcztcbiAgICAgICAgdmFyIG91dEVycm9yID0gYWRhcHRlck9wdGlvbnMuZXJyb3I7XG4gICAgICAgIHZhciBncm91cElkID0gYWRhcHRlck9wdGlvbnMuZ3JvdXBJZDtcblxuICAgICAgICB2YXIgZGVjb2RlVG9rZW4gPSBmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgICAgICAgIHZhciBlbmNvZGVkID0gdG9rZW4uc3BsaXQoJy4nKVsxXTtcbiAgICAgICAgICAgIHdoaWxlIChlbmNvZGVkLmxlbmd0aCAlIDQgIT09IDApIHtcbiAgICAgICAgICAgICAgICBlbmNvZGVkICs9ICc9JztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGRlY29kZSA9IHdpbmRvdy5hdG9iID8gd2luZG93LmF0b2IgOiBmdW5jdGlvbiAoZW5jb2RlZCkgeyByZXR1cm4gbmV3IEJ1ZmZlcihlbmNvZGVkLCAnYmFzZTY0JykudG9TdHJpbmcoJ2FzY2lpJyk7IH07XG5cbiAgICAgICAgICAgIHJldHVybiBKU09OLnBhcnNlKGRlY29kZShlbmNvZGVkKSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIGhhbmRsZUdyb3VwRXJyb3IgPSBmdW5jdGlvbiAobWVzc2FnZSwgc3RhdHVzQ29kZSwgZGF0YSkge1xuICAgICAgICAgICAgLy8gbG9nb3V0IHRoZSB1c2VyIHNpbmNlIGl0J3MgaW4gYW4gaW52YWxpZCBzdGF0ZSB3aXRoIG5vIGdyb3VwIHNlbGVjdGVkXG4gICAgICAgICAgICBfdGhpcy5sb2dvdXQoKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB2YXIgZXJyb3IgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGF0YSwgeyBzdGF0dXNUZXh0OiBtZXNzYWdlLCBzdGF0dXM6IHN0YXR1c0NvZGUgfSk7XG4gICAgICAgICAgICAgICAgJGQucmVqZWN0KGVycm9yKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIHZhciBoYW5kbGVTdWNjZXNzID0gZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICAvL2pzaGludCBjYW1lbGNhc2U6IGZhbHNlXG4gICAgICAgICAgICAvL2pzY3M6ZGlzYWJsZVxuICAgICAgICAgICAgdG9rZW4gPSByZXNwb25zZS5hY2Nlc3NfdG9rZW47XG5cbiAgICAgICAgICAgIHZhciB1c2VySW5mbyA9IGRlY29kZVRva2VuKHRva2VuKTtcbiAgICAgICAgICAgIHZhciB1c2VyR3JvdXBPcHRzID0gJC5leHRlbmQodHJ1ZSwge30sIGFkYXB0ZXJPcHRpb25zLCB7IHN1Y2Nlc3M6ICQubm9vcCwgdG9rZW46IHRva2VuIH0pO1xuICAgICAgICAgICAgX3RoaXMuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogdXNlckluZm8udXNlcl9pZCwgdG9rZW46IHRva2VuIH0sIHVzZXJHcm91cE9wdHMpLmRvbmUoIGZ1bmN0aW9uIChtZW1iZXJJbmZvKSB7XG4gICAgICAgICAgICAgICAgdmFyIGRhdGEgPSB7YXV0aDogcmVzcG9uc2UsIHVzZXI6IHVzZXJJbmZvLCB1c2VyR3JvdXBzOiBtZW1iZXJJbmZvLCBncm91cFNlbGVjdGlvbjoge30gfTtcblxuICAgICAgICAgICAgICAgIHZhciBzZXNzaW9uSW5mbyA9IHtcbiAgICAgICAgICAgICAgICAgICAgJ2F1dGhfdG9rZW4nOiB0b2tlbixcbiAgICAgICAgICAgICAgICAgICAgJ2FjY291bnQnOiBhZGFwdGVyT3B0aW9ucy5hY2NvdW50LFxuICAgICAgICAgICAgICAgICAgICAncHJvamVjdCc6IGFkYXB0ZXJPcHRpb25zLnByb2plY3QsXG4gICAgICAgICAgICAgICAgICAgICd1c2VySWQnOiB1c2VySW5mby51c2VyX2lkXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAvLyBUaGUgZ3JvdXAgaXMgbm90IHJlcXVpcmVkIGlmIHRoZSB1c2VyIGlzIG5vdCBsb2dnaW5nIGludG8gYSBwcm9qZWN0XG4gICAgICAgICAgICAgICAgaWYgKCFhZGFwdGVyT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHNhdmVTZXNzaW9uKHNlc3Npb25JbmZvKTtcbiAgICAgICAgICAgICAgICAgICAgb3V0U3VjY2Vzcy5hcHBseSh0aGlzLCBbZGF0YV0pO1xuICAgICAgICAgICAgICAgICAgICAkZC5yZXNvbHZlKGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdmFyIGdyb3VwID0gbnVsbDtcbiAgICAgICAgICAgICAgICBpZiAobWVtYmVySW5mby5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgaGFuZGxlR3JvdXBFcnJvcignVGhlIHVzZXIgaGFzIG5vIGdyb3VwcyBhc3NvY2lhdGVkIGluIHRoaXMgYWNjb3VudCcsIDQwMSwgZGF0YSk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKG1lbWJlckluZm8ubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFNlbGVjdCB0aGUgb25seSBncm91cFxuICAgICAgICAgICAgICAgICAgICBncm91cCA9IG1lbWJlckluZm9bMF07XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChtZW1iZXJJbmZvLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGdyb3VwSWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBmaWx0ZXJlZEdyb3VwcyA9ICQuZ3JlcChtZW1iZXJJbmZvLCBmdW5jdGlvbiAocmVzR3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVzR3JvdXAuZ3JvdXBJZCA9PT0gZ3JvdXBJZDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBmaWx0ZXJlZEdyb3Vwcy5sZW5ndGggPT09IDEgPyBmaWx0ZXJlZEdyb3Vwc1swXSA6IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoZ3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGdyb3VwU2VsZWN0aW9uID0gZ3JvdXAuZ3JvdXBJZDtcbiAgICAgICAgICAgICAgICAgICAgZGF0YS5ncm91cFNlbGVjdGlvblthZGFwdGVyT3B0aW9ucy5wcm9qZWN0XSA9IGdyb3VwU2VsZWN0aW9uO1xuICAgICAgICAgICAgICAgICAgICB2YXIgc2Vzc2lvbkluZm9XaXRoR3JvdXAgPSAkLmV4dGVuZCh7fSwgc2Vzc2lvbkluZm8sIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICdncm91cElkJzogZ3JvdXAuZ3JvdXBJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICdncm91cE5hbWUnOiBncm91cC5uYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgJ2lzRmFjJzogX2ZpbmRVc2VySW5Hcm91cChncm91cC5tZW1iZXJzLCB1c2VySW5mby51c2VyX2lkKS5yb2xlID09PSAnZmFjaWxpdGF0b3InXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBzYXZlU2Vzc2lvbihzZXNzaW9uSW5mb1dpdGhHcm91cCk7XG4gICAgICAgICAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW2RhdGFdKTtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBoYW5kbGVHcm91cEVycm9yKCdUaGlzIHVzZXIgaXMgYXNzb2NpYXRlZCB3aXRoIG1vcmUgdGhhbiBvbmUgZ3JvdXAuIFBsZWFzZSBzcGVjaWZ5IGEgZ3JvdXAgaWQgdG8gbG9nIGludG8gYW5kIHRyeSBhZ2FpbicsIDQwMywgZGF0YSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSkuZmFpbCgkZC5yZWplY3QpO1xuICAgICAgICB9O1xuXG4gICAgICAgIGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3MgPSBoYW5kbGVTdWNjZXNzO1xuICAgICAgICBhZGFwdGVyT3B0aW9ucy5lcnJvciA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgaWYgKGFkYXB0ZXJPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgICAgICAgICAvLyBUcnkgdG8gbG9naW4gYXMgYSBzeXN0ZW0gdXNlclxuICAgICAgICAgICAgICAgIGFkYXB0ZXJPcHRpb25zLmFjY291bnQgPSBudWxsO1xuICAgICAgICAgICAgICAgIGFkYXB0ZXJPcHRpb25zLmVycm9yID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICBvdXRFcnJvci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAkZC5yZWplY3QocmVzcG9uc2UpO1xuICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICBfdGhpcy5hdXRoQWRhcHRlci5sb2dpbihhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBvdXRFcnJvci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgJGQucmVqZWN0KHJlc3BvbnNlKTtcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLmF1dGhBZGFwdGVyLmxvZ2luKGFkYXB0ZXJPcHRpb25zKTtcbiAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgKiBMb2dzIHVzZXIgb3V0LlxuICAgICpcbiAgICAqICoqRXhhbXBsZSoqXG4gICAgKlxuICAgICogICAgICAgYXV0aE1nci5sb2dvdXQoKTtcbiAgICAqXG4gICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICpcbiAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAqL1xuICAgIGxvZ291dDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGFkYXB0ZXJPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgeyB0b2tlbjogdG9rZW4gfSwgdGhpcy5vcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICB2YXIgcmVtb3ZlQ29va2llRm4gPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgIHN0b3JlLnJlbW92ZShFUElfQ09PS0lFX0tFWSwgYWRhcHRlck9wdGlvbnMpO1xuICAgICAgICAgICAgc3RvcmUucmVtb3ZlKEVQSV9TRVNTSU9OX0tFWSwgYWRhcHRlck9wdGlvbnMpO1xuICAgICAgICAgICAgdG9rZW4gPSAnJztcbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gdGhpcy5hdXRoQWRhcHRlci5sb2dvdXQoYWRhcHRlck9wdGlvbnMpLmRvbmUocmVtb3ZlQ29va2llRm4pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBleGlzdGluZyB1c2VyIGFjY2VzcyB0b2tlbiBpZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbi4gT3RoZXJ3aXNlLCBsb2dzIHRoZSB1c2VyIGluLCBjcmVhdGluZyBhIG5ldyB1c2VyIGFjY2VzcyB0b2tlbiwgYW5kIHJldHVybnMgdGhlIG5ldyB0b2tlbi4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgYXV0aE1nci5nZXRUb2tlbigpXG4gICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHRva2VuKSB7IFxuICAgICAqICAgICAgICAgICAgICBjb25zb2xlLmxvZygnTXkgdG9rZW4gaXMgJywgdG9rZW4pOyBcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldFRva2VuOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB0aGlzLm9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgaWYgKHRva2VuKSB7XG4gICAgICAgICAgICAkZC5yZXNvbHZlKHRva2VuKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMubG9naW4oaHR0cE9wdGlvbnMpLnRoZW4oJGQucmVzb2x2ZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhbiBhcnJheSBvZiBncm91cCByZWNvcmRzLCBvbmUgZm9yIGVhY2ggZ3JvdXAgb2Ygd2hpY2ggdGhlIGN1cnJlbnQgdXNlciBpcyBhIG1lbWJlci4gRWFjaCBncm91cCByZWNvcmQgaW5jbHVkZXMgdGhlIGdyb3VwIGBuYW1lYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgZ3JvdXBJZGAuXG4gICAgICpcbiAgICAgKiBJZiBzb21lIGVuZCB1c2VycyBpbiB5b3VyIHByb2plY3QgYXJlIG1lbWJlcnMgb2YgbXVsdGlwbGUgZ3JvdXBzLCB0aGlzIGlzIGEgdXNlZnVsIG1ldGhvZCB0byBjYWxsIG9uIHlvdXIgcHJvamVjdCdzIGxvZ2luIHBhZ2UuIFdoZW4gdGhlIHVzZXIgYXR0ZW1wdHMgdG8gbG9nIGluLCB5b3UgY2FuIHVzZSB0aGlzIHRvIGRpc3BsYXkgdGhlIGdyb3VwcyBvZiB3aGljaCB0aGUgdXNlciBpcyBtZW1iZXIsIGFuZCBoYXZlIHRoZSB1c2VyIHNlbGVjdCB0aGUgY29ycmVjdCBncm91cCB0byBsb2cgaW4gdG8gZm9yIHRoaXMgc2Vzc2lvbi5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIGN1cnJlbnQgdXNlclxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKiAgICAgIGF1dGhNZ3IuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogc2Vzc2lvbk9iai51c2VySWQsIHRva2VuOiBzZXNzaW9uT2JqLmF1dGhfdG9rZW4gfSlcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAoZ3JvdXBzKSB7IFxuICAgICAqICAgICAgICAgICAgICBmb3IgKHZhciBpPTA7IGkgPCBncm91cHMubGVuZ3RoOyBpKyspIFxuICAgICAqICAgICAgICAgICAgICAgICAgeyBjb25zb2xlLmxvZyhncm91cHNbaV0ubmFtZSk7IH1cbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gZ2V0IGdyb3VwcyBmb3IgcGFydGljdWxhciB1c2VyXG4gICAgICogICAgICBhdXRoTWdyLmdldFVzZXJHcm91cHMoe3VzZXJJZDogJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHRva2VuOiBzYXZlZFByb2pBY2Nlc3NUb2tlbiB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBwYXJhbXNgIE9iamVjdCB3aXRoIGEgdXNlcklkIGFuZCB0b2tlbiBwcm9wZXJ0aWVzLlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgcGFyYW1zLnVzZXJJZGAgVGhlIHVzZXJJZC4gSWYgbG9va2luZyB1cCBncm91cHMgZm9yIHRoZSBjdXJyZW50bHkgbG9nZ2VkIGluIHVzZXIsIHRoaXMgaXMgaW4gdGhlIHNlc3Npb24gaW5mb3JtYXRpb24uIE90aGVyd2lzZSwgcGFzcyBhIHN0cmluZy5cbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gYHBhcmFtcy50b2tlbmAgVGhlIGF1dGhvcml6YXRpb24gY3JlZGVudGlhbHMgKGFjY2VzcyB0b2tlbikgdG8gdXNlIGZvciBjaGVja2luZyB0aGUgZ3JvdXBzIGZvciB0aGlzIHVzZXIuIElmIGxvb2tpbmcgdXAgZ3JvdXBzIGZvciB0aGUgY3VycmVudGx5IGxvZ2dlZCBpbiB1c2VyLCB0aGlzIGlzIGluIHRoZSBzZXNzaW9uIGluZm9ybWF0aW9uLiBBIHRlYW0gbWVtYmVyJ3MgdG9rZW4gb3IgYSBwcm9qZWN0IGFjY2VzcyB0b2tlbiBjYW4gYWNjZXNzIGFsbCB0aGUgZ3JvdXBzIGZvciBhbGwgZW5kIHVzZXJzIGluIHRoZSB0ZWFtIG9yIHByb2plY3QuXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldFVzZXJHcm91cHM6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGFkYXB0ZXJPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgeyBzdWNjZXNzOiAkLm5vb3AgfSwgdGhpcy5vcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgb3V0U3VjY2VzcyA9IGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3M7XG5cbiAgICAgICAgYWRhcHRlck9wdGlvbnMuc3VjY2VzcyA9IGZ1bmN0aW9uIChtZW1iZXJJbmZvKSB7XG4gICAgICAgICAgICAvLyBUaGUgbWVtYmVyIEFQSSBpcyBhdCB0aGUgYWNjb3VudCBzY29wZSwgd2UgZmlsdGVyIGJ5IHByb2plY3RcbiAgICAgICAgICAgIGlmIChhZGFwdGVyT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgbWVtYmVySW5mbyA9ICQuZ3JlcChtZW1iZXJJbmZvLCBmdW5jdGlvbiAoZ3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGdyb3VwLnByb2plY3QgPT09IGFkYXB0ZXJPcHRpb25zLnByb2plY3Q7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW21lbWJlckluZm9dKTtcbiAgICAgICAgICAgICRkLnJlc29sdmUobWVtYmVySW5mbyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIG1lbWJlckFkYXB0ZXIgPSBuZXcgTWVtYmVyQWRhcHRlcih7IHRva2VuOiBwYXJhbXMudG9rZW4gfSk7XG4gICAgICAgIG1lbWJlckFkYXB0ZXIuZ2V0R3JvdXBzRm9yVXNlcihwYXJhbXMsIGFkYXB0ZXJPcHRpb25zKS5mYWlsKCRkLnJlamVjdCk7XG4gICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgc2Vzc2lvbiBpbmZvcm1hdGlvbiBmb3IgdGhlIGN1cnJlbnQgdXNlciwgaW5jbHVkaW5nIHRoZSBgdXNlcklkYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGBncm91cElkYCwgYGdyb3VwTmFtZWAsIGBpc0ZhY2AgKHdoZXRoZXIgdGhlIGVuZCB1c2VyIGlzIGEgZmFjaWxpdGF0b3Igb2YgdGhpcyBncm91cCksIGFuZCBgYXV0aF90b2tlbmAgKHVzZXIgYWNjZXNzIHRva2VuKS5cbiAgICAgKlxuICAgICAqICpJbXBvcnRhbnQqOiBUaGlzIG1ldGhvZCBpcyBzeW5jaHJvbm91cy4gVGhlIHNlc3Npb24gaW5mb3JtYXRpb24gaXMgcmV0dXJuZWQgaW1tZWRpYXRlbHkgaW4gYW4gb2JqZWN0OyBubyBjYWxsYmFja3Mgb3IgcHJvbWlzZXMgYXJlIG5lZWRlZC5cbiAgICAgKlxuICAgICAqIEJ5IGRlZmF1bHQsIHNlc3Npb24gaW5mb3JtYXRpb24gaXMgc3RvcmVkIGluIGEgY29va2llIGluIHRoZSBicm93c2VyLiBZb3UgY2FuIGNoYW5nZSB0aGlzIHdpdGggdGhlIGBzdG9yZWAgY29uZmlndXJhdGlvbiBvcHRpb24uIFxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm86IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiBnZXRTZXNzaW9uKG9wdGlvbnMpO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEF1dGhNYW5hZ2VyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ2hhbm5lbCA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlJyk7XG5cbi8qKlxuICogIyMgQ2hhbm5lbCBNYW5hZ2VyXG4gKlxuICogVGhlcmUgYXJlIHR3byBtYWluIHVzZSBjYXNlcyBmb3IgdGhlIGNoYW5uZWw6IGV2ZW50IG5vdGlmaWNhdGlvbnMgYW5kIGNoYXQgbWVzc2FnZXMuXG4gKlxuICogVGhlIENoYW5uZWwgTWFuYWdlciBpcyBhIHdyYXBwZXIgYXJvdW5kIHRoZSBkZWZhdWx0IFtjb21ldGQgSmF2YVNjcmlwdCBsaWJyYXJ5XShodHRwOi8vZG9jcy5jb21ldGQub3JnLzIvcmVmZXJlbmNlL2phdmFzY3JpcHQuaHRtbCksIGAkLmNvbWV0ZGAuIEl0IHByb3ZpZGVzIGEgZmV3IG5pY2UgZmVhdHVyZXMgdGhhdCBgJC5jb21ldGRgIGRvZXNuJ3QsIGluY2x1ZGluZzpcbiAqXG4gKiAqIEF1dG9tYXRpYyByZS1zdWJzY3JpcHRpb24gdG8gY2hhbm5lbHMgaWYgeW91IGxvc2UgeW91ciBjb25uZWN0aW9uXG4gKiAqIE9ubGluZSAvIE9mZmxpbmUgbm90aWZpY2F0aW9uc1xuICogKiAnRXZlbnRzJyBmb3IgY29tZXRkIG5vdGlmaWNhdGlvbnMgKGluc3RlYWQgb2YgaGF2aW5nIHRvIGxpc3RlbiBvbiBzcGVjaWZpYyBtZXRhIGNoYW5uZWxzKVxuICpcbiAqIFdoaWxlIHlvdSBjYW4gd29yayBkaXJlY3RseSB3aXRoIHRoZSBDaGFubmVsIE1hbmFnZXIgdGhyb3VnaCBOb2RlLmpzIChmb3IgZXhhbXBsZSwgYHJlcXVpcmUoJ21hbmFnZXIvY2hhbm5lbC1tYW5hZ2VyJylgKSAtLSBvciBldmVuIHdvcmsgZGlyZWN0bHkgd2l0aCBgJC5jb21ldGRgIGFuZCBFcGljZW50ZXIncyB1bmRlcmx5aW5nIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIC0tIG1vc3Qgb2Z0ZW4gaXQgd2lsbCBiZSBlYXNpZXN0IHRvIHdvcmsgd2l0aCB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKS4gVGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaXMgYSB3cmFwcGVyIHRoYXQgaW5zdGFudGlhdGVzIGEgQ2hhbm5lbCBNYW5hZ2VyIHdpdGggRXBpY2VudGVyLXNwZWNpZmljIGRlZmF1bHRzLlxuICpcbiAqIFlvdSdsbCBuZWVkIHRvIGluY2x1ZGUgdGhlIGBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzYCBsaWJyYXJ5IGluIGFkZGl0aW9uIHRvIHRoZSBgZXBpY2VudGVyLmpzYCBsaWJyYXJ5IGluIHlvdXIgcHJvamVjdCB0byB1c2UgdGhlIENoYW5uZWwgTWFuYWdlci4gKFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLilcbiAqXG4gKiBUbyB1c2UgdGhlIENoYW5uZWwgTWFuYWdlciBpbiBjbGllbnQtc2lkZSBKYXZhU2NyaXB0LCBpbnN0YW50aWF0ZSB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKSwgZ2V0IHRoZSBjaGFubmVsLCB0aGVuIHVzZSB0aGUgY2hhbm5lbCdzIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gc3Vic2NyaWJlIHRvIHRvcGljcyBvciBwdWJsaXNoIGRhdGEgdG8gdG9waWNzLlxuICpcbiAqICAgICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gKiAgICAgICAgdmFyIGNoYW5uZWwgPSBjbS5nZXRDaGFubmVsKCk7XG4gKlxuICogICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCd0b3BpYycsIGNhbGxiYWNrKTtcbiAqICAgICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIFRoZSBvcHRpb25zIG9iamVjdCB0byBjb25maWd1cmUgdGhlIENoYW5uZWwgTWFuYWdlci4gQmVzaWRlcyB0aGUgY29tbW9uIG9wdGlvbnMgbGlzdGVkIGhlcmUsIHNlZSBodHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0Lmh0bWwgZm9yIG90aGVyIHN1cHBvcnRlZCBvcHRpb25zLlxuICogKiBgb3B0aW9ucy51cmxgIFRoZSBDb21ldGQgZW5kcG9pbnQgVVJMLlxuICogKiBgb3B0aW9ucy53ZWJzb2NrZXRFbmFibGVkYCBXaGV0aGVyIHdlYnNvY2tldCBzdXBwb3J0IGlzIGFjdGl2ZSAoYm9vbGVhbikuXG4gKiAqIGBvcHRpb25zLmNoYW5uZWxgIE90aGVyIGRlZmF1bHRzIHRvIHBhc3Mgb24gdG8gaW5zdGFuY2VzIG9mIHRoZSB1bmRlcmx5aW5nIENoYW5uZWwgU2VydmljZS4gU2VlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pIGZvciBkZXRhaWxzLlxuICpcbiAqL1xudmFyIENoYW5uZWxNYW5hZ2VyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICBpZiAoISQuY29tZXRkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignQ29tZXRkIGxpYnJhcnkgbm90IGZvdW5kLiBQbGVhc2UgaW5jbHVkZSBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzJyk7XG4gICAgfVxuICAgIGlmICghb3B0aW9ucyB8fCAhb3B0aW9ucy51cmwpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhbiB1cmwgZm9yIHRoZSBjb21ldGQgc2VydmVyJyk7XG4gICAgfVxuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIENvbWV0ZCBlbmRwb2ludCBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1cmw6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbG9nIGxldmVsIGZvciB0aGUgY2hhbm5lbCAobG9ncyB0byBjb25zb2xlKS5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGxvZ0xldmVsOiAnaW5mbycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFdoZXRoZXIgd2Vic29ja2V0IHN1cHBvcnQgaXMgYWN0aXZlLiBEZWZhdWx0cyB0byBgZmFsc2VgOyBFcGljZW50ZXIgZG9lc24ndCBjdXJyZW50bHkgc3VwcG9ydCBjb21tdW5pY2F0aW9uIHRocm91Z2ggd2Vic29ja2V0cy5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICB3ZWJzb2NrZXRFbmFibGVkOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogSWYgZmFsc2UgZWFjaCBpbnN0YW5jZSBvZiBDaGFubmVsIHdpbGwgaGF2ZSBhIHNlcGFyYXRlIGNvbWV0ZCBjb25uZWN0aW9uIHRvIHNlcnZlciwgd2hpY2ggY291bGQgYmUgbm9pc3kuIFNldCB0byB0cnVlIHRvIHJlLXVzZSB0aGUgc2FtZSBjb25uZWN0aW9uIGFjcm9zcyBpbnN0YW5jZXMuXG4gICAgICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAgICAgKi9cbiAgICAgICAgc2hhcmVDb25uZWN0aW9uOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3RoZXIgZGVmYXVsdHMgdG8gcGFzcyBvbiB0byBpbnN0YW5jZXMgb2YgdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLyksIHdoaWNoIGFyZSBjcmVhdGVkIHRocm91Z2ggYGdldENoYW5uZWwoKWAuXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBjaGFubmVsOiB7XG5cbiAgICAgICAgfVxuICAgIH07XG4gICAgdmFyIGRlZmF1bHRDb21ldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMgPSBbXTtcbiAgICB0aGlzLm9wdGlvbnMgPSBkZWZhdWx0Q29tZXRPcHRpb25zO1xuXG4gICAgaWYgKGRlZmF1bHRDb21ldE9wdGlvbnMuc2hhcmVDb25uZWN0aW9uICYmIENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZS5fY29tZXRkKSB7XG4gICAgICAgIHRoaXMuY29tZXRkID0gQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQ7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbiAgICB2YXIgY29tZXRkID0gbmV3ICQuQ29tZXRkKCk7XG4gICAgQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQgPSBjb21ldGQ7XG5cbiAgICBjb21ldGQud2Vic29ja2V0RW5hYmxlZCA9IGRlZmF1bHRDb21ldE9wdGlvbnMud2Vic29ja2V0RW5hYmxlZDtcblxuICAgIHRoaXMuaXNDb25uZWN0ZWQgPSBmYWxzZTtcbiAgICB2YXIgY29ubmVjdGlvbkJyb2tlbiA9IGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQodGhpcykudHJpZ2dlcignZGlzY29ubmVjdCcsIG1lc3NhZ2UpO1xuICAgIH07XG4gICAgdmFyIGNvbm5lY3Rpb25TdWNjZWVkZWQgPSBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIoJ2Nvbm5lY3QnLCBtZXNzYWdlKTtcbiAgICB9O1xuICAgIHZhciBtZSA9IHRoaXM7XG5cbiAgICBjb21ldGQuY29uZmlndXJlKGRlZmF1bHRDb21ldE9wdGlvbnMpO1xuXG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9jb25uZWN0JywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgdmFyIHdhc0Nvbm5lY3RlZCA9IHRoaXMuaXNDb25uZWN0ZWQ7XG4gICAgICAgIHRoaXMuaXNDb25uZWN0ZWQgPSAobWVzc2FnZS5zdWNjZXNzZnVsID09PSB0cnVlKTtcbiAgICAgICAgaWYgKCF3YXNDb25uZWN0ZWQgJiYgdGhpcy5pc0Nvbm5lY3RlZCkgeyAvL0Nvbm5lY3RpbmcgZm9yIHRoZSBmaXJzdCB0aW1lXG4gICAgICAgICAgICBjb25uZWN0aW9uU3VjY2VlZGVkLmNhbGwodGhpcywgbWVzc2FnZSk7XG4gICAgICAgIH0gZWxzZSBpZiAod2FzQ29ubmVjdGVkICYmICF0aGlzLmlzQ29ubmVjdGVkKSB7IC8vT25seSB0aHJvdyBkaXNjb25uZWN0ZWQgbWVzc2FnZSBmcm8gdGhlIGZpcnN0IGRpc2Nvbm5lY3QsIG5vdCBvbmNlIHBlciB0cnlcbiAgICAgICAgICAgIGNvbm5lY3Rpb25Ccm9rZW4uY2FsbCh0aGlzLCBtZXNzYWdlKTtcbiAgICAgICAgfVxuICAgIH0uYmluZCh0aGlzKSk7XG5cbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL2Rpc2Nvbm5lY3QnLCBjb25uZWN0aW9uQnJva2VuKTtcblxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvaGFuZHNoYWtlJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgaWYgKG1lc3NhZ2Uuc3VjY2Vzc2Z1bCkge1xuICAgICAgICAgICAgLy9odHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0X3N1YnNjcmliZS5odG1sI2phdmFzY3JpcHRfc3Vic2NyaWJlX21ldGFfY2hhbm5lbHNcbiAgICAgICAgICAgIC8vIF4gXCJkeW5hbWljIHN1YnNjcmlwdGlvbnMgYXJlIGNsZWFyZWQgKGxpa2UgYW55IG90aGVyIHN1YnNjcmlwdGlvbikgYW5kIHRoZSBhcHBsaWNhdGlvbiBuZWVkcyB0byBmaWd1cmUgb3V0IHdoaWNoIGR5bmFtaWMgc3Vic2NyaXB0aW9uIG11c3QgYmUgcGVyZm9ybWVkIGFnYWluXCJcbiAgICAgICAgICAgIGNvbWV0ZC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgJChtZS5jdXJyZW50U3Vic2NyaXB0aW9ucykuZWFjaChmdW5jdGlvbiAoaW5kZXgsIHN1YnMpIHtcbiAgICAgICAgICAgICAgICAgICAgY29tZXRkLnJlc3Vic2NyaWJlKHN1YnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vT3RoZXIgaW50ZXJlc3RpbmcgZXZlbnRzIGZvciByZWZlcmVuY2VcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3N1YnNjcmliZScsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3N1YnNjcmliZScsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvdW5zdWJzY3JpYmUnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKG1lKS50cmlnZ2VyKCd1bnN1YnNjcmliZScsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvcHVibGlzaCcsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3B1Ymxpc2gnLCBtZXNzYWdlKTtcbiAgICB9KTtcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3Vuc3VjY2Vzc2Z1bCcsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ2Vycm9yJywgbWVzc2FnZSk7XG4gICAgfSk7XG5cbiAgICBjb21ldGQuaGFuZHNoYWtlKCk7XG5cbiAgICB0aGlzLmNvbWV0ZCA9IGNvbWV0ZDtcbn07XG5cblxuQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlID0gJC5leHRlbmQoQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLCB7XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgY2hhbm5lbCwgdGhhdCBpcywgYW4gaW5zdGFuY2Ugb2YgYSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgIHZhciBjaGFubmVsID0gY20uZ2V0Q2hhbm5lbCgpO1xuICAgICAqXG4gICAgICogICAgICBjaGFubmVsLnN1YnNjcmliZSgndG9waWMnLCBjYWxsYmFjayk7XG4gICAgICogICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBJZiBzdHJpbmcsIGFzc3VtZWQgdG8gYmUgdGhlIGJhc2UgY2hhbm5lbCB1cmwuIElmIG9iamVjdCwgYXNzdW1lZCB0byBiZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjb25zdHJ1Y3Rvci5cbiAgICAgKi9cbiAgICBnZXRDaGFubmVsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvL0lmIHlvdSBqdXN0IHdhbnQgdG8gcGFzcyBpbiBhIHN0cmluZ1xuICAgICAgICBpZiAob3B0aW9ucyAmJiAhJC5pc1BsYWluT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgICAgICAgICBvcHRpb25zID0ge1xuICAgICAgICAgICAgICAgIGJhc2U6IG9wdGlvbnNcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAgICAgdHJhbnNwb3J0OiB0aGlzLmNvbWV0ZFxuICAgICAgICB9O1xuICAgICAgICB2YXIgY2hhbm5lbCA9IG5ldyBDaGFubmVsKCQuZXh0ZW5kKHRydWUsIHt9LCB0aGlzLm9wdGlvbnMuY2hhbm5lbCwgZGVmYXVsdHMsIG9wdGlvbnMpKTtcblxuXG4gICAgICAgIC8vV3JhcCBzdWJzIGFuZCB1bnN1YnMgc28gd2UgY2FuIHVzZSBpdCB0byByZS1hdHRhY2ggaGFuZGxlcnMgYWZ0ZXIgYmVpbmcgZGlzY29ubmVjdGVkXG4gICAgICAgIHZhciBzdWJzID0gY2hhbm5lbC5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHN1YmlkID0gc3Vicy5hcHBseShjaGFubmVsLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucyAgPSB0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zLmNvbmNhdChzdWJpZCk7XG4gICAgICAgICAgICByZXR1cm4gc3ViaWQ7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuXG4gICAgICAgIHZhciB1bnN1YnMgPSBjaGFubmVsLnVuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnVuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJlbW92ZWQgPSB1bnN1YnMuYXBwbHkoY2hhbm5lbCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zW2ldLmlkID09PSByZW1vdmVkLmlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMuc3BsaWNlKGksIDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZW1vdmVkO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0YXJ0IGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqXG4gICAgICogU3VwcG9ydGVkIGV2ZW50cyBhcmU6IGBjb25uZWN0YCwgYGRpc2Nvbm5lY3RgLCBgc3Vic2NyaWJlYCwgYHVuc3Vic2NyaWJlYCwgYHB1Ymxpc2hgLCBgZXJyb3JgLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29uLy5cbiAgICAgKi9cbiAgICBvbjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub24uYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RvcCBsaXN0ZW5pbmcgZm9yIGV2ZW50cyBvbiB0aGlzIGluc3RhbmNlLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKi9cbiAgICBvZmY6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLm9mZi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUcmlnZ2VyIGV2ZW50cyBhbmQgZXhlY3V0ZSBoYW5kbGVycy4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKi9cbiAgICB0cmlnZ2VyOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuICogIyMgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlclxuICpcbiAqIFRoZSBFcGljZW50ZXIgcGxhdGZvcm0gcHJvdmlkZXMgYSBwdXNoIGNoYW5uZWwsIHdoaWNoIGFsbG93cyB5b3UgdG8gcHVibGlzaCBhbmQgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzIHdpdGhpbiBhIFtwcm9qZWN0XSguLi8uLi8uLi9nbG9zc2FyeS8jcHJvamVjdHMpLCBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvciBbbXVsdGlwbGF5ZXIgd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuIFRoZXJlIGFyZSB0d28gbWFpbiB1c2UgY2FzZXMgZm9yIHRoZSBjaGFubmVsOiBldmVudCBub3RpZmljYXRpb25zIGFuZCBjaGF0IG1lc3NhZ2VzLlxuICpcbiAqIFRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIGEgd3JhcHBlciBhcm91bmQgdGhlIChtb3JlIGdlbmVyaWMpIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pLCB0byBpbnN0YW50aWF0ZSBpdCB3aXRoIEVwaWNlbnRlci1zcGVjaWZpYyBkZWZhdWx0cy4gSWYgeW91IGFyZSBpbnRlcmVzdGVkIGluIGluY2x1ZGluZyBhIG5vdGlmaWNhdGlvbiBvciBjaGF0IGZlYXR1cmUgaW4geW91ciBwcm9qZWN0LCB1c2luZyBhbiBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIHByb2JhYmx5IHRoZSBlYXNpZXN0IHdheSB0byBnZXQgc3RhcnRlZC5cbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyLiBTZWUgW0luY2x1ZGluZyBFcGljZW50ZXIuanNdKC4uLy4uLyNpbmNsdWRlKS5cbiAqXG4gKiBUbyB1c2UgdGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXI6IGluc3RhbnRpYXRlIGl0LCBnZXQgdGhlIGNoYW5uZWwgb2YgdGhlIHNjb3BlIHlvdSB3YW50IChbdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgW3dvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLCBvciBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpKSwgdGhlbiB1c2UgdGhlIGNoYW5uZWwncyBgc3Vic2NyaWJlKClgIGFuZCBgcHVibGlzaCgpYCBtZXRob2RzIHRvIHN1YnNjcmliZSB0byB0b3BpY3Mgb3IgcHVibGlzaCBkYXRhIHRvIHRvcGljcy5cbiAqXG4gKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICogICAgIHZhciBnYyA9IGNtLmdldEdyb3VwQ2hhbm5lbCgpO1xuICogICAgIGdjLnN1YnNjcmliZSgnYnJvYWRjYXN0cycsIGNhbGxiYWNrKTtcbiAqXG4gKiBGb3IgYWRkaXRpb25hbCBiYWNrZ3JvdW5kIG9uIEVwaWNlbnRlcidzIHB1c2ggY2hhbm5lbCwgc2VlIHRoZSBpbnRyb2R1Y3Rvcnkgbm90ZXMgb24gdGhlIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIHBhZ2UuXG4gKlxuICogVGhlIHBhcmFtZXRlcnMgZm9yIGluc3RhbnRpYXRpbmcgYW4gRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYHNlcnZlcmAgT2JqZWN0IHdpdGggZGV0YWlscyBhYm91dCB0aGUgRXBpY2VudGVyIHByb2plY3QgZm9yIHRoaXMgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpbnN0YW5jZS5cbiAqICogYHNlcnZlci5hY2NvdW50YCBUaGUgRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICogKiBgc2VydmVyLnByb2plY3RgIEVwaWNlbnRlciBwcm9qZWN0IGlkLlxuICovXG5cbnZhciBDaGFubmVsTWFuYWdlciA9IHJlcXVpcmUoJy4vY2hhbm5lbC1tYW5hZ2VyJyk7XG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgdXJsU2VydmljZSA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlJyk7XG5cbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBzZXNzaW9uID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG52YXIgZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvciA9IGZ1bmN0aW9uICh2YWx1ZSwgc2Vzc2lvbktleU5hbWUsIHNldHRpbmdzKSB7XG4gICAgaWYgKCF2YWx1ZSkge1xuICAgICAgICB2YXIgdXNlckluZm8gPSBzZXNzaW9uLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgaWYgKHNldHRpbmdzICYmIHNldHRpbmdzW3Nlc3Npb25LZXlOYW1lXSkge1xuICAgICAgICAgICAgdmFsdWUgPSBzZXR0aW5nc1tzZXNzaW9uS2V5TmFtZV07XG4gICAgICAgIH0gZWxzZSBpZiAodXNlckluZm9bc2Vzc2lvbktleU5hbWVdKSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHVzZXJJbmZvW3Nlc3Npb25LZXlOYW1lXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihzZXNzaW9uS2V5TmFtZSArICcgbm90IGZvdW5kLiBQbGVhc2UgbG9nLWluIGFnYWluLCBvciBzcGVjaWZ5ICcgKyBzZXNzaW9uS2V5TmFtZSArICcgZXhwbGljaXRseScpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZTtcbn07XG52YXIgX19zdXBlciA9IENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZTtcbnZhciBFcGljZW50ZXJDaGFubmVsTWFuYWdlciA9IGNsYXNzRnJvbShDaGFubmVsTWFuYWdlciwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgdXNlckluZm8gPSBzZXNzaW9uLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcblxuICAgICAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgICAgICBhY2NvdW50OiB1c2VySW5mby5hY2NvdW50LFxuICAgICAgICAgICAgcHJvamVjdDogdXNlckluZm8ucHJvamVjdCxcbiAgICAgICAgfTtcbiAgICAgICAgdmFyIGRlZmF1bHRDb21ldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIHVzZXJJbmZvLCBvcHRpb25zKTtcblxuICAgICAgICB2YXIgdXJsT3B0cyA9IHVybFNlcnZpY2UoZGVmYXVsdENvbWV0T3B0aW9ucy5zZXJ2ZXIpO1xuICAgICAgICBpZiAoIWRlZmF1bHRDb21ldE9wdGlvbnMudXJsKSB7XG4gICAgICAgICAgICAvL0RlZmF1bHQgZXBpY2VudGVyIGNvbWV0ZCBlbmRwb2ludFxuICAgICAgICAgICAgZGVmYXVsdENvbWV0T3B0aW9ucy51cmwgPSB1cmxPcHRzLnByb3RvY29sICsgJzovLycgKyB1cmxPcHRzLmhvc3QgKyAnL2NoYW5uZWwvc3Vic2NyaWJlJztcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMub3B0aW9ucyA9IGRlZmF1bHRDb21ldE9wdGlvbnM7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgZGVmYXVsdENvbWV0T3B0aW9ucyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhbmQgcmV0dXJuIGEgcHVibGlzaC9zdWJzY3JpYmUgY2hhbm5lbCAoZnJvbSB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSkgZm9yIHRoZSBnaXZlbiBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLiBUaGUgZ3JvdXAgbXVzdCBleGlzdCBpbiB0aGUgYWNjb3VudCAodGVhbSkgYW5kIHByb2plY3QgcHJvdmlkZWQuXG4gICAgICpcbiAgICAgKiBUaGVyZSBhcmUgbm8gbm90aWZpY2F0aW9ucyBmcm9tIEVwaWNlbnRlciBvbiB0aGlzIGNoYW5uZWw7IGFsbCBtZXNzYWdlcyBhcmUgdXNlci1vcmlnaW5hdGVkLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciBnYyA9IGNtLmdldEdyb3VwQ2hhbm5lbCgpO1xuICAgICAqICAgICBnYy5zdWJzY3JpYmUoJ2Jyb2FkY2FzdHMnLCBjYWxsYmFjayk7XG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBHcm91cCB0byBicm9hZGNhc3QgdG8uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldEdyb3VwQ2hhbm5lbDogZnVuY3Rpb24gKGdyb3VwTmFtZSkge1xuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScpO1xuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2dyb3VwJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lXS5qb2luKCcvJyk7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIFt3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS5cbiAgICAgKlxuICAgICAqIFRoaXMgaXMgdHlwaWNhbGx5IHVzZWQgdG9nZXRoZXIgd2l0aCB0aGUgW1dvcmxkIE1hbmFnZXJdKC4uL3dvcmxkLW1hbmFnZXIpLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciB3b3JsZE1hbmFnZXIgPSBuZXcgRi5tYW5hZ2VyLldvcmxkTWFuYWdlcih7XG4gICAgICogICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICogICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAqICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gICAgICogICAgICAgICBydW46IHsgbW9kZWw6ICdtb2RlbC5lcW4nIH1cbiAgICAgKiAgICAgfSk7XG4gICAgICogICAgIHdvcmxkTWFuYWdlci5nZXRDdXJyZW50V29ybGQoKS50aGVuKGZ1bmN0aW9uICh3b3JsZE9iamVjdCwgd29ybGRBZGFwdGVyKSB7XG4gICAgICogICAgICAgICB2YXIgd29ybGRDaGFubmVsID0gY20uZ2V0V29ybGRDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHdvcmxkQ2hhbm5lbC5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICogICAgICAgICAgICAgY29uc29sZS5sb2coZGF0YSk7XG4gICAgICogICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSBgd29ybGRgIFRoZSB3b3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFdvcmxkQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCBncm91cE5hbWUpIHtcbiAgICAgICAgdmFyIHdvcmxkaWQgPSAoJC5pc1BsYWluT2JqZWN0KHdvcmxkKSAmJiB3b3JsZC5pZCkgPyB3b3JsZC5pZCA6IHdvcmxkO1xuICAgICAgICBpZiAoIXdvcmxkaWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHNwZWNpZnkgYSB3b3JsZCBpZCcpO1xuICAgICAgICB9XG4gICAgICAgIGdyb3VwTmFtZSA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJyk7XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvd29ybGQnLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWUsIHdvcmxkaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgY3VycmVudCBbZW5kIHVzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycykgaW4gdGhhdCB1c2VyJ3MgY3VycmVudCBbd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuXG4gICAgICpcbiAgICAgKiBUaGlzIGlzIHR5cGljYWxseSB1c2VkIHRvZ2V0aGVyIHdpdGggdGhlIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyKS4gTm90ZSB0aGF0IHRoaXMgY2hhbm5lbCBvbmx5IGdldHMgbm90aWZpY2F0aW9ucyBmb3Igd29ybGRzIGN1cnJlbnRseSBpbiBtZW1vcnkuIChTZWUgbW9yZSBiYWNrZ3JvdW5kIG9uIFtwZXJzaXN0ZW5jZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlKS4pXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIHdvcmxkTWFuYWdlciA9IG5ldyBGLm1hbmFnZXIuV29ybGRNYW5hZ2VyKHtcbiAgICAgKiAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgKiAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICogICAgICAgICBncm91cDogJ3RlYW0xJyxcbiAgICAgKiAgICAgICAgIHJ1bjogeyBtb2RlbDogJ21vZGVsLmVxbicgfVxuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgKiAgICAgICAgIHZhciB1c2VyQ2hhbm5lbCA9IGNtLmdldFVzZXJDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHVzZXJDaGFubmVsLnN1YnNjcmliZSgnJywgZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgKiAgICAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKiAgICAgICAgIH0pO1xuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHdvcmxkYCBXb3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHVzZXJgIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFVzZXJDaGFubmVsOiBmdW5jdGlvbiAod29ybGQsIHVzZXIsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVzZXJpZCA9ICgkLmlzUGxhaW5PYmplY3QodXNlcikgJiYgdXNlci5pZCkgPyB1c2VyLmlkIDogdXNlcjtcbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnKTtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcihncm91cE5hbWUsICdncm91cE5hbWUnKTtcblxuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3VzZXJzJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkLCB1c2VyaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIHRoYXQgYXV0b21hdGljYWxseSB0cmFja3MgdGhlIHByZXNlbmNlIG9mIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgdGhhdCBpcywgd2hldGhlciB0aGUgZW5kIHVzZXIgaXMgY3VycmVudGx5IG9ubGluZSBpbiB0aGlzIGdyb3VwIGFuZCB3b3JsZC4gTm90aWZpY2F0aW9ucyBhcmUgYXV0b21hdGljYWxseSBzZW50IHdoZW4gdGhlIGVuZCB1c2VyIGNvbWVzIG9ubGluZSwgYW5kIHdoZW4gdGhlIGVuZCB1c2VyIGdvZXMgb2ZmbGluZSAobm90IHByZXNlbnQgZm9yIG1vcmUgdGhhbiAyIG1pbnV0ZXMpLiBVc2VmdWwgaW4gbXVsdGlwbGF5ZXIgZ2FtZXMgZm9yIGxldHRpbmcgZWFjaCBlbmQgdXNlciBrbm93IHdoZXRoZXIgb3RoZXIgdXNlcnMgaW4gdGhlaXIgc2hhcmVkIHdvcmxkIGFyZSBhbHNvIG9ubGluZS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgd29ybGRNYW5hZ2VyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuICAgICAqICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAqICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgKiAgICAgICAgIG1vZGVsOiAnbW9kZWwuZXFuJ1xuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZFNlcnZpY2UpIHtcbiAgICAgKiAgICAgICAgIHZhciBwcmVzZW5jZUNoYW5uZWwgPSBjbS5nZXRQcmVzZW5jZUNoYW5uZWwod29ybGRPYmplY3QpO1xuICAgICAqICAgICAgICAgcHJlc2VuY2VDaGFubmVsLm9uKCdwcmVzZW5jZScsIGZ1bmN0aW9uIChldnQsIG5vdGlmaWNhdGlvbikge1xuICAgICAqICAgICAgICAgICAgICBjb25zb2xlLmxvZyhub3RpZmljYXRpb24ub25saW5lLCBub3RpZmljYXRpb24udXNlcklkKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB3b3JsZGAgV29ybGQgb2JqZWN0IG9yIGlkLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB1c2VyaWRgIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFByZXNlbmNlQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCB1c2VyaWQsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnKTtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcihncm91cE5hbWUsICdncm91cE5hbWUnKTtcblxuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3VzZXJzJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG5cbiAgICAgICAgdmFyIGxhc3RQaW5nVGltZSA9IHsgfTtcblxuICAgICAgICB2YXIgUElOR19JTlRFUlZBTCA9IDYwMDA7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCdpbnRlcm5hbC1waW5nLWNoYW5uZWwnLCBmdW5jdGlvbiAobm90aWZpY2F0aW9uKSB7XG4gICAgICAgICAgICB2YXIgaW5jb21pbmdVc2VySWQgPSBub3RpZmljYXRpb24uZGF0YS51c2VyO1xuICAgICAgICAgICAgaWYgKCFsYXN0UGluZ1RpbWVbaW5jb21pbmdVc2VySWRdICYmIGluY29taW5nVXNlcklkICE9PSB1c2VyaWQpIHtcbiAgICAgICAgICAgICAgICBjaGFubmVsLnRyaWdnZXIuY2FsbChjaGFubmVsLCAncHJlc2VuY2UnLCB7IHVzZXJJZDogaW5jb21pbmdVc2VySWQsIG9ubGluZTogdHJ1ZSB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxhc3RQaW5nVGltZVtpbmNvbWluZ1VzZXJJZF0gPSAobmV3IERhdGUoKSkudmFsdWVPZigpO1xuICAgICAgICB9KTtcblxuICAgICAgICBzZXRJbnRlcnZhbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBjaGFubmVsLnB1Ymxpc2goJ2ludGVybmFsLXBpbmctY2hhbm5lbCcsIHsgdXNlcjogdXNlcmlkIH0pO1xuXG4gICAgICAgICAgICAkLmVhY2gobGFzdFBpbmdUaW1lLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHZhciBub3cgPSAobmV3IERhdGUoKSkudmFsdWVPZigpO1xuICAgICAgICAgICAgICAgIGlmICh2YWx1ZSAmJiB2YWx1ZSArIChQSU5HX0lOVEVSVkFMICogMikgPCBub3cpIHtcbiAgICAgICAgICAgICAgICAgICAgbGFzdFBpbmdUaW1lW2tleV0gPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICBjaGFubmVsLnRyaWdnZXIuY2FsbChjaGFubmVsLCAncHJlc2VuY2UnLCB7IHVzZXJJZDoga2V5LCBvbmxpbmU6IGZhbHNlIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LCBQSU5HX0lOVEVSVkFMKTtcblxuICAgICAgICByZXR1cm4gY2hhbm5lbDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIGNvbGxlY3Rpb24uIChUaGUgY29sbGVjdGlvbiBuYW1lIGlzIHNwZWNpZmllZCBpbiB0aGUgYHJvb3RgIGFyZ3VtZW50IHdoZW4gdGhlIFtEYXRhIFNlcnZpY2VdKC4uL2RhdGEtYXBpLXNlcnZpY2UvKSBpcyBpbnN0YW50aWF0ZWQuKSBNdXN0IGJlIG9uZSBvZiB0aGUgY29sbGVjdGlvbnMgaW4gdGhpcyBhY2NvdW50ICh0ZWFtKSBhbmQgcHJvamVjdC5cbiAgICAgKlxuICAgICAqIFRoZXJlIGFyZSBhdXRvbWF0aWMgbm90aWZpY2F0aW9ucyBmcm9tIEVwaWNlbnRlciBvbiB0aGlzIGNoYW5uZWwgd2hlbiBkYXRhIGlzIGNyZWF0ZWQsIHVwZGF0ZWQsIG9yIGRlbGV0ZWQgaW4gdGhpcyBjb2xsZWN0aW9uLiBTZWUgbW9yZSBvbiBbYXV0b21hdGljIG1lc3NhZ2VzIHRvIHRoZSBkYXRhIGNoYW5uZWxdKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLyNkYXRhLW1lc3NhZ2VzKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgZ2MgPSBjbS5nZXREYXRhQ2hhbm5lbCgnc3VydmV5LXJlc3BvbnNlcycpO1xuICAgICAqICAgICBnYy5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uKGRhdGEsIG1ldGEpIHtcbiAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKlxuICAgICAqICAgICAgICAgIC8vIG1ldGEuZGF0ZSBpcyB0aW1lIG9mIGNoYW5nZSxcbiAgICAgKiAgICAgICAgICAvLyBtZXRhLnN1YlR5cGUgaXMgdGhlIGtpbmQgb2YgY2hhbmdlOiBuZXcsIHVwZGF0ZSwgb3IgZGVsZXRlXG4gICAgICogICAgICAgICAgLy8gbWV0YS5wYXRoIGlzIHRoZSBmdWxsIHBhdGggdG8gdGhlIGNoYW5nZWQgZGF0YVxuICAgICAqICAgICAgICAgIGNvbnNvbGUubG9nKG1ldGEpO1xuICAgICAqICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgY29sbGVjdGlvbmAgTmFtZSBvZiBjb2xsZWN0aW9uIHdob3NlIGF1dG9tYXRpYyBub3RpZmljYXRpb25zIHlvdSB3YW50IHRvIHJlY2VpdmUuXG4gICAgICovXG4gICAgZ2V0RGF0YUNoYW5uZWw6IGZ1bmN0aW9uIChjb2xsZWN0aW9uKSB7XG4gICAgICAgIGlmICghY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIGNvbGxlY3Rpb24gdG8gbGlzdGVuIG9uLicpO1xuICAgICAgICB9XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2RhdGEnLCBhY2NvdW50LCBwcm9qZWN0LCBjb2xsZWN0aW9uXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG5cbiAgICAgICAgLy9UT0RPOiBGaXggYWZ0ZXIgRXBpY2VudGVyIGJ1ZyBpcyByZXNvbHZlZFxuICAgICAgICB2YXIgb2xkc3VicyA9IGNoYW5uZWwuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnN1YnNjcmliZSA9IGZ1bmN0aW9uICh0b3BpYywgY2FsbGJhY2ssIGNvbnRleHQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBjYWxsYmFja1dpdGhDbGVhbkRhdGEgPSBmdW5jdGlvbiAocGF5bG9hZCkge1xuICAgICAgICAgICAgICAgIHZhciBtZXRhID0ge1xuICAgICAgICAgICAgICAgICAgICBwYXRoOiBwYXlsb2FkLmNoYW5uZWwsXG4gICAgICAgICAgICAgICAgICAgIHN1YlR5cGU6IHBheWxvYWQuZGF0YS5zdWJUeXBlLFxuICAgICAgICAgICAgICAgICAgICBkYXRlOiBwYXlsb2FkLmRhdGEuZGF0ZVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdmFyIGFjdHVhbERhdGEgPSBwYXlsb2FkLmRhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICBpZiAoYWN0dWFsRGF0YS5kYXRhKSB7IC8vRGVsZXRlIG5vdGlmaWNhdGlvbnMgYXJlIG9uZSBkYXRhLWxldmVsIGJlaGluZCBvZiBjb3Vyc2VcbiAgICAgICAgICAgICAgICAgICAgYWN0dWFsRGF0YSA9IGFjdHVhbERhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBjYWxsYmFjay5jYWxsKGNvbnRleHQsIGFjdHVhbERhdGEsIG1ldGEpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiBvbGRzdWJzLmNhbGwoY2hhbm5lbCwgdG9waWMsIGNhbGxiYWNrV2l0aENsZWFuRGF0YSwgY29udGV4dCwgb3B0aW9ucyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gRXBpY2VudGVyQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIEVQSV9DT09LSUVfS0VZOiAnZXBpY2VudGVyLnByb2plY3QudG9rZW4nLFxuICAgIEVQSV9TRVNTSU9OX0tFWTogJ2VwaWNlbnRlci51c2VyLnNlc3Npb24nLFxuICAgIFNUUkFURUdZX1NFU1NJT05fS0VZOiAnZXBpY2VudGVyLXNjZW5hcmlvJ1xufTsiLCIvKipcbiogIyMgUnVuIE1hbmFnZXJcbipcbiogVGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBhY2Nlc3MgdG8gcnVucyBmb3IgeW91ciBwcm9qZWN0LiBUaGlzIGFsbG93cyB5b3UgdG8gcmVhZCBhbmQgdXBkYXRlIHZhcmlhYmxlcywgY2FsbCBvcGVyYXRpb25zLCBldGMuIEFkZGl0aW9uYWxseSwgdGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBjb250cm9sIG92ZXIgcnVuIGNyZWF0aW9uIGRlcGVuZGluZyBvbiBydW4gc3RhdGVzLiBTcGVjaWZpY2FsbHksIHlvdSBjYW4gc2VsZWN0IFtydW4gY3JlYXRpb24gc3RyYXRlZ2llcyAocnVsZXMpXSguLi8uLi9zdHJhdGVneS8pIGZvciB3aGljaCBydW5zIGVuZCB1c2VycyBvZiB5b3VyIHByb2plY3Qgd29yayB3aXRoIHdoZW4gdGhleSBsb2cgaW4gdG8geW91ciBwcm9qZWN0LlxuKlxuKiBUaGVyZSBhcmUgbWFueSB3YXlzIHRvIGNyZWF0ZSBuZXcgcnVucywgaW5jbHVkaW5nIHRoZSBFcGljZW50ZXIuanMgW1J1biBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSwgdGhlIFJFU0ZUZnVsIFtSdW4gQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkpIGFuZCB0aGUgW01vZGVsIFJ1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9vdGhlcl9hcGlzL21vZGVsX2FwaXMvcnVuLykuIEhvd2V2ZXIsIGZvciBzb21lIHByb2plY3RzIGl0IG1ha2VzIG1vcmUgc2Vuc2UgdG8gcGljayB1cCB3aGVyZSB0aGUgdXNlciBsZWZ0IG9mZiwgdXNpbmcgYW4gZXhpc3RpbmcgcnVuLiBBbmQgaW4gc29tZSBwcm9qZWN0cywgd2hldGhlciB0byBjcmVhdGUgYSBuZXcgcnVuIG9yIHVzZSBhbiBleGlzdGluZyBvbmUgaXMgY29uZGl0aW9uYWwsIGZvciBleGFtcGxlIGJhc2VkIG9uIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgZXhpc3RpbmcgcnVuIG9yIHlvdXIgb3duIGtub3dsZWRnZSBhYm91dCB0aGUgbW9kZWwuIFRoZSBSdW4gTWFuYWdlciBwcm92aWRlcyB0aGlzIGxldmVsIG9mIGNvbnRyb2w6IHlvdXIgY2FsbCB0byBgZ2V0UnVuKClgLCByYXRoZXIgdGhhbiBhbHdheXMgcmV0dXJuaW5nIGEgbmV3IHJ1biwgcmV0dXJucyBhIHJ1biBiYXNlZCBvbiB0aGUgc3RyYXRlZ3kgeW91J3ZlIHNwZWNpZmllZC4gKE5vdGUgdGhhdCBtYW55IG9mIHRoZSBFcGljZW50ZXIgc2FtcGxlIHByb2plY3RzIHVzZSBhIFJ1biBTZXJ2aWNlIGRpcmVjdGx5LCBiZWNhdXNlIGdlbmVyYWxseSB0aGUgc2FtcGxlIHByb2plY3RzIGFyZSBwbGF5ZWQgaW4gb25lIGVuZCB1c2VyIHNlc3Npb24gYW5kIGRvbid0IGNhcmUgYWJvdXQgcnVuIHN0YXRlcyBvciBydW4gc3RyYXRlZ2llcy4pXG4qXG4qXG4qICMjIyBVc2luZyB0aGUgUnVuIE1hbmFnZXIgdG8gY3JlYXRlIGFuZCBhY2Nlc3MgcnVuc1xuKlxuKiBUbyB1c2UgdGhlIFJ1biBNYW5hZ2VyLCBpbnN0YW50aWF0ZSBpdCBieSBwYXNzaW5nIGluOlxuKlxuKiAgICogYHJ1bmA6IChyZXF1aXJlZCkgUnVuIG9iamVjdC4gTXVzdCBjb250YWluOlxuKiAgICAgICAqIGBhY2NvdW50YDogRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuKiAgICAgICAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4qICAgICAgICogYG1vZGVsYDogVGhlIG5hbWUgb2YgeW91ciBwcmltYXJ5IG1vZGVsIGZpbGUuIChTZWUgbW9yZSBvbiBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4pXG4qICAgICAgICogYHNjb3BlYDogKG9wdGlvbmFsKSBTY29wZSBvYmplY3QgZm9yIHRoZSBydW4sIGZvciBleGFtcGxlIGBzY29wZS5ncm91cGAgd2l0aCB2YWx1ZSBvZiB0aGUgbmFtZSBvZiB0aGUgZ3JvdXAuXG4qICAgICAgICogYHNlcnZlcmA6IChvcHRpb25hbCkgQW4gb2JqZWN0IHdpdGggb25lIGZpZWxkLCBgaG9zdGAuIFRoZSB2YWx1ZSBvZiBgaG9zdGAgaXMgdGhlIHN0cmluZyBgYXBpLmZvcmlvLmNvbWAsIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4qICAgICAgICogYGZpbGVzYDogKG9wdGlvbmFsKSBJZiBhbmQgb25seSBpZiB5b3UgYXJlIHVzaW5nIGEgVmVuc2ltIG1vZGVsIGFuZCB5b3UgaGF2ZSBhZGRpdGlvbmFsIGRhdGEgdG8gcGFzcyBpbiB0byB5b3VyIG1vZGVsLCB5b3UgY2FuIHBhc3MgYSBgZmlsZXNgIG9iamVjdCB3aXRoIHRoZSBuYW1lcyBvZiB0aGUgZmlsZXMsIGZvciBleGFtcGxlOiBgXCJmaWxlc1wiOiB7XCJkYXRhXCI6IFwibXlFeHRyYURhdGEueGxzXCJ9YC4gKE5vdGUgdGhhdCB5b3UnbGwgYWxzbyBuZWVkIHRvIGFkZCB0aGlzIHNhbWUgZmlsZXMgb2JqZWN0IHRvIHlvdXIgVmVuc2ltIFtjb25maWd1cmF0aW9uIGZpbGVdKC4uLy4uLy4uL21vZGVsX2NvZGUvdmVuc2ltLykuKSBTZWUgdGhlIFt1bmRlcmx5aW5nIE1vZGVsIFJ1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9vdGhlcl9hcGlzL21vZGVsX2FwaXMvcnVuLyNwb3N0LWNyZWF0aW5nLWEtbmV3LXJ1bi1mb3ItdGhpcy1wcm9qZWN0KSBmb3IgYWRkaXRpb25hbCBpbmZvcm1hdGlvbi5cbipcbiogICAqIGBzdHJhdGVneWA6IChvcHRpb25hbCkgUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgZGV0YWlscy4gRGVmYXVsdHMgdG8gYG5ldy1pZi1pbml0aWFsaXplZGAuXG4qXG4qICAgKiBgc2Vzc2lvbktleWA6IChvcHRpb25hbCkgTmFtZSBvZiBicm93c2VyIGNvb2tpZSBpbiB3aGljaCB0byBzdG9yZSBydW4gaW5mb3JtYXRpb24sIGluY2x1ZGluZyBydW4gaWQuIE1hbnkgY29uZGl0aW9uYWwgc3RyYXRlZ2llcywgaW5jbHVkaW5nIHRoZSBwcm92aWRlZCBzdHJhdGVnaWVzLCByZWx5IG9uIHRoaXMgYnJvd3NlciBjb29raWUgdG8gc3RvcmUgdGhlIHJ1biBpZCBhbmQgaGVscCBtYWtlIHRoZSBkZWNpc2lvbiBvZiB3aGV0aGVyIHRvIGNyZWF0ZSBhIG5ldyBydW4gb3IgdXNlIGFuIGV4aXN0aW5nIG9uZS4gVGhlIG5hbWUgb2YgdGhpcyBjb29raWUgZGVmYXVsdHMgdG8gYGVwaWNlbnRlci1zY2VuYXJpb2AgYW5kIGNhbiBiZSBzZXQgd2l0aCB0aGUgYHNlc3Npb25LZXlgIHBhcmFtZXRlci5cbipcbipcbiogQWZ0ZXIgaW5zdGFudGlhdGluZyBhIFJ1biBNYW5hZ2VyLCBtYWtlIGEgY2FsbCB0byBgZ2V0UnVuKClgIHdoZW5ldmVyIHlvdSBuZWVkIHRvIGFjY2VzcyBhIHJ1biBmb3IgdGhpcyBlbmQgdXNlci4gVGhlIGBSdW5NYW5hZ2VyLnJ1bmAgY29udGFpbnMgdGhlIGluc3RhbnRpYXRlZCBbUnVuIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLiBUaGUgUnVuIFNlcnZpY2UgYWxsb3dzIHlvdSB0byBhY2Nlc3MgdmFyaWFibGVzLCBjYWxsIG9wZXJhdGlvbnMsIGV0Yy5cbipcbiogKipFeGFtcGxlKipcbipcbiogICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiogICAgICAgICAgIHJ1bjoge1xuKiAgICAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5LWNoYWluLW1vZGVsLmpsJyxcbiogICAgICAgICAgICAgICBzZXJ2ZXI6IHsgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH1cbiogICAgICAgICAgIH0sXG4qICAgICAgICAgICBzdHJhdGVneTogJ2Fsd2F5cy1uZXcnLFxuKiAgICAgICAgICAgc2Vzc2lvbktleTogJ2VwaWNlbnRlci1zZXNzaW9uJ1xuKiAgICAgICB9KTtcbiogICAgICAgcm0uZ2V0UnVuKClcbiogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1bikge1xuKiAgICAgICAgICAgICAgIC8vIHRoZSByZXR1cm4gdmFsdWUgb2YgZ2V0UnVuKCkgaXMgYSBydW4gb2JqZWN0XG4qICAgICAgICAgICAgICAgdmFyIHRoaXNSdW5JZCA9IHJ1bi5pZDtcbiogICAgICAgICAgICAgICAvLyB0aGUgUnVuTWFuYWdlci5ydW4gYWxzbyBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFJ1biBTZXJ2aWNlLFxuKiAgICAgICAgICAgICAgIC8vIHNvIGFueSBSdW4gU2VydmljZSBtZXRob2QgaXMgdmFsaWQgaGVyZVxuKiAgICAgICAgICAgICAgIHJtLnJ1bi5kbygncnVuTW9kZWwnKTtcbiogICAgICAgfSlcbipcbiovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBzdHJhdGVnaWVzTWFwID0gcmVxdWlyZSgnLi9ydW4tc3RyYXRlZ2llcy9zdHJhdGVnaWVzLW1hcCcpO1xudmFyIHNwZWNpYWxPcGVyYXRpb25zID0gcmVxdWlyZSgnLi9zcGVjaWFsLW9wZXJhdGlvbnMnKTtcbnZhciBSdW5TZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9ydW4tYXBpLXNlcnZpY2UnKTtcblxuXG5mdW5jdGlvbiBwYXRjaFJ1blNlcnZpY2Uoc2VydmljZSwgbWFuYWdlcikge1xuICAgIGlmIChzZXJ2aWNlLnBhdGNoZWQpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2U7XG4gICAgfVxuXG4gICAgdmFyIG9yaWcgPSBzZXJ2aWNlLmRvO1xuICAgIHNlcnZpY2UuZG8gPSBmdW5jdGlvbiAob3BlcmF0aW9uLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHJlc2VydmVkT3BzID0gT2JqZWN0LmtleXMoc3BlY2lhbE9wZXJhdGlvbnMpO1xuICAgICAgICBpZiAocmVzZXJ2ZWRPcHMuaW5kZXhPZihvcGVyYXRpb24pID09PSAtMSkge1xuICAgICAgICAgICAgcmV0dXJuIG9yaWcuYXBwbHkoc2VydmljZSwgYXJndW1lbnRzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBzcGVjaWFsT3BlcmF0aW9uc1tvcGVyYXRpb25dLmNhbGwoc2VydmljZSwgcGFyYW1zLCBvcHRpb25zLCBtYW5hZ2VyKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBzZXJ2aWNlLnBhdGNoZWQgPSB0cnVlO1xuXG4gICAgcmV0dXJuIHNlcnZpY2U7XG59XG5cblxuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgLyoqXG4gICAgICogUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgZGV0YWlscy4gRGVmYXVsdHMgdG8gYG5ldy1pZi1pbml0aWFsaXplZGAuXG4gICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgKi9cblxuICAgIHN0cmF0ZWd5OiAnbmV3LWlmLWluaXRpYWxpemVkJ1xufTtcblxuZnVuY3Rpb24gUnVuTWFuYWdlcihvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcblxuICAgIGlmICh0aGlzLm9wdGlvbnMucnVuIGluc3RhbmNlb2YgUnVuU2VydmljZSkge1xuICAgICAgICB0aGlzLnJ1biA9IHRoaXMub3B0aW9ucy5ydW47XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5ydW4gPSBuZXcgUnVuU2VydmljZSh0aGlzLm9wdGlvbnMucnVuKTtcbiAgICB9XG5cbiAgICBwYXRjaFJ1blNlcnZpY2UodGhpcy5ydW4sIHRoaXMpO1xuXG4gICAgdmFyIFN0cmF0ZWd5Q3RvciA9IHR5cGVvZiB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kgPT09ICdmdW5jdGlvbicgPyB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kgOiBzdHJhdGVnaWVzTWFwW3RoaXMub3B0aW9ucy5zdHJhdGVneV07XG5cbiAgICBpZiAoIVN0cmF0ZWd5Q3Rvcikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NwZWNpZmllZCBydW4gY3JlYXRpb24gc3RyYXRlZ3kgd2FzIGludmFsaWQ6JywgdGhpcy5vcHRpb25zLnN0cmF0ZWd5KTtcbiAgICB9XG5cbiAgICB0aGlzLnN0cmF0ZWd5ID0gbmV3IFN0cmF0ZWd5Q3Rvcih0aGlzLnJ1biwgdGhpcy5vcHRpb25zKTtcbn1cblxuUnVuTWFuYWdlci5wcm90b3R5cGUgPSB7XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSAnZ29vZCcgcnVuLlxuICAgICAqXG4gICAgICogQSBnb29kIHJ1biBpcyBkZWZpbmVkIGJ5IHRoZSBzdHJhdGVneS4gRm9yIGV4YW1wbGUsIGlmIHRoZSBzdHJhdGVneSBpcyBgYWx3YXlzLW5ld2AsIHRoZSBjYWxsXG4gICAgICogdG8gYGdldFJ1bigpYCBhbHdheXMgcmV0dXJucyBhIG5ld2x5IGNyZWF0ZWQgcnVuOyBpZiB0aGUgc3RyYXRlZ3kgaXMgYG5ldy1pZi1wZXJzaXN0ZWRgLFxuICAgICAqIGBnZXRSdW4oKWAgY3JlYXRlcyBhIG5ldyBydW4gaWYgdGhlIHByZXZpb3VzIHJ1biBpcyBpbiBhIHBlcnNpc3RlZCBzdGF0ZSwgb3RoZXJ3aXNlXG4gICAgICogaXQgcmV0dXJucyB0aGUgcHJldmlvdXMgcnVuLiBTZWUgW1J1biBNYW5hZ2VyIFN0cmF0ZWdpZXNdKC4uLy4uL3N0cmF0ZWd5LykgZm9yIG1vcmUgb24gc3RyYXRlZ2llcy5cbiAgICAgKlxuICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBybS5nZXRSdW4oKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqIEByZXR1cm4geyRwcm9taXNlfSBQcm9taXNlIHRvIGNvbXBsZXRlIHRoZSBjYWxsLlxuICAgICAqL1xuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zdHJhdGVneVxuICAgICAgICAgICAgICAgIC5nZXRSdW4oKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSBuZXcgcnVuLCByZWdhcmRsZXNzIG9mIHN0cmF0ZWd5OiBmb3JjZSBjcmVhdGlvbiBvZiBhIG5ldyBydW4uXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgcm0ucmVzZXQoKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIChuZXcpIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBydW5TZXJ2aWNlT3B0aW9uc2AgVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGUgUnVuIFNlcnZpY2UuIFNlZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSBmb3IgbW9yZS5cbiAgICAgKi9cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0cmF0ZWd5LnJlc2V0KHJ1blNlcnZpY2VPcHRpb25zKTtcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJ1bk1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIC8vIGFsd2F5cyBjcmVhdGUgYSBuZXcgcnVuIVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIG1ha2VTZXEgPSByZXF1aXJlKCcuLi8uLi91dGlsL21ha2Utc2VxdWVuY2UnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFNlc3Npb25TdG9yZSA9IHJlcXVpcmUoJy4uLy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBVcmxTZXJ2aWNlID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4uL2F1dGgtbWFuYWdlcicpO1xuXG52YXIgc2Vzc2lvblN0b3JlID0gbmV3IFNlc3Npb25TdG9yZSh7fSk7XG52YXIgdXJsU2VydmljZSA9IG5ldyBVcmxTZXJ2aWNlKCk7XG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuLi9rZXktbmFtZXMnKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHNlc3Npb25LZXk6IGtleU5hbWVzLlNUUkFURUdZX1NFU1NJT05fS0VZLFxuICAgIHBhdGg6ICcnXG59O1xuXG5mdW5jdGlvbiBzZXRSdW5JblNlc3Npb24oc2Vzc2lvbktleSwgcnVuLCBwYXRoKSB7XG4gICAgaWYgKCFwYXRoKSB7XG4gICAgICAgIGlmICghdXJsU2VydmljZS5pc0xvY2FsaG9zdCgpKSB7XG4gICAgICAgICAgICBwYXRoID0gJy8nICsgW3VybFNlcnZpY2UuYXBwUGF0aCwgdXJsU2VydmljZS5hY2NvdW50UGF0aCwgdXJsU2VydmljZS5wcm9qZWN0UGF0aF0uam9pbignLycpO1xuICAgICAgICAgICAgLy8gbWFrZSBzdXJlIHdlIGRvbid0IGdldCBjb25zZWN1dGVpdmUgJy8nIHNvIHdlIGhhdmUgYSB2YWxpZCBwYXRoIGZvciB0aGUgc2Vzc2lvblxuICAgICAgICAgICAgcGF0aCA9IHBhdGgucmVwbGFjZSgvXFwvezIsfS9nLCcvJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwYXRoID0gJyc7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gc2V0IHRoZSBzZWVzaW9uS2V5IGZvciB0aGUgcnVuXG4gICAgc2Vzc2lvblN0b3JlLnNldChzZXNzaW9uS2V5LCBKU09OLnN0cmluZ2lmeSh7IHJ1bklkOiBydW4uaWQgfSksIHsgcm9vdDogcGF0aCB9KTtcbn1cblxuLyoqXG4qIENvbmRpdGlvbmFsIENyZWF0aW9uIFN0cmF0ZWd5XG4qIFRoaXMgc3RyYXRlZ3kgd2lsbCB0cnkgdG8gZ2V0IHRoZSBydW4gc3RvcmVkIGluIHRoZSBjb29raWUgYW5kXG4qIGV2YWx1YXRlIGlmIG5lZWRzIHRvIGNyZWF0ZSBhIG5ldyBydW4gYnkgY2FsbGluZyB0aGUgJ2NvbmRpdGlvbicgZnVuY3Rpb25cbiovXG5cbi8qIGpzaGludCBlcW51bGw6IHRydWUgKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIFN0cmF0ZWd5KHJ1blNlcnZpY2UsIGNvbmRpdGlvbiwgb3B0aW9ucykge1xuXG4gICAgICAgIGlmIChjb25kaXRpb24gPT0gbnVsbCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb25kaXRpb25hbCBzdHJhdGVneSBuZWVkcyBhIGNvbmRpdGlvbiB0byBjcmVhdGV0ZSBhIHJ1bicpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fYXV0aCA9IG5ldyBBdXRoTWFuYWdlcigpO1xuICAgICAgICB0aGlzLnJ1biA9IG1ha2VTZXEocnVuU2VydmljZSk7XG4gICAgICAgIHRoaXMuY29uZGl0aW9uID0gdHlwZW9mIGNvbmRpdGlvbiAhPT0gJ2Z1bmN0aW9uJyA/IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGNvbmRpdGlvbjsgfSA6IGNvbmRpdGlvbjtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICB9LFxuXG4gICAgcnVuT3B0aW9uc1dpdGhTY29wZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgdXNlclNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiB1c2VyU2Vzc2lvbi5ncm91cE5hbWUgfVxuICAgICAgICB9LCB0aGlzLnJ1bk9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBvcHQgPSB0aGlzLnJ1bk9wdGlvbnNXaXRoU2NvcGUoKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5ydW5cbiAgICAgICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgc2V0UnVuSW5TZXNzaW9uKF90aGlzLm9wdGlvbnMuc2Vzc2lvbktleSwgcnVuLCBfdGhpcy5vcHRpb25zLnBhdGgpO1xuICAgICAgICAgICAgICAgIHJ1bi5mcmVzaGx5Q3JlYXRlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuc3RhcnQoKTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBydW5TZXNzaW9uID0gSlNPTi5wYXJzZShzZXNzaW9uU3RvcmUuZ2V0KHRoaXMub3B0aW9ucy5zZXNzaW9uS2V5KSk7XG5cbiAgICAgICAgaWYgKHJ1blNlc3Npb24gJiYgcnVuU2Vzc2lvbi5ydW5JZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2xvYWRBbmRDaGVjayhydW5TZXNzaW9uKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJlc2V0KCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgX2xvYWRBbmRDaGVjazogZnVuY3Rpb24gKHJ1blNlc3Npb24pIHtcbiAgICAgICAgdmFyIHNob3VsZENyZWF0ZSA9IGZhbHNlO1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1blxuICAgICAgICAgICAgLmxvYWQocnVuU2Vzc2lvbi5ydW5JZCwgbnVsbCwge1xuICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZ1bmN0aW9uIChydW4sIG1zZywgaGVhZGVycykge1xuICAgICAgICAgICAgICAgICAgICBzaG91bGRDcmVhdGUgPSBfdGhpcy5jb25kaXRpb24uY2FsbChfdGhpcywgcnVuLCBoZWFkZXJzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIGlmIChzaG91bGRDcmVhdGUpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9wdCA9IF90aGlzLnJ1bk9wdGlvbnNXaXRoU2NvcGUoKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gd2UgbmVlZCB0byBkbyB0aGlzLCBvbiB0aGUgb3JpZ2luYWwgcnVuU2VydmljZSAoaWUgbm90IHNlcXVlbmNpYWxpemVkKVxuICAgICAgICAgICAgICAgICAgICAvLyBzbyB3ZSBkb24ndCBnZXQgaW4gdGhlIG1pZGRsZSBvZiB0aGUgcXVldWVcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1bi5vcmlnaW5hbC5jcmVhdGUob3B0KVxuICAgICAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRSdW5JblNlc3Npb24oX3RoaXMub3B0aW9ucy5zZXNzaW9uS2V5LCBydW4pO1xuICAgICAgICAgICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnN0YXJ0KCk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0ge307XG5cbi8vIEludGVyZmFjZSB0aGF0IGFsbCBzdHJhdGVnaWVzIG5lZWQgdG8gaW1wbGVtZW50XG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuU2VydmljZSAgPSBydW5TZXJ2aWNlO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSBuZXdseSBjcmVhdGVkIHJ1blxuICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlc29sdmUoKS5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSB1c2FibGUgcnVuXG4gICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVzb2x2ZSh0aGlzLnJ1blNlcnZpY2UpLnByb21pc2UoKTtcbiAgICB9XG59KTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xuXG52YXIgSWRlbnRpdHlTdHJhdGVneSA9IHJlcXVpcmUoJy4vaWRlbnRpdHktc3RyYXRlZ3knKTtcbnZhciBXb3JsZEFwaUFkYXB0ZXIgPSByZXF1aXJlKCcuLi8uLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuLi9hdXRoLW1hbmFnZXInKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHN0b3JlOiB7XG4gICAgICAgIHN5bmNocm9ub3VzOiB0cnVlXG4gICAgfVxufTtcblxudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKElkZW50aXR5U3RyYXRlZ3ksIHtcblxuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICB0aGlzLnJ1blNlcnZpY2UgPSBydW5TZXJ2aWNlO1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMud29ybGRBcGkgPSBuZXcgV29ybGRBcGlBZGFwdGVyKHRoaXMub3B0aW9ucy5ydW4pO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICB2YXIgY3VyVXNlcklkID0gc2Vzc2lvbi51c2VySWQ7XG4gICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaVxuICAgICAgICAgICAgLmdldEN1cnJlbnRXb3JsZEZvclVzZXIoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaS5uZXdSdW5Gb3JXb3JsZCh3b3JsZC5pZCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIGN1clVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICB2YXIgY3VyR3JvdXBOYW1lID0gc2Vzc2lvbi5ncm91cE5hbWU7XG4gICAgICAgIHZhciB3b3JsZEFwaSA9IHRoaXMud29ybGRBcGk7XG4gICAgICAgIHZhciBtb2RlbCA9IHRoaXMub3B0aW9ucy5tb2RlbDtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcblxuICAgICAgICBpZiAoIWN1clVzZXJJZCkge1xuICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDAsIGVycm9yOiAnV2UgbmVlZCBhbiBhdXRoZW50aWNhdGVkIHVzZXIgdG8gam9pbiBhIG11bHRpcGxheWVyIHdvcmxkLiAoRVJSOiBubyB1c2VySWQgaW4gc2Vzc2lvbiknIH0sIHNlc3Npb24pLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBsb2FkUnVuRnJvbVdvcmxkID0gZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICBpZiAoIXdvcmxkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDQsIGVycm9yOiAnVGhlIHVzZXIgaXMgbm90IGluIGFueSB3b3JsZC4nIH0sIHsgb3B0aW9uczogdGhpcy5vcHRpb25zLCBzZXNzaW9uOiBzZXNzaW9uIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gd29ybGRBcGkuZ2V0Q3VycmVudFJ1bklkKHsgbW9kZWw6IG1vZGVsLCBmaWx0ZXI6IHdvcmxkLmlkIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oX3RoaXMuX2xvYWRSdW4pXG4gICAgICAgICAgICAgICAgLnRoZW4oZHRkLnJlc29sdmUpXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHNlcnZlckVycm9yID0gZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAvLyBpcyB0aGlzIHBvc3NpYmxlP1xuICAgICAgICAgICAgZHRkLnJlamVjdChlcnJvciwgc2Vzc2lvbiwgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLndvcmxkQXBpXG4gICAgICAgICAgICAuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcihjdXJVc2VySWQsIGN1ckdyb3VwTmFtZSlcbiAgICAgICAgICAgIC50aGVuKGxvYWRSdW5Gcm9tV29ybGQpXG4gICAgICAgICAgICAuZmFpbChzZXJ2ZXJFcnJvcik7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIF9sb2FkUnVuOiBmdW5jdGlvbiAoaWQsIG9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5sb2FkKGlkLCBudWxsLCBvcHRpb25zKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIHJldHVybiBoZWFkZXJzLmdldFJlc3BvbnNlSGVhZGVyKCdwcmFnbWEnKSA9PT0gJ3BlcnNpc3RlbnQnIHx8IHJ1bi5pbml0aWFsaXplZDtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbi8qXG4qICBjcmVhdGUgYSBuZXcgcnVuIG9ubHkgaWYgbm90aGluZyBpcyBzdG9yZWQgaW4gdGhlIGNvb2tpZVxuKiAgdGhpcyBpcyB1c2VmdWwgZm9yIGJhc2VSdW5zLlxuKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgLy8gaWYgd2UgYXJlIGhlcmUsIGl0IG1lYW5zIHRoYXQgdGhlIHJ1biBleGlzdHMuLi4gc28gd2UgZG9uJ3QgbmVlZCBhIG5ldyBvbmVcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgcmV0dXJuIGhlYWRlcnMuZ2V0UmVzcG9uc2VIZWFkZXIoJ3ByYWdtYScpID09PSAncGVyc2lzdGVudCc7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBJZGVudGl0eVN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIFN0YXRlQXBpID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xudmFyIEF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4uL2tleS1uYW1lcycpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgc3RvcmU6IHtcbiAgICAgICAgc3luY2hyb25vdXM6IHRydWVcbiAgICB9XG59O1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oSWRlbnRpdHlTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiBTdHJhdGVneShydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICAgICAgdGhpcy5fc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkodGhpcy5vcHRpb25zLnN0b3JlKTtcbiAgICAgICAgdGhpcy5zdGF0ZUFwaSA9IG5ldyBTdGF0ZUFwaSgpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG5cbiAgICAgICAgdGhpcy5fbG9hZEFuZENoZWNrID0gdGhpcy5fbG9hZEFuZENoZWNrLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX3Jlc3RvcmVSdW4gPSB0aGlzLl9yZXN0b3JlUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2dldEFsbFJ1bnMgPSB0aGlzLl9nZXRBbGxSdW5zLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAocnVuU2VydmljZU9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiBzZXNzaW9uLmdyb3VwTmFtZSB9XG4gICAgICAgIH0sIHRoaXMucnVuT3B0aW9ucyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuXG4gICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0QWxsUnVucygpXG4gICAgICAgICAgICAudGhlbih0aGlzLl9sb2FkQW5kQ2hlY2spO1xuICAgIH0sXG5cbiAgICBfZ2V0QWxsUnVuczogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IEpTT04ucGFyc2UodGhpcy5fc3RvcmUuZ2V0KGtleU5hbWVzLkVQSV9TRVNTSU9OX0tFWSkgfHwgJ3t9Jyk7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5xdWVyeSh7XG4gICAgICAgICAgICAndXNlci5pZCc6IHNlc3Npb24udXNlcklkIHx8ICcwMDAwJyxcbiAgICAgICAgICAgICdzY29wZS5ncm91cCc6IHNlc3Npb24uZ3JvdXBOYW1lXG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICBfbG9hZEFuZENoZWNrOiBmdW5jdGlvbiAocnVucykge1xuICAgICAgICBpZiAoIXJ1bnMgfHwgIXJ1bnMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yZXNldCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGRhdGVDb21wID0gZnVuY3Rpb24gKGEsIGIpIHsgcmV0dXJuIG5ldyBEYXRlKGIuZGF0ZSkgLSBuZXcgRGF0ZShhLmRhdGUpOyB9O1xuICAgICAgICB2YXIgbGF0ZXN0UnVuID0gcnVucy5zb3J0KGRhdGVDb21wKVswXTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIHNob3VsZFJlcGxheSA9IGZhbHNlO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5sb2FkKGxhdGVzdFJ1bi5pZCwgbnVsbCwge1xuICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKHJ1biwgbXNnLCBoZWFkZXJzKSB7XG4gICAgICAgICAgICAgICAgc2hvdWxkUmVwbGF5ID0gaGVhZGVycy5nZXRSZXNwb25zZUhlYWRlcigncHJhZ21hJykgPT09ICdwZXJzaXN0ZW50JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSkudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICByZXR1cm4gc2hvdWxkUmVwbGF5ID8gX3RoaXMuX3Jlc3RvcmVSdW4ocnVuLmlkKSA6IHJ1bjtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIF9yZXN0b3JlUnVuOiBmdW5jdGlvbiAocnVuSWQpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGVBcGkucmVwbGF5KHsgcnVuSWQ6IHJ1bklkIH0pXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzcCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5fbG9hZFJ1bihyZXNwLnJ1bik7XG4gICAgICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgX2xvYWRSdW46IGZ1bmN0aW9uIChpZCwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5ydW4ubG9hZChpZCwgbnVsbCwgb3B0aW9ucyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIm1vZHVsZS5leHBvcnRzID0ge1xuICAgICduZXctaWYtaW5pdGlhbGl6ZWQnOiByZXF1aXJlKCcuL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpLFxuICAgICduZXctaWYtcGVyc2lzdGVkJzogcmVxdWlyZSgnLi9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5JyksXG4gICAgJ25ldy1pZi1taXNzaW5nJzogcmVxdWlyZSgnLi9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpLFxuICAgICdhbHdheXMtbmV3JzogcmVxdWlyZSgnLi9hbHdheXMtbmV3LXN0cmF0ZWd5JyksXG4gICAgJ211bHRpcGxheWVyJzogcmVxdWlyZSgnLi9tdWx0aXBsYXllci1zdHJhdGVneScpLFxuICAgICdwZXJzaXN0ZW50LXNpbmdsZS1wbGF5ZXInOiByZXF1aXJlKCcuL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneScpLFxuICAgICdub25lJzogcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpXG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIFJ1blNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgdmFsaWRGaWx0ZXI6IHsgc2F2ZWQ6IHRydWUgfVxufTtcblxuZnVuY3Rpb24gU2NlbmFyaW9NYW5hZ2VyKG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMucnVuU2VydmljZSA9IHRoaXMub3B0aW9ucy5ydW4gfHwgbmV3IFJ1blNlcnZpY2UodGhpcy5vcHRpb25zKTtcbn1cblxuU2NlbmFyaW9NYW5hZ2VyLnByb3RvdHlwZSA9IHtcbiAgICBnZXRSdW5zOiBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgIHRoaXMuZmlsdGVyID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMub3B0aW9ucy52YWxpZEZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5xdWVyeSh0aGlzLmZpbHRlcik7XG4gICAgfSxcblxuICAgIGxvYWRWYXJpYWJsZXM6IGZ1bmN0aW9uICh2YXJzKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1blNlcnZpY2UucXVlcnkodGhpcy5maWx0ZXIsIHsgaW5jbHVkZTogdmFycyB9KTtcbiAgICB9LFxuXG4gICAgc2F2ZTogZnVuY3Rpb24gKHJ1biwgbWV0YSkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0U2VydmljZShydW4pLnNhdmUoJC5leHRlbmQodHJ1ZSwge30sIHsgc2F2ZWQ6IHRydWUgfSwgbWV0YSkpO1xuICAgIH0sXG5cbiAgICBhcmNoaXZlOiBmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9nZXRTZXJ2aWNlKHJ1bikuc2F2ZSh7IHNhdmVkOiBmYWxzZSB9KTtcbiAgICB9LFxuXG4gICAgX2dldFNlcnZpY2U6IGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW4gfSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdvYmplY3QnICYmIHJ1biBpbnN0YW5jZW9mIFJ1blNlcnZpY2UpIHtcbiAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgIH1cblxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NhdmUgbWV0aG9kIHJlcXVpcmVzIGEgcnVuIHNlcnZpY2Ugb3IgYSBydW5JZCcpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW5JZCB9KSk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTY2VuYXJpb01hbmFnZXI7XG5cbiIsIid1c2Ugc3RyaWN0JztcblxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICByZXNldDogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucywgbWFuYWdlcikge1xuICAgICAgICByZXR1cm4gbWFuYWdlci5yZXNldChvcHRpb25zKTtcbiAgICB9XG59O1xuIiwiLyoqXG4qICMjIFdvcmxkIE1hbmFnZXJcbipcbiogQXMgZGlzY3Vzc2VkIHVuZGVyIHRoZSBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLyksIGEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsLiBGb3IgYnVpbGRpbmcgbXVsdGlwbGF5ZXIgc2ltdWxhdGlvbnMgeW91IHR5cGljYWxseSB3YW50IG11bHRpcGxlIGVuZCB1c2VycyB0byBzaGFyZSB0aGUgc2FtZSBzZXQgb2YgaW50ZXJhY3Rpb25zLCBhbmQgd29yayB3aXRoaW4gYSBjb21tb24gc3RhdGUuIEVwaWNlbnRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSBcIndvcmxkc1wiIHRvIGhhbmRsZSBzdWNoIGNhc2VzLlxuKlxuKiBUaGUgV29ybGQgTWFuYWdlciBwcm92aWRlcyBhbiBlYXN5IHdheSB0byB0cmFjayBhbmQgYWNjZXNzIHRoZSBjdXJyZW50IHdvcmxkIGFuZCBydW4gZm9yIHBhcnRpY3VsYXIgZW5kIHVzZXJzLiBJdCBpcyB0eXBpY2FsbHkgdXNlZCBpbiBwYWdlcyB0aGF0IGVuZCB1c2VycyB3aWxsIGludGVyYWN0IHdpdGguIChUaGUgcmVsYXRlZCBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLykgaGFuZGxlcyBjcmVhdGluZyBtdWx0aXBsYXllciB3b3JsZHMsIGFuZCBhZGRpbmcgYW5kIHJlbW92aW5nIGVuZCB1c2VycyBhbmQgcnVucyBmcm9tIGEgd29ybGQuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4pXG4qXG4qICMjIyBVc2luZyB0aGUgV29ybGQgTWFuYWdlclxuKlxuKiBUbyB1c2UgdGhlIFdvcmxkIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LiBUaGVuLCBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbipcbiogV2hlbiB5b3UgaW5zdGFudGlhdGUgYSBXb3JsZCBNYW5hZ2VyLCB0aGUgd29ybGQncyBhY2NvdW50IGlkLCBwcm9qZWN0IGlkLCBhbmQgZ3JvdXAgYXJlIGF1dG9tYXRpY2FsbHkgdGFrZW4gZnJvbSB0aGUgc2Vzc2lvbiAodGhhbmtzIHRvIHRoZSBbQXV0aGVudGljYXRpb24gU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZSkpLlxuKlxuKiBOb3RlIHRoYXQgdGhlIFdvcmxkIE1hbmFnZXIgZG9lcyAqbm90KiBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkuIChUaGlzIGlzIGRpZmZlcmVudCB0aGFuIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyKS4pIEhvd2V2ZXIsIHlvdSBjYW4gcGFzcyBpbiBzcGVjaWZpYyBvcHRpb25zIHRvIGFueSBydW5zIGNyZWF0ZWQgYnkgdGhlIG1hbmFnZXIsIHVzaW5nIGEgYHJ1bmAgb2JqZWN0LlxuKlxuKiBUaGUgcGFyYW1ldGVycyBmb3IgY3JlYXRpbmcgYSBXb3JsZCBNYW5hZ2VyIGFyZTpcbipcbiogICAqIGBhY2NvdW50YDogVGhlICoqVGVhbSBJRCoqIGluIHRoZSBFcGljZW50ZXIgdXNlciBpbnRlcmZhY2UgZm9yIHRoaXMgcHJvamVjdC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGlzIHByb2plY3QuXG4qICAgKiBgZ3JvdXBgOiBUaGUgKipHcm91cCBOYW1lKiogZm9yIHRoaXMgd29ybGQuXG4qICAgKiBgcnVuYDogT3B0aW9ucyB0byB1c2Ugd2hlbiBjcmVhdGluZyBuZXcgcnVucyB3aXRoIHRoZSBtYW5hZ2VyLCBlLmcuIGBydW46IHsgZmlsZXM6IFsnZGF0YS54bHMnXSB9YC5cbiogICAqIGBydW4ubW9kZWxgOiBUaGUgbmFtZSBvZiB0aGUgcHJpbWFyeSBtb2RlbCBmaWxlIGZvciB0aGlzIHByb2plY3QuIFJlcXVpcmVkIGlmIHlvdSBoYXZlIG5vdCBhbHJlYWR5IHBhc3NlZCBpdCBpbiBhcyBwYXJ0IG9mIHRoZSBgb3B0aW9uc2AgcGFyYW1ldGVyIGZvciBhbiBlbmNsb3NpbmcgY2FsbC5cbipcbiogRm9yIGV4YW1wbGU6XG4qXG4qICAgICAgIHZhciB3TWdyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4qICAgICAgICAgIHJ1bjogeyBtb2RlbDogJ3N1cHBseS1jaGFpbi5weScgfSxcbiogICAgICAgICAgZ3JvdXA6ICd0ZWFtMSdcbiogICAgICAgfSk7XG4qXG4qICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bigpO1xuKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgV29ybGRBcGkgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgUnVuTWFuYWdlciA9ICByZXF1aXJlKCcuL3J1bi1tYW5hZ2VyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL2F1dGgtbWFuYWdlcicpO1xudmFyIHdvcmxkQXBpO1xuXG4vLyB2YXIgZGVmYXVsdHMgPSB7XG4vLyAgYWNjb3VudDogJycsXG4vLyAgcHJvamVjdDogJycsXG4vLyAgZ3JvdXA6ICcnLFxuLy8gIHRyYW5zcG9ydDoge1xuLy8gIH1cbi8vIH07XG5cblxuZnVuY3Rpb24gYnVpbGRTdHJhdGVneSh3b3JsZElkLCBkdGQpIHtcblxuICAgIHJldHVybiBmdW5jdGlvbiBDdG9yKHJ1blNlcnZpY2UsIG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5ydW5TZXJ2aWNlID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcblxuICAgICAgICAkLmV4dGVuZCh0aGlzLCB7XG4gICAgICAgICAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbm90IGltcGxlbWVudGQuIE5lZWQgYXBpIGNoYW5nZXMnKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgICAgICAgICAgLy9nZXQgb3IgY3JlYXRlIVxuICAgICAgICAgICAgICAgIC8vIE1vZGVsIGlzIHJlcXVpcmVkIGluIHRoZSBvcHRpb25zXG4gICAgICAgICAgICAgICAgdmFyIG1vZGVsID0gdGhpcy5vcHRpb25zLnJ1bi5tb2RlbCB8fCB0aGlzLm9wdGlvbnMubW9kZWw7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHdvcmxkQXBpLmdldEN1cnJlbnRSdW5JZCh7IG1vZGVsOiBtb2RlbCwgZmlsdGVyOiB3b3JsZElkIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1blNlcnZpY2UubG9hZChydW5JZCk7XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlLmNhbGwodGhpcywgcnVuLCBfdGhpcy5ydW5TZXJ2aWNlKTtcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH07XG59XG5cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnMgfHwgeyBydW46IHt9LCB3b3JsZDoge30gfTtcblxuICAgICQuZXh0ZW5kKHRydWUsIHRoaXMub3B0aW9ucywgdGhpcy5vcHRpb25zLnJ1bik7XG4gICAgJC5leHRlbmQodHJ1ZSwgdGhpcy5vcHRpb25zLCB0aGlzLm9wdGlvbnMud29ybGQpO1xuXG4gICAgd29ybGRBcGkgPSBuZXcgV29ybGRBcGkodGhpcy5vcHRpb25zKTtcbiAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgIHZhciBhcGkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0dXJucyB0aGUgY3VycmVudCB3b3JsZCAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtXb3JsZCBBUEkgQWRhcHRlcl0oLi4vd29ybGQtYXBpLWFkYXB0ZXIvKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB3TWdyLmdldEN1cnJlbnRXb3JsZCgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkLCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdvcmxkQWRhcHRlci5nZXRDdXJyZW50UnVuSWQoKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgdXNlcklkYCAoT3B0aW9uYWwpIFRoZSBpZCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZCBpcyBiZWluZyBhY2Nlc3NlZC4gRGVmYXVsdHMgdG8gdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgZ3JvdXAgd2hvc2Ugd29ybGQgaXMgYmVpbmcgYWNjZXNzZWQuIERlZmF1bHRzIHRvIHRoZSBncm91cCBmb3IgdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFdvcmxkOiBmdW5jdGlvbiAodXNlcklkLCBncm91cE5hbWUpIHtcbiAgICAgICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5fYXV0aC5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgICAgICBpZiAoIXVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFncm91cE5hbWUpIHtcbiAgICAgICAgICAgICAgICBncm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB3b3JsZEFwaS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKHVzZXJJZCwgZ3JvdXBOYW1lKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHJ1biAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bih7bW9kZWw6ICdteU1vZGVsLnB5J30pXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1biwgcnVuU2VydmljZSkge1xuICAgICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2cocnVuLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHJ1blNlcnZpY2UuZG8oJ3N0YXJ0R2FtZScpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBtb2RlbGAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgbW9kZWwgZmlsZS4gUmVxdWlyZWQgaWYgbm90IGFscmVhZHkgcGFzc2VkIGluIGFzIGBydW4ubW9kZWxgIHdoZW4gdGhlIFdvcmxkIE1hbmFnZXIgaXMgY3JlYXRlZC5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFJ1bjogZnVuY3Rpb24gKG1vZGVsKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgICAgIHZhciBjdXJVc2VySWQgPSBzZXNzaW9uLnVzZXJJZDtcbiAgICAgICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICAgICAgZnVuY3Rpb24gZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bih3b3JsZCkge1xuICAgICAgICAgICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBlcnJvcjogJ1RoZSB1c2VyIGlzIG5vdCBwYXJ0IG9mIGFueSB3b3JsZCEnIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBjdXJyZW50V29ybGRJZCA9IHdvcmxkLmlkO1xuICAgICAgICAgICAgICAgIHZhciBydW5PcHRzID0gJC5leHRlbmQodHJ1ZSwgX3RoaXMub3B0aW9ucywgeyBtb2RlbDogbW9kZWwgfSk7XG4gICAgICAgICAgICAgICAgdmFyIHN0cmF0ZWd5ID0gYnVpbGRTdHJhdGVneShjdXJyZW50V29ybGRJZCwgZHRkKTtcbiAgICAgICAgICAgICAgICB2YXIgb3B0ID0gJC5leHRlbmQodHJ1ZSwge30sIHtcbiAgICAgICAgICAgICAgICAgICAgc3RyYXRlZ3k6IHN0cmF0ZWd5LFxuICAgICAgICAgICAgICAgICAgICBydW46IHJ1bk9wdHNcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB2YXIgcm0gPSBuZXcgUnVuTWFuYWdlcihvcHQpO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJtLmdldFJ1bigpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHJ1biwgcm0ucnVuU2VydmljZSwgcm0pO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5nZXRDdXJyZW50V29ybGQoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAgICAgLnRoZW4oZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bik7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIGFwaSk7XG59O1xuIiwiLyoqXG4gKiAjI0ZpbGUgQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGlzIGlzIHVzZWQgdG8gdXBsb2FkL2Rvd25sb2FkIGZpbGVzIGRpcmVjdGx5IG9udG8gRXBpY2VudGVyLCBhbmFsb2dvdXMgdG8gdXNpbmcgdGhlIEZpbGUgTWFuYWdlciBVSSBpbiBFcGljZW50ZXIgZGlyZWN0bHkgb3IgU0ZUUGluZyBmaWxlcyBpbi4gVGhlIEFzc2V0IEFQSSBpcyB0eXBpY2FsbHkgdXNlZCBmb3IgYWxsIHByb2plY3QgdXNlLWNhc2VzLCBhbmQgaXQncyB1bmxpa2VseSB0aGlzIEZpbGUgU2VydmljZSB3aWxsIGJlIHVzZWQgZGlyZWN0bHkgZXhjZXB0IGJ5IEFkbWluIHRvb2xzIChlLmcuIEZsb3cgSW5zcGVjdG9yKS5cbiAqXG4gKiBQYXJ0aWFsbHkgaW1wbGVtZW50ZWQuXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIC8vIGNvbmZpZyB8fCAoY29uZmlnID0gY29uZmlnU2VydmljZS5nZXQoKSk7XG4gICAgdmFyIHN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHsgc3luY2hyb25vdXM6IHRydWUgfSk7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICAgdG9rZW46IHN0b3JlLmdldCgnZXBpY2VudGVyLnByb2plY3QudG9rZW4nKSB8fCBzdG9yZS5nZXQoJ2VwaWNlbnRlci50b2tlbicpIHx8ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiAnJyxcblxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgnZmlsZScpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQXN5bmNBUEkgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgYSBkaXJlY3RvcnkgbGlzdGluZywgb3IgY29udGVudHMgb2YgYSBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGZpbGVQYXRoYCAgIFBhdGggdG8gdGhlIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBgZm9sZGVyVHlwZWAgT25lIG9mIE1vZGVsfFN0YXRpY3xOb2RlXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBnZXRDb250ZW50czogZnVuY3Rpb24gKGZpbGVQYXRoLCBmb2xkZXJUeXBlLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IGZvbGRlclR5cGUgKyAnLycgKyBmaWxlUGF0aDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2ZpbGUnKSArIHBhdGhcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQXN5bmNBUEkpO1xufTtcbiIsIi8qKlxuICogIyNBc3NldCBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBBc3NldCBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHN0b3JlIGFzc2V0cyAtLSByZXNvdXJjZXMgb3IgZmlsZXMgb2YgYW55IGtpbmQgLS0gdXNlZCBieSBhIHByb2plY3Qgd2l0aCBhIHNjb3BlIHRoYXQgaXMgc3BlY2lmaWMgdG8gcHJvamVjdCwgZ3JvdXAsIG9yIGVuZCB1c2VyLlxuICpcbiAqIEFzc2V0cyBhcmUgdXNlZCB3aXRoIFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9wcm9qZWN0X2FkbWluLyN0ZWFtKS4gT25lIGNvbW1vbiB1c2UgY2FzZSBpcyBoYXZpbmcgZW5kIHVzZXJzIGluIGEgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSBvciBpbiBhIFttdWx0aXBsYXllciB3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKSB1cGxvYWQgZGF0YSAtLSB2aWRlb3MgY3JlYXRlZCBkdXJpbmcgZ2FtZSBwbGF5LCBwcm9maWxlIHBpY3R1cmVzIGZvciBjdXN0b21pemluZyB0aGVpciBleHBlcmllbmNlLCBldGMuIC0tIGFzIHBhcnQgb2YgcGxheWluZyB0aHJvdWdoIHRoZSBwcm9qZWN0LlxuICpcbiAqIFJlc291cmNlcyBjcmVhdGVkIHVzaW5nIHRoZSBBc3NldCBBZGFwdGVyIGFyZSBzY29wZWQ6XG4gKlxuICogICogUHJvamVjdCBhc3NldHMgYXJlIHdyaXRhYmxlIG9ubHkgYnkgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pLCB0aGF0IGlzLCBFcGljZW50ZXIgYXV0aG9ycy5cbiAqICAqIEdyb3VwIGFzc2V0cyBhcmUgd3JpdGFibGUgYnkgYW55b25lIHdpdGggYWNjZXNzIHRvIHRoZSBwcm9qZWN0IHRoYXQgaXMgcGFydCBvZiB0aGF0IHBhcnRpY3VsYXIgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS4gVGhpcyBpbmNsdWRlcyBhbGwgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIChFcGljZW50ZXIgYXV0aG9ycykgYW5kIGFueSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiB0aGUgZ3JvdXAgLS0gYm90aCBmYWNpbGl0YXRvcnMgYW5kIHN0YW5kYXJkIGVuZCB1c2Vycy5cbiAqICAqIFVzZXIgYXNzZXRzIGFyZSB3cml0YWJsZSBieSB0aGUgc3BlY2lmaWMgZW5kIHVzZXIsIGFuZCBieSB0aGUgZmFjaWxpdGF0b3Igb2YgdGhlIGdyb3VwLlxuICogICogQWxsIGFzc2V0cyBhcmUgcmVhZGFibGUgYnkgYW55b25lIHdpdGggdGhlIGV4YWN0IFVSSS5cbiAqXG4gKiBUbyB1c2UgdGhlIEFzc2V0IEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSkgYW5kIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKS4gVGhlIGdyb3VwIG5hbWUgaXMgcmVxdWlyZWQgZm9yIGFzc2V0cyB3aXRoIGEgZ3JvdXAgc2NvcGUsIGFuZCB0aGUgZ3JvdXAgbmFtZSBhbmQgdXNlcklkIGFyZSByZXF1aXJlZCBmb3IgYXNzZXRzIHdpdGggYSB1c2VyIHNjb3BlLiBJZiBub3QgaW5jbHVkZWQsIHRoZXkgYXJlIHRha2VuIGZyb20gdGhlIGxvZ2dlZCBpbiB1c2VyJ3Mgc2Vzc2lvbiBpbmZvcm1hdGlvbiBpZiBuZWVkZWQuXG4gKlxuICogV2hlbiBjcmVhdGluZyBhbiBhc3NldCwgeW91IGNhbiBwYXNzIGluIHRleHQgKGVuY29kZWQgZGF0YSkgdG8gdGhlIGBjcmVhdGUoKWAgY2FsbC4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBtYWtlIHRoZSBgY3JlYXRlKClgIGNhbGwgYXMgcGFydCBvZiBhbiBIVE1MIGZvcm0gYW5kIHBhc3MgaW4gYSBmaWxlIHVwbG9hZGVkIHZpYSB0aGUgZm9ybS5cbiAqXG4gKiAgICAgICAvLyBpbnN0YW50aWF0ZSB0aGUgQXNzZXQgQWRhcHRlclxuICogICAgICAgdmFyIGFhID0gbmV3IEYuc2VydmljZS5Bc3NldCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gKiAgICAgICAgICB1c2VySWQ6ICcxMjM0NSdcbiAqICAgICAgIH0pO1xuICpcbiAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAqICAgICAgIGFhLmNyZWF0ZSgndGVzdC50eHQnLCB7XG4gKiAgICAgICAgICAgZW5jb2Rpbmc6ICdCQVNFXzY0JyxcbiAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICogICAgICAgfSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICpcbiAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAqICAgICAgIC8vIHRoaXMgc2FtcGxlIGNvZGUgZ29lcyB3aXRoIGFuIGh0bWwgZm9ybSB0aGF0IGxvb2tzIGxpa2UgdGhpczpcbiAqICAgICAgIC8vXG4gKiAgICAgICAvLyA8Zm9ybSBpZD1cInVwbG9hZC1maWxlXCI+XG4gKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlVwbG9hZCBteUZpbGU8L2J1dHRvbj5cbiAqICAgICAgIC8vIDwvZm9ybT5cbiAqICAgICAgIC8vXG4gKiAgICAgICAkKCcjdXBsb2FkLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAqICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAqXG4gKiAgICAgICAgICBhYS5jcmVhdGUoZmlsZW5hbWUsIGRhdGEsIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAqICAgICAgIH0pO1xuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBTdG9yYWdlRmFjdG9yeSA9IHJlcXVpcmUoJy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbi8vIHZhciBxdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIGtleU5hbWVzID0gcmVxdWlyZSgnLi4vbWFuYWdlcnMva2V5LW5hbWVzJyk7XG5cbnZhciBhcGlFbmRwb2ludCA9ICdhc3NldCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBzdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh7IHN5bmNocm9ub3VzOiB0cnVlIH0pO1xuICAgIHZhciBzZXNzaW9uID0gSlNPTi5wYXJzZShzdG9yZS5nZXQoa2V5TmFtZXMuRVBJX1NFU1NJT05fS0VZKSB8fCAne30nKTtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KGtleU5hbWVzLkVQSV9DT09LSUVfS0VZKSB8fCAnJyxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgZ3JvdXAgbmFtZS4gRGVmYXVsdHMgdG8gc2Vzc2lvbidzIGBncm91cE5hbWVgLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZ3JvdXA6IHNlc3Npb24uZ3JvdXBOYW1lLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHVzZXIgaWQuIERlZmF1bHRzIHRvIHNlc3Npb24ncyBgdXNlcklkYC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogc2Vzc2lvbi51c2VySWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgc2NvcGUgZm9yIHRoZSBhc3NldC4gVmFsaWQgdmFsdWVzIGFyZTogYHVzZXJgLCBgZ3JvdXBgLCBhbmQgYHByb2plY3RgLiBTZWUgYWJvdmUgZm9yIHRoZSByZXF1aXJlZCBwZXJtaXNzaW9ucyB0byB3cml0ZSB0byBlYWNoIHNjb3BlLiBEZWZhdWx0cyB0byBgdXNlcmAsIG1lYW5pbmcgdGhlIGN1cnJlbnQgZW5kIHVzZXIgb3IgYSBmYWNpbGl0YXRvciBpbiB0aGUgZW5kIHVzZXIncyBncm91cCBjYW4gZWRpdCB0aGUgYXNzZXQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBzY29wZTogJ3VzZXInLFxuICAgICAgICAvKipcbiAgICAgICAgICogRGV0ZXJtaW5lcyBpZiBhIHJlcXVlc3QgdG8gbGlzdCB0aGUgYXNzZXRzIGluIGEgc2NvcGUgaW5jbHVkZXMgdGhlIGNvbXBsZXRlIFVSTCBmb3IgZWFjaCBhc3NldCAoYHRydWVgKSwgb3Igb25seSB0aGUgZmlsZSBuYW1lcyBvZiB0aGUgYXNzZXRzIChgZmFsc2VgKS4gRGVmYXVsdHMgdG8gYHRydWVgLlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn1cbiAgICAgICAgICovXG4gICAgICAgIGZ1bGxVcmw6IHRydWUsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgdHJhbnNwb3J0IG9iamVjdCBjb250YWlucyB0aGUgb3B0aW9ucyBwYXNzZWQgdG8gdGhlIFhIUiByZXF1ZXN0LlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7XG4gICAgICAgICAgICBwcm9jZXNzRGF0YTogZmFsc2VcbiAgICAgICAgfVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIGlmICghc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50ID0gdXJsQ29uZmlnLmFjY291bnRQYXRoO1xuICAgIH1cblxuICAgIGlmICghc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0ID0gdXJsQ29uZmlnLnByb2plY3RQYXRoO1xuICAgIH1cblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuXG4gICAgdmFyIGFzc2V0QXBpUGFyYW1zID0gWydlbmNvZGluZycsICdkYXRhJywgJ2NvbnRlbnRUeXBlJ107XG4gICAgdmFyIHNjb3BlQ29uZmlnID0ge1xuICAgICAgICB1c2VyOiBbJ3Njb3BlJywgJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCcsICd1c2VySWQnXSxcbiAgICAgICAgZ3JvdXA6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10sXG4gICAgICAgIHByb2plY3Q6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0J10sXG4gICAgfTtcblxuICAgIHZhciB2YWxpZGF0ZUZpbGVuYW1lID0gZnVuY3Rpb24gKGZpbGVuYW1lKSB7XG4gICAgICAgIGlmICghZmlsZW5hbWUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZmlsZW5hbWUgaXMgbmVlZGVkLicpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciB2YWxpZGF0ZVVybFBhcmFtcyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBwYXJ0S2V5cyA9IHNjb3BlQ29uZmlnW29wdGlvbnMuc2NvcGVdO1xuICAgICAgICBpZiAoIXBhcnRLZXlzKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3Njb3BlIHBhcmFtZXRlciBpcyBuZWVkZWQuJyk7XG4gICAgICAgIH1cblxuICAgICAgICAkLmVhY2gocGFydEtleXMsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmICghb3B0aW9uc1t0aGlzXSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcih0aGlzICsgJyBwYXJhbWV0ZXIgaXMgbmVlZGVkLicpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgdmFyIGJ1aWxkVXJsID0gZnVuY3Rpb24gKGZpbGVuYW1lLCBvcHRpb25zKSB7XG4gICAgICAgIHZhbGlkYXRlVXJsUGFyYW1zKG9wdGlvbnMpO1xuICAgICAgICB2YXIgcGFydEtleXMgPSBzY29wZUNvbmZpZ1tvcHRpb25zLnNjb3BlXTtcbiAgICAgICAgdmFyIHBhcnRzID0gJC5tYXAocGFydEtleXMsIGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgIHJldHVybiBvcHRpb25zW2tleV07XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoZmlsZW5hbWUpIHtcbiAgICAgICAgICAgIC8vIFRoaXMgcHJldmVudHMgYWRkaW5nIGEgdHJhaWxpbmcgLyBpbiB0aGUgVVJMIGFzIHRoZSBBc3NldCBBUElcbiAgICAgICAgICAgIC8vIGRvZXMgbm90IHdvcmsgY29ycmVjdGx5IHdpdGggaXRcbiAgICAgICAgICAgIGZpbGVuYW1lID0gJy8nICsgZmlsZW5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHBhcnRzLmpvaW4oJy8nKSArIGZpbGVuYW1lO1xuICAgIH07XG5cbiAgICAvLyBQcml2YXRlIGZ1bmN0aW9uLCBhbGwgcmVxdWVzdHMgZm9sbG93IGEgbW9yZSBvciBsZXNzIHNhbWUgYXBwcm9hY2ggdG9cbiAgICAvLyB1c2UgdGhlIEFzc2V0IEFQSSBhbmQgdGhlIGRpZmZlcmVuY2UgaXMgdGhlIEhUVFAgdmVyYlxuICAgIC8vXG4gICAgLy8gQHBhcmFtIHtzdHJpbmd9IGBtZXRob2RgIChSZXF1aXJlZCkgSFRUUCB2ZXJiXG4gICAgLy8gQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIGRlbGV0ZS9yZXBsYWNlL2NyZWF0ZVxuICAgIC8vIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCAoT3B0aW9uYWwpIEJvZHkgcGFyYW1ldGVycyB0byBzZW5kIHRvIHRoZSBBc3NldCBBUElcbiAgICAvLyBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgdmFyIHVwbG9hZCA9IGZ1bmN0aW9uIChtZXRob2QsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFsaWRhdGVGaWxlbmFtZShmaWxlbmFtZSk7XG4gICAgICAgIC8vIG1ha2Ugc3VyZSB0aGUgcGFyYW1ldGVyIGlzIGNsZWFuXG4gICAgICAgIG1ldGhvZCA9IG1ldGhvZC50b0xvd2VyQ2FzZSgpO1xuICAgICAgICB2YXIgY29udGVudFR5cGUgPSBwYXJhbXMgaW5zdGFuY2VvZiBGb3JtRGF0YSA9PT0gdHJ1ZSA/IGZhbHNlIDogJ2FwcGxpY2F0aW9uL2pzb24nO1xuICAgICAgICBpZiAoY29udGVudFR5cGUgPT09ICdhcHBsaWNhdGlvbi9qc29uJykge1xuICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIGFzc2V0QXBpUGFyYW1zKTtcbiAgICAgICAgfSBlbHNlIHsgLy8gZWxzZSB3ZSdyZSBzZW5kaW5nIGZvcm0gZGF0YSB3aGljaCBnb2VzIGRpcmVjdGx5IGluIHJlcXVlc3QgYm9keVxuICAgICAgICAgICAgLy8gRm9yIG11bHRpcGFydC9mb3JtLWRhdGEgdXBsb2FkcyB0aGUgZmlsZW5hbWUgaXMgbm90IHNldCBpbiB0aGUgVVJMLFxuICAgICAgICAgICAgLy8gaXQncyBnZXR0aW5nIHBpY2tlZCBieSB0aGUgRm9ybURhdGEgZmllbGQgZmlsZW5hbWUuXG4gICAgICAgICAgICBmaWxlbmFtZSA9IG1ldGhvZCA9PT0gJ3Bvc3QnIHx8IG1ldGhvZCA9PT0gJ3B1dCcgPyAnJyA6IGZpbGVuYW1lO1xuICAgICAgICB9XG4gICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyIHVybCA9IGJ1aWxkVXJsKGZpbGVuYW1lLCB1cmxPcHRpb25zKTtcbiAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdXJsT3B0aW9ucywgeyB1cmw6IHVybCwgY29udGVudFR5cGU6IGNvbnRlbnRUeXBlIH0pO1xuXG4gICAgICAgIHJldHVybiBodHRwW21ldGhvZF0ocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIGZpbGUgaW4gdGhlIEFzc2V0IEFQSS4gVGhlIHNlcnZlciByZXR1cm5zIGFuIGVycm9yIChzdGF0dXMgY29kZSBgNDA5YCwgY29uZmxpY3QpIGlmIHRoZSBmaWxlIGFscmVhZHkgZXhpc3RzLCBzb1xuICAgICAgICAqIGNoZWNrIGZpcnN0IHdpdGggYSBgbGlzdCgpYCBvciBhIGBnZXQoKWAuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBhYSA9IG5ldyBGLnNlcnZpY2UuQXNzZXQoe1xuICAgICAgICAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgIGdyb3VwOiAndGVhbTEnLFxuICAgICAgICAqICAgICAgICAgIHVzZXJJZDogJydcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAgICAgICAgKiAgICAgICBhYS5jcmVhdGUoJ3Rlc3QudHh0Jywge1xuICAgICAgICAqICAgICAgICAgICBlbmNvZGluZzogJ0JBU0VfNjQnLFxuICAgICAgICAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gICAgICAgICogICAgICAgICAgIGNvbnRlbnRUeXBlOiAndGV4dC9wbGFpbidcbiAgICAgICAgKiAgICAgICB9LCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAvLyBhbHRlcm5hdGl2ZWx5LCBjcmVhdGUgYSBuZXcgYXNzZXQgdXNpbmcgYSBmaWxlIHVwbG9hZGVkIHRocm91Z2ggYSBmb3JtXG4gICAgICAgICogICAgICAgLy8gdGhpcyBzYW1wbGUgY29kZSBnb2VzIHdpdGggYW4gaHRtbCBmb3JtIHRoYXQgbG9va3MgbGlrZSB0aGlzOlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgLy8gPGZvcm0gaWQ9XCJ1cGxvYWQtZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwiZmlsZVwiIHR5cGU9XCJmaWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gICAgICAgICogICAgICAgLy8gICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIj5VcGxvYWQgbXlGaWxlPC9idXR0b24+XG4gICAgICAgICogICAgICAgLy8gPC9mb3JtPlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgJCgnI3VwbG9hZC1maWxlJykub24oJ3N1Ym1pdCcsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICogICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBkYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGlucHV0Q29udHJvbCA9ICQoJyNmaWxlJylbMF07XG4gICAgICAgICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgIGFhLmNyZWF0ZShmaWxlbmFtZSwgZGF0YSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gY3JlYXRlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCAoT3B0aW9uYWwpIEJvZHkgcGFyYW1ldGVycyB0byBzZW5kIHRvIHRoZSBBc3NldCBBUEkuIFJlcXVpcmVkIGlmIHRoZSBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYCwgb3RoZXJ3aXNlIGlnbm9yZWQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZW5jb2RpbmdgIEVpdGhlciBgSEVYYCBvciBgQkFTRV82NGAuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmRhdGFgIFRoZSBlbmNvZGVkIGRhdGEgZm9yIHRoZSBmaWxlLiBSZXF1aXJlZCBpZiBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5jb250ZW50VHlwZWAgVGhlIG1pbWUgdHlwZSBvZiB0aGUgZmlsZS4gT3B0aW9uYWwuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ3Bvc3QnLCBmaWxlbmFtZSwgcGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGEgZmlsZSBmcm9tIHRoZSBBc3NldCBBUEksIGZldGNoaW5nIHRoZSBhc3NldCBjb250ZW50LiAoVG8gZ2V0IGEgbGlzdFxuICAgICAgICAqIG9mIHRoZSBhc3NldHMgaW4gYSBzY29wZSwgdXNlIGBsaXN0KClgLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSB0byByZXRyaWV2ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBnZXRTZXJ2aWNlT3B0aW9ucyA9IF9waWNrKHNlcnZpY2VPcHRpb25zLCBbJ3Njb3BlJywgJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCcsICd1c2VySWQnXSk7XG4gICAgICAgICAgICB2YXIgdXJsT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBnZXRTZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgdXJsID0gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdXJsT3B0aW9ucywgeyB1cmw6IHVybCB9KTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIHRoZSBsaXN0IG9mIHRoZSBhc3NldHMgaW4gYSBzY29wZS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBhYS5saXN0KHsgZnVsbFVybDogdHJ1ZSB9KS50aGVuKGZ1bmN0aW9uKGZpbGVMaXN0KXtcbiAgICAgICAgKiAgICAgICAgICAgY29uc29sZS5sb2coJ2FycmF5IG9mIGZpbGVzID0gJywgZmlsZUxpc3QpO1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5zY29wZWAgKE9wdGlvbmFsKSBUaGUgc2NvcGUgKGB1c2VyYCwgYGdyb3VwYCwgYHByb2plY3RgKS5cbiAgICAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IGBvcHRpb25zLmZ1bGxVcmxgIChPcHRpb25hbCkgRGV0ZXJtaW5lcyBpZiB0aGUgbGlzdCBvZiBhc3NldHMgaW4gYSBzY29wZSBpbmNsdWRlcyB0aGUgY29tcGxldGUgVVJMIGZvciBlYWNoIGFzc2V0IChgdHJ1ZWApLCBvciBvbmx5IHRoZSBmaWxlIG5hbWVzIG9mIHRoZSBhc3NldHMgKGBmYWxzZWApLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGxpc3Q6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciB1cmwgPSBidWlsZFVybCgnJywgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsIH0pO1xuICAgICAgICAgICAgdmFyIGZ1bGxVcmwgPSBnZXRPcHRpb25zLmZ1bGxVcmw7XG5cbiAgICAgICAgICAgIGlmICghZnVsbFVybCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldCh7fSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKVxuICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChmaWxlcykge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZnVsbFBhdGhGaWxlcyA9ICQubWFwKGZpbGVzLCBmdW5jdGlvbiAoZmlsZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGJ1aWxkVXJsKGZpbGUsIHVybE9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUoZnVsbFBhdGhGaWxlcywgbWUpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJlcGxhY2VzIGFuIGV4aXN0aW5nIGZpbGUgaW4gdGhlIEFzc2V0IEFQSS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAvLyByZXBsYWNlIGFuIGFzc2V0IHVzaW5nIGVuY29kZWQgdGV4dFxuICAgICAgICAqICAgICAgIGFhLnJlcGxhY2UoJ3Rlc3QudHh0Jywge1xuICAgICAgICAqICAgICAgICAgICBlbmNvZGluZzogJ0JBU0VfNjQnLFxuICAgICAgICAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhObFkyOXVaQ0IwWlhOMElHWnBiR1V1JyxcbiAgICAgICAgKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICAgICAgICAqICAgICAgIH0sIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIHJlcGxhY2UgYW4gYXNzZXQgdXNpbmcgYSBmaWxlIHVwbG9hZGVkIHRocm91Z2ggYSBmb3JtXG4gICAgICAgICogICAgICAgLy8gdGhpcyBzYW1wbGUgY29kZSBnb2VzIHdpdGggYW4gaHRtbCBmb3JtIHRoYXQgbG9va3MgbGlrZSB0aGlzOlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgLy8gPGZvcm0gaWQ9XCJyZXBsYWNlLWZpbGVcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwicmVwbGFjZS1maWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gICAgICAgICogICAgICAgLy8gICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIj5SZXBsYWNlIG15RmlsZTwvYnV0dG9uPlxuICAgICAgICAqICAgICAgIC8vIDwvZm9ybT5cbiAgICAgICAgKiAgICAgICAvL1xuICAgICAgICAqICAgICAgICQoJyNyZXBsYWNlLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgKiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGZpbGVuYW1lID0gJCgnI3JlcGxhY2UtZmlsZW5hbWUnKS52YWwoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgZGF0YSA9IG5ldyBGb3JtRGF0YSgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICAgICAgICAqICAgICAgICAgIGRhdGEuYXBwZW5kKCdmaWxlJywgaW5wdXRDb250cm9sLmZpbGVzWzBdLCBmaWxlbmFtZSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICBhYS5yZXBsYWNlKGZpbGVuYW1lLCBkYXRhLCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgYmVpbmcgcmVwbGFjZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSS4gUmVxdWlyZWQgaWYgdGhlIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLCBvdGhlcndpc2UgaWdub3JlZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5lbmNvZGluZ2AgRWl0aGVyIGBIRVhgIG9yIGBCQVNFXzY0YC4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZGF0YWAgVGhlIGVuY29kZWQgZGF0YSBmb3IgdGhlIGZpbGUuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmNvbnRlbnRUeXBlYCBUaGUgbWltZSB0eXBlIG9mIHRoZSBmaWxlLiBPcHRpb25hbC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgcmVwbGFjZTogZnVuY3Rpb24gKGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ3B1dCcsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgYSBmaWxlIGZyb20gdGhlIEFzc2V0IEFQSS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBhYS5kZWxldGUoc2FtcGxlRmlsZU5hbWUpO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIGRlbGV0ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgZGVsZXRlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ2RlbGV0ZScsIGZpbGVuYW1lLCB7fSwgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgYXNzZXRVcmw6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGJ1aWxkVXJsKGZpbGVuYW1lLCB1cmxPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjI0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhlIEF1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlIHByb3ZpZGVzIG1ldGhvZHMgZm9yIGxvZ2dpbmcgaW4gYW5kIGxvZ2dpbmcgb3V0LiBPbiBsb2dpbiwgdGhpcyBzZXJ2aWNlIGNyZWF0ZXMgYW5kIHJldHVybnMgYSB1c2VyIGFjY2VzcyB0b2tlbi5cbiAqXG4gKiBVc2VyIGFjY2VzcyB0b2tlbnMgYXJlIHJlcXVpcmVkIGZvciBlYWNoIGNhbGwgdG8gRXBpY2VudGVyLiAoU2VlIFtQcm9qZWN0IEFjY2Vzc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSBmb3IgbW9yZSBpbmZvcm1hdGlvbi4pXG4gKlxuICogSWYgeW91IG5lZWQgYWRkaXRpb25hbCBmdW5jdGlvbmFsaXR5IC0tIHN1Y2ggYXMgdHJhY2tpbmcgc2Vzc2lvbiBpbmZvcm1hdGlvbiwgZWFzaWx5IHJldHJpZXZpbmcgdGhlIHVzZXIgdG9rZW4sIG9yIGdldHRpbmcgdGhlIGdyb3VwcyB0byB3aGljaCBhbiBlbmQgdXNlciBiZWxvbmdzIC0tIGNvbnNpZGVyIHVzaW5nIHRoZSBbQXV0aG9yaXphdGlvbiBNYW5hZ2VyXSguLi9hdXRoLW1hbmFnZXIvKSBpbnN0ZWFkLlxuICpcbiAqICAgICAgdmFyIGF1dGggPSBuZXcgRi5zZXJ2aWNlLkF1dGgoKTtcbiAqICAgICAgYXV0aC5sb2dpbih7IHVzZXJOYW1lOiAnanNtaXRoQGFjbWVzaW11bGF0aW9ucy5jb20nLFxuICogICAgICAgICAgICAgICAgICBwYXNzd29yZDogJ3Bhc3N3MHJkJyB9KTtcbiAqICAgICAgYXV0aC5sb2dvdXQoKTtcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRW1haWwgb3IgdXNlcm5hbWUgdG8gdXNlIGZvciBsb2dnaW5nIGluLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1c2VyTmFtZTogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcGFzc3dvcmQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZCBmb3IgdGhpcyBgdXNlck5hbWVgLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yIHRoZSAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gUmVxdWlyZWQgaWYgdGhlIGB1c2VyTmFtZWAgaXMgZm9yIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdhdXRoZW50aWNhdGlvbicpXG4gICAgfSk7XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIExvZ3MgdXNlciBpbiwgcmV0dXJuaW5nIHRoZSB1c2VyIGFjY2VzcyB0b2tlbi5cbiAgICAgICAgICpcbiAgICAgICAgICogSWYgbm8gYHVzZXJOYW1lYCBvciBgcGFzc3dvcmRgIHdlcmUgcHJvdmlkZWQgaW4gdGhlIGluaXRpYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLCB0aGV5IGFyZSByZXF1aXJlZCBpbiB0aGUgYG9wdGlvbnNgIGhlcmUuIElmIG5vIGBhY2NvdW50YCB3YXMgcHJvdmlkZWQgaW4gdGhlIGluaXRpYWwgY29uZmlndXJhdGlvbiBvcHRpb25zIGFuZCB0aGUgYHVzZXJOYW1lYCBpcyBmb3IgYW4gW2VuZCB1c2VyXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpLCB0aGUgYGFjY291bnRgIGlzIHJlcXVpcmVkIGFzIHdlbGwuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgYXV0aC5sb2dpbih7XG4gICAgICAgICAqICAgICAgICAgIHVzZXJOYW1lOiAnanNtaXRoJyxcbiAgICAgICAgICogICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCcsXG4gICAgICAgICAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyB9KVxuICAgICAgICAgKiAgICAgIC50aGVuKGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhcInVzZXIgYWNjZXNzIHRva2VuIGlzOiBcIiwgdG9rZW4uYWNjZXNzX3Rva2VuKTtcbiAgICAgICAgICogICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9naW46IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7IHN1Y2Nlc3M6ICQubm9vcCB9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBpZiAoIWh0dHBPcHRpb25zLnVzZXJOYW1lIHx8ICFodHRwT3B0aW9ucy5wYXNzd29yZCkge1xuICAgICAgICAgICAgICAgIHZhciByZXNwID0geyBzdGF0dXM6IDQwMSwgc3RhdHVzTWVzc2FnZTogJ05vIHVzZXJuYW1lIG9yIHBhc3N3b3JkIHNwZWNpZmllZC4nIH07XG4gICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMuZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5lcnJvci5jYWxsKHRoaXMsIHJlc3ApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVqZWN0KHJlc3ApLnByb21pc2UoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHBvc3RQYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgdXNlck5hbWU6IGh0dHBPcHRpb25zLnVzZXJOYW1lLFxuICAgICAgICAgICAgICAgIHBhc3N3b3JkOiBodHRwT3B0aW9ucy5wYXNzd29yZCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBpZiAoaHR0cE9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICAgICAgICAgIC8vcGFzcyBpbiBudWxsIGZvciBhY2NvdW50IHVuZGVyIG9wdGlvbnMgaWYgeW91IGRvbid0IHdhbnQgaXQgdG8gYmUgc2VudFxuICAgICAgICAgICAgICAgIHBvc3RQYXJhbXMuYWNjb3VudCA9IGh0dHBPcHRpb25zLmFjY291bnQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocG9zdFBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2dzIHVzZXIgb3V0IGZyb20gc3BlY2lmaWVkIGFjY291bnRzLlxuICAgICAgICAgKiBFcGljZW50ZXIgbG9nb3V0IGlzIG5vdCBpbXBsZW1lbnRlZCB5ZXQsIGFkZGVkIGEgZHVtbXkgcHJvbWlzZSB0aGF0IGdldHMgYXV0b21hdGljYWxseSByZXNvbHZlZC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICBhdXRoLmxvZ291dCgpO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2dvdXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgZHRkLnJlc29sdmUoKTtcbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqICMjIENoYW5uZWwgU2VydmljZVxuICpcbiAqIFRoZSBFcGljZW50ZXIgcGxhdGZvcm0gcHJvdmlkZXMgYSBwdXNoIGNoYW5uZWwsIHdoaWNoIGFsbG93cyB5b3UgdG8gcHVibGlzaCBhbmQgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzIHdpdGhpbiBhIFtwcm9qZWN0XSguLi8uLi8uLi9nbG9zc2FyeS8jcHJvamVjdHMpLCBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvciBbbXVsdGlwbGF5ZXIgd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuIFRoZXJlIGFyZSB0d28gbWFpbiB1c2UgY2FzZXMgZm9yIHRoZSBjaGFubmVsOiBldmVudCBub3RpZmljYXRpb25zIGFuZCBjaGF0IG1lc3NhZ2VzLlxuICpcbiAqIFRoZSBDaGFubmVsIFNlcnZpY2UgaXMgYSBidWlsZGluZyBibG9jayBmb3IgdGhpcyBmdW5jdGlvbmFsaXR5LiBJdCBjcmVhdGVzIGEgcHVibGlzaC1zdWJzY3JpYmUgb2JqZWN0LCBhbGxvd2luZyB5b3UgdG8gcHVibGlzaCBtZXNzYWdlcywgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzLCBvciB1bnN1YnNjcmliZSBmcm9tIG1lc3NhZ2VzIGZvciBhIGdpdmVuICd0b3BpYycgb24gYSBgJC5jb21ldGRgIHRyYW5zcG9ydCBpbnN0YW5jZS5cbiAqXG4gKiBUeXBpY2FsbHksIHlvdSB1c2UgdGhlIFtFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLykgdG8gY3JlYXRlIG9yIHJldHJpZXZlIGNoYW5uZWxzLCB0aGVuIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gbGlzdGVuIHRvIG9yIHVwZGF0ZSBkYXRhLiAoRm9yIGFkZGl0aW9uYWwgYmFja2dyb3VuZCBvbiBFcGljZW50ZXIncyBwdXNoIGNoYW5uZWwsIHNlZSB0aGUgaW50cm9kdWN0b3J5IG5vdGVzIG9uIHRoZSBbUHVzaCBDaGFubmVsIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL2NoYW5uZWwvKSBwYWdlLilcbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBDaGFubmVsIFNlcnZpY2UuIFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLlxuICpcbiAqIFRvIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlLCBpbnN0YW50aWF0ZSBpdCwgdGhlbiBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbiAqXG4gKiAgICAgICAgdmFyIGNzID0gbmV3IEYuc2VydmljZS5DaGFubmVsKCk7XG4gKiAgICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi92YXJpYWJsZXMnLCB7IHByaWNlOiA1MCB9KTtcbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhIENoYW5uZWwgU2VydmljZSBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIFRoZSBvcHRpb25zIG9iamVjdCB0byBjb25maWd1cmUgdGhlIENoYW5uZWwgU2VydmljZS5cbiAqICogYG9wdGlvbnMuYmFzZWAgVGhlIGJhc2UgdG9waWMuIFRoaXMgaXMgYWRkZWQgYXMgYSBwcmVmaXggdG8gYWxsIGZ1cnRoZXIgdG9waWNzIHlvdSBwdWJsaXNoIG9yIHN1YnNjcmliZSB0byB3aGlsZSB3b3JraW5nIHdpdGggdGhpcyBDaGFubmVsIFNlcnZpY2UuXG4gKiAqIGBvcHRpb25zLnRvcGljUmVzb2x2ZXJgIEEgZnVuY3Rpb24gdGhhdCBwcm9jZXNzZXMgYWxsICd0b3BpY3MnIHBhc3NlZCBpbnRvIHRoZSBgcHVibGlzaGAgYW5kIGBzdWJzY3JpYmVgIG1ldGhvZHMuIFRoaXMgaXMgdXNlZnVsIGlmIHlvdSB3YW50IHRvIGltcGxlbWVudCB5b3VyIG93biBzZXJpYWxpemUgZnVuY3Rpb25zIGZvciBjb252ZXJ0aW5nIGN1c3RvbSBvYmplY3RzIHRvIHRvcGljIG5hbWVzLiBSZXR1cm5zIGEgU3RyaW5nLiBCeSBkZWZhdWx0LCBpdCBqdXN0IGVjaG9lcyB0aGUgdG9waWMuXG4gKiAqIGBvcHRpb25zLnRyYW5zcG9ydGAgVGhlIGluc3RhbmNlIG9mIGAkLmNvbWV0ZGAgdG8gaG9vayBvbnRvLiBTZWUgaHR0cDovL2RvY3MuY29tZXRkLm9yZy9yZWZlcmVuY2UvamF2YXNjcmlwdC5odG1sIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQgb24gY29tZXRkLlxuICovXG52YXIgQ2hhbm5lbCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYmFzZSB0b3BpYy4gVGhpcyBpcyBhZGRlZCBhcyBhIHByZWZpeCB0byBhbGwgZnVydGhlciB0b3BpY3MgeW91IHB1Ymxpc2ggb3Igc3Vic2NyaWJlIHRvIHdoaWxlIHdvcmtpbmcgd2l0aCB0aGlzIENoYW5uZWwgU2VydmljZS5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGJhc2U6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBBIGZ1bmN0aW9uIHRoYXQgcHJvY2Vzc2VzIGFsbCAndG9waWNzJyBwYXNzZWQgaW50byB0aGUgYHB1Ymxpc2hgIGFuZCBgc3Vic2NyaWJlYCBtZXRob2RzLiBUaGlzIGlzIHVzZWZ1bCBpZiB5b3Ugd2FudCB0byBpbXBsZW1lbnQgeW91ciBvd24gc2VyaWFsaXplIGZ1bmN0aW9ucyBmb3IgY29udmVydGluZyBjdXN0b20gb2JqZWN0cyB0byB0b3BpYyBuYW1lcy4gQnkgZGVmYXVsdCwgaXQganVzdCBlY2hvZXMgdGhlIHRvcGljLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqIGB0b3BpY2AgVG9waWMgdG8gcGFyc2UuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgICAgICpcbiAgICAgICAgICogKiAqU3RyaW5nKjogVGhpcyBmdW5jdGlvbiBzaG91bGQgcmV0dXJuIGEgc3RyaW5nIHRvcGljLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICB0b3BpY1Jlc29sdmVyOiBmdW5jdGlvbiAodG9waWMpIHtcbiAgICAgICAgICAgIHJldHVybiB0b3BpYztcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGluc3RhbmNlIG9mIGAkLmNvbWV0ZGAgdG8gaG9vayBvbnRvLlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiBudWxsXG4gICAgfTtcbiAgICB0aGlzLmNoYW5uZWxPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbn07XG5cbnZhciBtYWtlTmFtZSA9IGZ1bmN0aW9uIChjaGFubmVsTmFtZSwgdG9waWMpIHtcbiAgICAvL1JlcGxhY2UgdHJhaWxpbmcvZG91YmxlIHNsYXNoZXNcbiAgICB2YXIgbmV3TmFtZSA9IChjaGFubmVsTmFtZSA/IChjaGFubmVsTmFtZSArICcvJyArIHRvcGljKSA6IHRvcGljKS5yZXBsYWNlKC9cXC9cXC8vZywgJy8nKS5yZXBsYWNlKC9cXC8kLywnJyk7XG4gICAgcmV0dXJuIG5ld05hbWU7XG59O1xuXG5cbkNoYW5uZWwucHJvdG90eXBlID0gJC5leHRlbmQoQ2hhbm5lbC5wcm90b3R5cGUsIHtcblxuICAgIC8vIGZ1dHVyZSBmdW5jdGlvbmFsaXR5OlxuICAgIC8vICAgICAgLy8gU2V0IHRoZSBjb250ZXh0IGZvciB0aGUgY2FsbGJhY2tcbiAgICAvLyAgICAgIGNzLnN1YnNjcmliZSgncnVuJywgZnVuY3Rpb24gKCkgeyB0aGlzLmlubmVySFRNTCA9ICdUcmlnZ2VyZWQnfSwgZG9jdW1lbnQuYm9keSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gQ29udHJvbCB0aGUgb3JkZXIgb2Ygb3BlcmF0aW9ucyBieSBzZXR0aW5nIHRoZSBgcHJpb3JpdHlgXG4gICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4nLCBjYiwgdGhpcywge3ByaW9yaXR5OiA5fSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIDUwXG4gICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4vdmFyaWFibGVzL3ByaWNlJywgY2IsIHRoaXMsIHtwcmlvcml0eTogMzAsIHZhbHVlOiA1MH0pO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIE9ubHkgZXhlY3V0ZSB0aGUgY2FsbGJhY2ssIGBjYmAsIGlmIHRoZSB2YWx1ZSBvZiB0aGUgYHByaWNlYCB2YXJpYWJsZSBpcyBncmVhdGVyIHRoYW4gNTBcbiAgICAgLy8gICAgICBzdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6ICc+NTAnfSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIGV2ZW5cbiAgICAgLy8gICAgICBzdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6IGZ1bmN0aW9uICh2YWwpIHtyZXR1cm4gdmFsICUgMiA9PT0gMH19KTtcblxuXG4gICAgLyoqXG4gICAgICogU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqIFRoZSB0b3BpYyBzaG91bGQgaW5jbHVkZSB0aGUgZnVsbCBwYXRoIG9mIHRoZSBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBmb3IgdGVhbSBwcm9qZWN0cyksIHByb2plY3QgaWQsIGFuZCBncm91cCBuYW1lLiAoSW4gbW9zdCBjYXNlcywgaXQgaXMgc2ltcGxlciB0byB1c2UgdGhlIFtFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLykgaW5zdGVhZCwgaW4gd2hpY2ggY2FzZSB0aGlzIGlzIGNvbmZpZ3VyZWQgZm9yIHlvdS4pXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlcyoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBjYiA9IGZ1bmN0aW9uKHZhbCkgeyBjb25zb2xlLmxvZyh2YWwuZGF0YSk7IH07XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGEgdG9wLWxldmVsICdydW4nIHRvcGljXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4nLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGNoaWxkcmVuIG9mIHRoZSAncnVuJyB0b3BpYy4gTm90ZSB0aGlzIHdpbGwgYWxzbyBiZSB0cmlnZ2VyZWQgZm9yIGNoYW5nZXMgdG8gcnVuLngueS56LlxuICAgICAqICAgICAgY3Muc3Vic2NyaWJlKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuLyonLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGJvdGggdGhlIHRvcC1sZXZlbCAncnVuJyB0b3BpYyBhbmQgaXRzIGNoaWxkcmVuXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoWycvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuJyxcbiAgICAgKiAgICAgICAgICAnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi8qJ10sIGNiKTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSBwYXJ0aWN1bGFyIHZhcmlhYmxlXG4gICAgICogICAgICBzdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vdmFyaWFibGVzL3ByaWNlJywgY2IpO1xuICAgICAqXG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpTdHJpbmcqIFJldHVybnMgYSB0b2tlbiB5b3UgY2FuIGxhdGVyIHVzZSB0byB1bnN1YnNjcmliZS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfEFycmF5fSAgIGB0b3BpY2AgICAgTGlzdCBvZiB0b3BpY3MgdG8gbGlzdGVuIGZvciBjaGFuZ2VzIG9uLlxuICAgICAqIEBwYXJhbSAge0Z1bmN0aW9ufSBgY2FsbGJhY2tgIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGV4ZWN1dGUuIENhbGxiYWNrIGlzIGNhbGxlZCB3aXRoIHNpZ25hdHVyZSBgKGV2dCwgcGF5bG9hZCwgbWV0YWRhdGEpYC5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9ICAgYGNvbnRleHRgICBDb250ZXh0IGluIHdoaWNoIHRoZSBgY2FsbGJhY2tgIGlzIGV4ZWN1dGVkLlxuICAgICAqIEBwYXJhbSAge09iamVjdH0gICBgb3B0aW9uc2AgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICogQHBhcmFtICB7TnVtYmVyfSAgIGBvcHRpb25zLnByaW9yaXR5YCAgVXNlZCB0byBjb250cm9sIG9yZGVyIG9mIG9wZXJhdGlvbnMuIERlZmF1bHRzIHRvIDAuIENhbiBiZSBhbnkgK3ZlIG9yIC12ZSBudW1iZXIuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE51bWJlcnxGdW5jdGlvbn0gICBgb3B0aW9ucy52YWx1ZWAgVGhlIGBjYWxsYmFja2AgaXMgb25seSB0cmlnZ2VyZWQgaWYgdGhpcyBjb25kaXRpb24gbWF0Y2hlcy4gU2VlIGV4YW1wbGVzIGZvciBkZXRhaWxzLlxuICAgICAqXG4gICAgICovXG4gICAgc3Vic2NyaWJlOiBmdW5jdGlvbiAodG9waWMsIGNhbGxiYWNrLCBjb250ZXh0LCBvcHRpb25zKSB7XG5cbiAgICAgICAgdmFyIHRvcGljcyA9IFtdLmNvbmNhdCh0b3BpYyk7XG4gICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgIHZhciBzdWJzY3JpcHRpb25JZHMgPSBbXTtcbiAgICAgICAgdmFyIG9wdHMgPSBtZS5jaGFubmVsT3B0aW9ucztcblxuICAgICAgICBvcHRzLnRyYW5zcG9ydC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAkLmVhY2godG9waWNzLCBmdW5jdGlvbiAoaW5kZXgsIHRvcGljKSB7XG4gICAgICAgICAgICAgICAgdG9waWMgPSBtYWtlTmFtZShvcHRzLmJhc2UsIG9wdHMudG9waWNSZXNvbHZlcih0b3BpYykpO1xuICAgICAgICAgICAgICAgIHN1YnNjcmlwdGlvbklkcy5wdXNoKG9wdHMudHJhbnNwb3J0LnN1YnNjcmliZSh0b3BpYywgY2FsbGJhY2spKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIChzdWJzY3JpcHRpb25JZHNbMV0gPyBzdWJzY3JpcHRpb25JZHMgOiBzdWJzY3JpcHRpb25JZHNbMF0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBQdWJsaXNoIGRhdGEgdG8gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAqXG4gICAgICogICAgICAvLyBTZW5kIGRhdGEgdG8gYWxsIHN1YnNjcmliZXJzIG9mIHRoZSAncnVuJyB0b3BpY1xuICAgICAqICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bicsIHsgY29tcGxldGVkOiBmYWxzZSB9KTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU2VuZCBkYXRhIHRvIGFsbCBzdWJzY3JpYmVycyBvZiB0aGUgJ3J1bi92YXJpYWJsZXMnIHRvcGljXG4gICAgICogICAgICBjcy5wdWJsaXNoKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuL3ZhcmlhYmxlcycsIHsgcHJpY2U6IDUwIH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYHRvcGljYCBUb3BpYyB0byBwdWJsaXNoIHRvLlxuICAgICAqIEBwYXJhbSAgeyp9IGBkYXRhYCAgRGF0YSB0byBwdWJsaXNoIHRvIHRvcGljLlxuICAgICAqXG4gICAgICovXG4gICAgcHVibGlzaDogZnVuY3Rpb24gKHRvcGljLCBkYXRhKSB7XG4gICAgICAgIHZhciB0b3BpY3MgPSBbXS5jb25jYXQodG9waWMpO1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICB2YXIgcmV0dXJuT2JqcyA9IFtdO1xuICAgICAgICB2YXIgb3B0cyA9IG1lLmNoYW5uZWxPcHRpb25zO1xuXG5cbiAgICAgICAgb3B0cy50cmFuc3BvcnQuYmF0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgJC5lYWNoKHRvcGljcywgZnVuY3Rpb24gKGluZGV4LCB0b3BpYykge1xuICAgICAgICAgICAgICAgIHRvcGljID0gbWFrZU5hbWUob3B0cy5iYXNlLCBvcHRzLnRvcGljUmVzb2x2ZXIodG9waWMpKTtcbiAgICAgICAgICAgICAgICBpZiAodG9waWMuY2hhckF0KHRvcGljLmxlbmd0aCAtIDEpID09PSAnKicpIHtcbiAgICAgICAgICAgICAgICAgICAgdG9waWMgPSB0b3BpYy5yZXBsYWNlKC9cXCorJC8sICcnKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdZb3UgY2FuIGNhbm5vdCBwdWJsaXNoIHRvIGNoYW5uZWxzIHdpdGggd2lsZGNhcmRzLiBQdWJsaXNoaW5nIHRvICcsIHRvcGljLCAnaW5zdGVhZCcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5PYmpzLnB1c2gob3B0cy50cmFuc3BvcnQucHVibGlzaCh0b3BpYywgZGF0YSkpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gKHJldHVybk9ianNbMV0gPyByZXR1cm5PYmpzIDogcmV0dXJuT2Jqc1swXSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFVuc3Vic2NyaWJlIGZyb20gY2hhbmdlcyB0byBhIHRvcGljLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgY3MudW5zdWJzY3JpYmUoJ3NhbXBsZVRva2VuJyk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYHRva2VuYCBUaGUgdG9rZW4gZm9yIHRvcGljIGlzIHJldHVybmVkIHdoZW4geW91IGluaXRpYWxseSBzdWJzY3JpYmUuIFBhc3MgaXQgaGVyZSB0byB1bnN1YnNjcmliZSBmcm9tIHRoYXQgdG9waWMuXG4gICAgICovXG4gICAgdW5zdWJzY3JpYmU6IGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICB0aGlzLmNoYW5uZWxPcHRpb25zLnRyYW5zcG9ydC51bnN1YnNjcmliZSh0b2tlbik7XG4gICAgICAgIHJldHVybiB0b2tlbjtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RhcnQgbGlzdGVuaW5nIGZvciBldmVudHMgb24gdGhpcyBpbnN0YW5jZS4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vbi8uXG4gICAgICpcbiAgICAgKiBTdXBwb3J0ZWQgZXZlbnRzIGFyZTogYGNvbm5lY3RgLCBgZGlzY29ubmVjdGAsIGBzdWJzY3JpYmVgLCBgdW5zdWJzY3JpYmVgLCBgcHVibGlzaGAsIGBlcnJvcmAuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqL1xuICAgIG9uOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS5vbi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTdG9wIGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vZmYvLlxuICAgICAqL1xuICAgIG9mZjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub2ZmLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRyaWdnZXIgZXZlbnRzIGFuZCBleGVjdXRlIGhhbmRsZXJzLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqL1xuICAgIHRyaWdnZXI6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIuYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9XG5cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IENoYW5uZWw7XG4iLCIvKipcbiAqIEBjbGFzcyBDb25maWd1cmF0aW9uU2VydmljZVxuICpcbiAqIEFsbCBzZXJ2aWNlcyB0YWtlIGluIGEgY29uZmlndXJhdGlvbiBzZXR0aW5ncyBvYmplY3QgdG8gY29uZmlndXJlIHRoZW1zZWx2ZXMuIEEgSlMgaGFzaCB7fSBpcyBhIHZhbGlkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LCBidXQgb3B0aW9uYWxseSB5b3UgY2FuIHVzZSB0aGUgY29uZmlndXJhdGlvbiBzZXJ2aWNlIHRvIHRvZ2dsZSBjb25maWdzIGJhc2VkIG9uIHRoZSBlbnZpcm9ubWVudFxuICpcbiAqIEBleGFtcGxlXG4gKiAgICAgdmFyIGNzID0gcmVxdWlyZSgnY29uZmlndXJhdGlvbi1zZXJ2aWNlJykoe1xuICogICAgICAgICAgZGV2OiB7IC8vZW52aXJvbm1lbnRcbiAgICAgICAgICAgICAgICBwb3J0OiAzMDAwLFxuICAgICAgICAgICAgICAgIGhvc3Q6ICdsb2NhbGhvc3QnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHByb2Q6IHtcbiAgICAgICAgICAgICAgICBwb3J0OiA4MDgwLFxuICAgICAgICAgICAgICAgIGhvc3Q6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgICAgICAgICBsb2dMZXZlbDogJ25vbmUnXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgbG9nTGV2ZWw6ICdERUJVRycgLy9nbG9iYWxcbiAqICAgICB9KTtcbiAqXG4gKiAgICAgIGNzLmdldCgnbG9nTGV2ZWwnKTsgLy9yZXR1cm5zICdERUJVRydcbiAqXG4gKiAgICAgIGNzLnNldEVudignZGV2Jyk7XG4gKiAgICAgIGNzLmdldCgnbG9nTGV2ZWwnKTsgLy9yZXR1cm5zICdERUJVRydcbiAqXG4gKiAgICAgIGNzLnNldEVudigncHJvZCcpO1xuICogICAgICBjcy5nZXQoJ2xvZ0xldmVsJyk7IC8vcmV0dXJucyAnbm9uZSdcbiAqXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xudmFyIHVybFNlcnZpY2UgPSByZXF1aXJlKCcuL3VybC1jb25maWctc2VydmljZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAvL1RPRE86IEVudmlyb25tZW50c1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgbG9nTGV2ZWw6ICdOT05FJ1xuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHNlcnZpY2VPcHRpb25zLnNlcnZlciA9IHVybFNlcnZpY2Uoc2VydmljZU9wdGlvbnMuc2VydmVyKTtcblxuICAgIHJldHVybiB7XG5cbiAgICAgICAgZGF0YTogc2VydmljZU9wdGlvbnMsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgZW52aXJvbm1lbnQga2V5IHRvIGdldCBjb25maWd1cmF0aW9uIG9wdGlvbnMgZnJvbVxuICAgICAgICAgKiBAcGFyYW0geyBzdHJpbmd9IGVudlxuICAgICAgICAgKi9cbiAgICAgICAgc2V0RW52OiBmdW5jdGlvbiAoZW52KSB7XG5cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd9IHByb3BlcnR5IG9wdGlvbmFsXG4gICAgICAgICAqIEByZXR1cm4geyp9ICAgICAgICAgIFZhbHVlIG9mIHByb3BlcnR5IGlmIHNwZWNpZmllZCwgdGhlIGVudGlyZSBjb25maWcgb2JqZWN0IG90aGVyd2lzZVxuICAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAocHJvcGVydHkpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9uc1twcm9wZXJ0eV07XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCBjb25maWd1cmF0aW9uLlxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5IGlmIGEga2V5IGlzIHByb3ZpZGVkLCBzZXQgYSBrZXkgdG8gdGhhdCB2YWx1ZS4gT3RoZXJ3aXNlIG1lcmdlIG9iamVjdCB3aXRoIGN1cnJlbnQgY29uZmlnXG4gICAgICAgICAqIEBwYXJhbSAgeyp9IHZhbHVlICB2YWx1ZSBmb3IgcHJvdmlkZWQga2V5XG4gICAgICAgICAqL1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9uc1trZXldID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9O1xufTtcblxuIiwiLyoqXG4gKiAjI0RhdGEgQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGUgRGF0YSBBUEkgU2VydmljZSBhbGxvd3MgeW91IHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgbWFuaXB1bGF0ZSBkYXRhIHJlbGF0ZWQgdG8gYW55IG9mIHlvdXIgcHJvamVjdHMuIERhdGEgYXJlIG9yZ2FuaXplZCBpbiBjb2xsZWN0aW9ucy4gRWFjaCBjb2xsZWN0aW9uIGNvbnRhaW5zIGEgZG9jdW1lbnQ7IGVhY2ggZWxlbWVudCBvZiB0aGlzIHRvcC1sZXZlbCBkb2N1bWVudCBpcyBhIEpTT04gb2JqZWN0LiAoU2VlIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24gb24gdGhlIHVuZGVybHlpbmcgW0RhdGEgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvZGF0YV9hcGkvKS4pXG4gKlxuICogQWxsIEFQSSBjYWxscyB0YWtlIGluIGFuIFwib3B0aW9uc1wiIG9iamVjdCBhcyB0aGUgbGFzdCBwYXJhbWV0ZXIuIFRoZSBvcHRpb25zIGNhbiBiZSB1c2VkIHRvIGV4dGVuZC9vdmVycmlkZSB0aGUgRGF0YSBBUEkgU2VydmljZSBkZWZhdWx0cy4gSW4gcGFydGljdWxhciwgdGhlcmUgYXJlIHRocmVlIHJlcXVpcmVkIHBhcmFtZXRlcnMgd2hlbiB5b3UgaW5zdGFudGlhdGUgdGhlIERhdGEgU2VydmljZTpcbiAqXG4gKiAqIGBhY2NvdW50YDogRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICogKiBgcHJvamVjdGA6IEVwaWNlbnRlciBwcm9qZWN0IGlkLlxuICogKiBgcm9vdGA6IFRoZSB0aGUgbmFtZSBvZiB0aGUgY29sbGVjdGlvbi4gSWYgeW91IGhhdmUgbXVsdGlwbGUgY29sbGVjdGlvbnMgd2l0aGluIGVhY2ggb2YgeW91ciBwcm9qZWN0cywgeW91IGNhbiBhbHNvIHBhc3MgdGhlIGNvbGxlY3Rpb24gbmFtZSBhcyBhbiBvcHRpb24gZm9yIGVhY2ggY2FsbC5cbiAqXG4gKiAgICAgICB2YXIgZHMgPSBuZXcgRi5zZXJ2aWNlLkRhdGEoe1xuICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgICAgIHJvb3Q6ICdzdXJ2ZXktcmVzcG9uc2VzJyxcbiAqICAgICAgICAgIHNlcnZlcjogeyBob3N0OiAnYXBpLmZvcmlvLmNvbScgfVxuICogICAgICAgfSk7XG4gKiAgICAgICBkcy5zYXZlQXMoJ3VzZXIxJyxcbiAqICAgICAgICAgIHsgJ3F1ZXN0aW9uMSc6IDIsICdxdWVzdGlvbjInOiAxMCxcbiAqICAgICAgICAgICdxdWVzdGlvbjMnOiBmYWxzZSwgJ3F1ZXN0aW9uNCc6ICdzb21ldGltZXMnIH0gKTtcbiAqICAgICAgIGRzLnNhdmVBcygndXNlcjInLFxuICogICAgICAgICAgeyAncXVlc3Rpb24xJzogMywgJ3F1ZXN0aW9uMic6IDgsXG4gKiAgICAgICAgICAncXVlc3Rpb24zJzogdHJ1ZSwgJ3F1ZXN0aW9uNCc6ICdhbHdheXMnIH0gKTtcbiAqICAgICAgIGRzLnF1ZXJ5KCcnLHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICpcbiAqIE5vdGUgdGhhdCBpbiBhZGRpdGlvbiB0byB0aGUgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgcm9vdGAsIHRoZSBEYXRhIFNlcnZpY2UgcGFyYW1ldGVycyBvcHRpb25hbGx5IGluY2x1ZGUgYSBgc2VydmVyYCBvYmplY3QsIHdob3NlIGBob3N0YCBmaWVsZCBjb250YWlucyB0aGUgVVJJIG9mIHRoZSBGb3JpbyBzZXJ2ZXIuIFRoaXMgaXMgYXV0b21hdGljYWxseSBzZXQsIGJ1dCB5b3UgY2FuIHBhc3MgaXQgZXhwbGljaXRseSBpZiBkZXNpcmVkLiBJdCBpcyBtb3N0IGNvbW1vbmx5IHVzZWQgZm9yIGNsYXJpdHkgd2hlbiB5b3UgYXJlIFtob3N0aW5nIGFuIEVwaWNlbnRlciBwcm9qZWN0IG9uIHlvdXIgb3duIHNlcnZlcl0oLi4vLi4vLi4vaG93X3RvL3NlbGZfaG9zdGluZy8pLlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBzdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh7IHN5bmNocm9ub3VzOiB0cnVlIH0pO1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogTmFtZSBvZiBjb2xsZWN0aW9uLiBEZWZhdWx0cyB0byBgL2AsIHRoYXQgaXMsIHRoZSByb290IGxldmVsIG9mIHlvdXIgcHJvamVjdCBhdCBgZm9yaW8uY29tL2FwcC95b3VyLWFjY291bnQtaWQveW91ci1wcm9qZWN0LWlkL2AuIFJlcXVpcmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcm9vdDogJy8nLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRm9yIG9wZXJhdGlvbnMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KCdlcGljZW50ZXIucHJvamVjdC50b2tlbicpIHx8ICcnLFxuXG4gICAgICAgIGRvbWFpbjogJ2ZvcmlvLmNvbScsXG5cbiAgICAgICAgLy9PcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBnZXRVUkwgPSBmdW5jdGlvbiAoa2V5LCByb290KSB7XG4gICAgICAgIGlmICghcm9vdCkge1xuICAgICAgICAgICAgcm9vdCA9IHNlcnZpY2VPcHRpb25zLnJvb3Q7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVybCA9IHVybENvbmZpZy5nZXRBUElQYXRoKCdkYXRhJykgKyBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKHJvb3QpO1xuICAgICAgICBpZiAoa2V5KSB7XG4gICAgICAgICAgICB1cmwrPSBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKGtleSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IGdldFVSTFxuICAgIH0pO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNlYXJjaCBmb3IgZGF0YSB3aXRoaW4gYSBjb2xsZWN0aW9uLlxuICAgICAgICAgKlxuICAgICAgICAgKiBTZWFyY2hpbmcgdXNpbmcgY29tcGFyaXNvbiBvciBsb2dpY2FsIG9wZXJhdG9ycyAoYXMgb3Bwb3NlZCB0byBleGFjdCBtYXRjaGVzKSByZXF1aXJlcyBNb25nb0RCIHN5bnRheC4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLyNzZWFyY2hpbmcpIGZvciBhZGRpdGlvbmFsIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRhdGEgYXNzb2NpYXRlZCB3aXRoIGRvY3VtZW50ICd1c2VyMSdcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgndXNlcjEnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBleGFjdCBtYXRjaGluZzpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvbiB3aGVyZSAncXVlc3Rpb24yJyBpcyA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IDl9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBjb21wYXJpc29uIG9wZXJhdG9yczpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjInIGlzIGdyZWF0ZXIgdGhhbiA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIGxvZ2ljYWwgb3BlcmF0b3JzOlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRvY3VtZW50cyBpbiBjb2xsZWN0aW9uXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgJ3F1ZXN0aW9uMicgaXMgbGVzcyB0aGFuIDEwLCBhbmQgJ3F1ZXN0aW9uMycgaXMgZmFsc2VcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgnJywgeyAnJGFuZCc6IFsgeyAncXVlc3Rpb24yJzogeyAnJGx0JzoxMH0gfSwgeyAncXVlc3Rpb24zJzogZmFsc2UgfV0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gcmVndWxhciBleHByZXNzc2lvbnM6IHVzZSBhbnkgUGVybC1jb21wYXRpYmxlIHJlZ3VsYXIgZXhwcmVzc2lvbnNcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjUnIGNvbnRhaW5zIHRoZSBzdHJpbmcgJy4qZGF5J1xuICAgICAgICAgKiAgICAgIGRzLnF1ZXJ5KCcnLCB7ICdxdWVzdGlvbjUnOiB7ICckcmVnZXgnOiAnLipkYXknIH0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBga2V5YCBUaGUgbmFtZSBvZiB0aGUgZG9jdW1lbnQgdG8gc2VhcmNoLiBQYXNzIHRoZSBlbXB0eSBzdHJpbmcgKCcnKSB0byBzZWFyY2ggdGhlIGVudGlyZSBjb2xsZWN0aW9uLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHF1ZXJ5YCBUaGUgcXVlcnkgb2JqZWN0LiBGb3IgZXhhY3QgbWF0Y2hpbmcsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCBmaWVsZCB2YWx1ZSB0byBtYXRjaC4gRm9yIG1hdGNoaW5nIGJhc2VkIG9uIGNvbXBhcmlzb24sIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCB0aGUgY29tcGFyaXNvbiBleHByZXNzaW9uLiBGb3IgbWF0Y2hpbmcgYmFzZWQgb24gbG9naWNhbCBvcGVyYXRvcnMsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIGFuIGV4cHJlc3Npb24gdXNpbmcgTW9uZ29EQiBzeW50YXguIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8jc2VhcmNoaW5nKSBmb3IgYWRkaXRpb25hbCBleGFtcGxlcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKlxuICAgICAgICAgKi9cbiAgICAgICAgcXVlcnk6IGZ1bmN0aW9uIChrZXksIHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgcTogcXVlcnkgfSwgb3V0cHV0TW9kaWZpZXIpO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGRhdGEgdG8gYW4gYW5vbnltb3VzIGRvY3VtZW50IHdpdGhpbiB0aGUgY29sbGVjdGlvbi5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmUoJ3F1ZXN0aW9uMScsICd5ZXMnKTtcbiAgICAgICAgICogICAgICBkcy5zYXZlKHtxdWVzdGlvbjE6J3llcycsIHF1ZXN0aW9uMjogMzIgfSk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZSh7IG5hbWU6J0pvaG4nLCBjbGFzc05hbWU6ICdDUzEwMScgfSwgeyByb290OiAnc3R1ZGVudHMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xPYmplY3R9IGBrZXlgIElmIGBrZXlgIGlzIGEgc3RyaW5nLCBpdCBpcyB0aGUgaWQgb2YgdGhlIGVsZW1lbnQgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJZiBga2V5YCBpcyBhbiBvYmplY3QsIHRoZSBvYmplY3QgaXMgdGhlIGRhdGEgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJbiBib3RoIGNhc2VzLCB0aGUgaWQgZm9yIHRoZSBkb2N1bWVudCBpcyBnZW5lcmF0ZWQgYXV0b21hdGljYWxseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGB2YWx1ZWAgKE9wdGlvbmFsKSBUaGUgZGF0YSB0byBzYXZlLiBJZiBga2V5YCBpcyBhIHN0cmluZywgdGhpcyBpcyB0aGUgdmFsdWUgdG8gc2F2ZS4gSWYgYGtleWAgaXMgYW4gb2JqZWN0LCB0aGUgdmFsdWUocykgdG8gc2F2ZSBhcmUgYWxyZWFkeSBwYXJ0IG9mIGBrZXlgIGFuZCB0aGlzIGFyZ3VtZW50IGlzIG5vdCByZXF1aXJlZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZTogZnVuY3Rpb24gKGtleSwgdmFsdWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBhdHRycztcbiAgICAgICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0ga2V5O1xuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSB2YWx1ZTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoJycsIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KGF0dHJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgZGF0YSB0byBhIG5hbWVkIGRvY3VtZW50IG9yIGVsZW1lbnQgd2l0aGluIHRoZSBjb2xsZWN0aW9uLiBUaGUgYHJvb3RgIG9mIHRoZSBjb2xsZWN0aW9uIG11c3QgYmUgc3BlY2lmaWVkIHNlcGFyYXRlbHkgaW4gY29uZmlndXJhdGlvbiBvcHRpb25zLCBlaXRoZXIgYXMgcGFydCBvZiB0aGUgY2FsbCBvciBhcyBwYXJ0IG9mIHRoZSBpbml0aWFsaXphdGlvbiBvZiBkcy5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmVBcygndXNlcjEnLFxuICAgICAgICAgKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAyLCAncXVlc3Rpb24yJzogMTAsXG4gICAgICAgICAqICAgICAgICAgICAncXVlc3Rpb24zJzogZmFsc2UsICdxdWVzdGlvbjQnOiAnc29tZXRpbWVzJyB9ICk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZUFzKCdzdHVkZW50MScsXG4gICAgICAgICAqICAgICAgICAgIHsgZmlyc3ROYW1lOiAnam9obicsIGxhc3ROYW1lOiAnc21pdGgnIH0sXG4gICAgICAgICAqICAgICAgICAgIHsgcm9vdDogJ3N0dWRlbnRzJyB9KTtcbiAgICAgICAgICogICAgICBkcy5zYXZlQXMoJ21nbXQxMDAvZ3JvdXBCJyxcbiAgICAgICAgICogICAgICAgICAgeyBzY2VuYXJpb1llYXI6ICcyMDE1JyB9LFxuICAgICAgICAgKiAgICAgICAgICB7IHJvb3Q6ICdteWNsYXNzZXMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYGtleWAgSWQgb2YgdGhlIGRvY3VtZW50LlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbHVlYCAoT3B0aW9uYWwpIFRoZSBkYXRhIHRvIHNhdmUsIGluIGtleTp2YWx1ZSBwYWlycy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZUFzOiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wdXQodmFsdWUsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGRhdGEgZm9yIGEgc3BlY2lmaWMgZG9jdW1lbnQgb3IgZmllbGQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgZHMubG9hZCgndXNlcjEnKTtcbiAgICAgICAgICogICAgICBkcy5sb2FkKCd1c2VyMS9xdWVzdGlvbjMnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYGtleWAgVGhlIGlkIG9mIHRoZSBkYXRhIHRvIHJldHVybi4gQ2FuIGJlIHRoZSBpZCBvZiBhIGRvY3VtZW50LCBvciBhIHBhdGggdG8gZGF0YSB3aXRoaW4gdGhhdCBkb2N1bWVudC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uIChrZXksIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMudXJsID0gZ2V0VVJMKGtleSwgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQob3V0cHV0TW9kaWZpZXIsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBkYXRhIGZyb20gY29sbGVjdGlvbi4gT25seSBkb2N1bWVudHMgKHRvcC1sZXZlbCBlbGVtZW50cyBpbiBlYWNoIGNvbGxlY3Rpb24pIGNhbiBiZSBkZWxldGVkLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgZHMucmVtb3ZlKCd1c2VyMScpO1xuICAgICAgICAgKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xBcnJheX0gYGtleXNgIFRoZSBpZCBvZiB0aGUgZG9jdW1lbnQgdG8gcmVtb3ZlIGZyb20gdGhpcyBjb2xsZWN0aW9uLCBvciBhbiBhcnJheSBvZiBzdWNoIGlkcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgcmVtb3ZlOiBmdW5jdGlvbiAoa2V5cywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBwYXJhbXM7XG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KGtleXMpKSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBpZDoga2V5cyB9O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSAnJztcbiAgICAgICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoa2V5cywgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUocGFyYW1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFcGljZW50ZXIgZG9lc24ndCBhbGxvdyBudWtpbmcgY29sbGVjdGlvbnNcbiAgICAgICAgLy8gICAgIC8qKlxuICAgICAgICAvLyAgICAgICogUmVtb3ZlcyBjb2xsZWN0aW9uIGJlaW5nIHJlZmVyZW5jZWRcbiAgICAgICAgLy8gICAgICAqIEByZXR1cm4gbnVsbFxuICAgICAgICAvLyAgICAgICovXG4gICAgICAgIC8vICAgICBkZXN0cm95OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvLyAgICAgICAgIHJldHVybiB0aGlzLnJlbW92ZSgnJywgb3B0aW9ucyk7XG4gICAgICAgIC8vICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKlxuICogIyNNZW1iZXIgQVBJIEFkYXB0ZXJcbiAqXG4gKiBUaGUgTWVtYmVyIEFQSSBBZGFwdGVyIHByb3ZpZGVzIG1ldGhvZHMgdG8gbG9vayB1cCBpbmZvcm1hdGlvbiBhYm91dCBlbmQgdXNlcnMgZm9yIHlvdXIgcHJvamVjdCBhbmQgaG93IHRoZXkgYXJlIGRpdmlkZWQgYWNyb3NzIGdyb3Vwcy4gSXQgaXMgYmFzZWQgb24gcXVlcnkgY2FwYWJpbGl0aWVzIG9mIHRoZSB1bmRlcmx5aW5nIFJFU1RmdWwgW01lbWJlciBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy91c2VyX21hbmFnZW1lbnQvbWVtYmVyLykuXG4gKlxuICogVGhpcyBpcyBvbmx5IG5lZWRlZCBmb3IgQXV0aGVudGljYXRlZCBwcm9qZWN0cywgdGhhdCBpcywgdGVhbSBwcm9qZWN0cyB3aXRoIFtlbmQgdXNlcnMgYW5kIGdyb3Vwc10oLi4vLi4vLi4vZ3JvdXBzX2FuZF9lbmRfdXNlcnMvKS4gRm9yIGV4YW1wbGUsIGlmIHNvbWUgb2YgeW91ciBlbmQgdXNlcnMgYXJlIGZhY2lsaXRhdG9ycywgb3IgaWYgeW91ciBlbmQgdXNlcnMgc2hvdWxkIGJlIHRyZWF0ZWQgZGlmZmVyZW50bHkgYmFzZWQgb24gd2hpY2ggZ3JvdXAgdGhleSBhcmUgaW4sIHVzZSB0aGUgTWVtYmVyIEFQSSB0byBmaW5kIHRoYXQgaW5mb3JtYXRpb24uXG4gKlxuICogICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gKiAgICAgIG1hLmdldEdyb3Vwc0ZvclVzZXIoeyB1c2VySWQ6ICdiNmIzMTNhMy1hYjg0LTQ3OWMtYmFlYS0yMDZmNmJmZjMzNycgfSk7XG4gKiAgICAgIG1hLmdldEdyb3VwRGV0YWlscyh7IGdyb3VwSWQ6ICcwMGI1MzMwOC05ODMzLTQ3ZjItYjIxZS0xMjc4YzA3ZDUzYjgnIH0pO1xuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIGFwaUVuZHBvaW50ID0gJ21lbWJlci9sb2NhbCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciB1c2VyIGlkLiBEZWZhdWx0cyB0byBhIGJsYW5rIHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciBncm91cCBpZC4gRGVmYXVsdHMgdG8gYSBibGFuayBzdHJpbmcuIE5vdGUgdGhhdCB0aGlzIGlzIHRoZSBncm91cCAqaWQqLCBub3QgdGhlIGdyb3VwICpuYW1lKi5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGdyb3VwSWQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucywgc2VydmljZU9wdGlvbnMpO1xuXG4gICAgdmFyIGdldEZpbmFsUGFyYW1zID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICAgICAgICBpZiAodHlwZW9mIHBhcmFtcyA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnM7XG4gICAgfTtcblxuICAgIHZhciBwYXRjaFVzZXJBY3RpdmVGaWVsZCA9IGZ1bmN0aW9uIChwYXJhbXMsIGFjdGl2ZSwgb3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBwYXJhbXMuZ3JvdXBJZCArICcvJyArIHBhcmFtcy51c2VySWRcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goeyBhY3RpdmU6IGFjdGl2ZSB9LCBodHRwT3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBhbGwgb2YgdGhlIGdyb3VwIG1lbWJlcnNoaXBzIGZvciBvbmUgZW5kIHVzZXIuIFRoZSBtZW1iZXJzaGlwIGRldGFpbHMgYXJlIHJldHVybmVkIGluIGFuIGFycmF5LCB3aXRoIG9uZSBlbGVtZW50IChncm91cCByZWNvcmQpIGZvciBlYWNoIGdyb3VwIHRvIHdoaWNoIHRoZSBlbmQgdXNlciBiZWxvbmdzLlxuICAgICAgICAqXG4gICAgICAgICogSW4gdGhlIG1lbWJlcnNoaXAgYXJyYXksIGVhY2ggZ3JvdXAgcmVjb3JkIGluY2x1ZGVzIHRoZSBncm91cCBpZCwgcHJvamVjdCBpZCwgYWNjb3VudCAodGVhbSkgaWQsIGFuZCBhbiBhcnJheSBvZiBtZW1iZXJzLiBIb3dldmVyLCBvbmx5IHRoZSB1c2VyIHdob3NlIHVzZXJJZCBpcyBpbmNsdWRlZCBpbiB0aGUgY2FsbCBpcyBsaXN0ZWQgaW4gdGhlIG1lbWJlcnMgYXJyYXkgKHJlZ2FyZGxlc3Mgb2Ygd2hldGhlciB0aGVyZSBhcmUgb3RoZXIgbWVtYmVycyBpbiB0aGlzIGdyb3VwKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcignNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24obWVtYmVyc2hpcHMpe1xuICAgICAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpPG1lbWJlcnNoaXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2cobWVtYmVyc2hpcHNbaV0uZ3JvdXBJZCk7XG4gICAgICAgICogICAgICAgICAgICAgICB9XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcih7IHVzZXJJZDogJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdH0gYHBhcmFtc2AgVGhlIHVzZXIgaWQgZm9yIHRoZSBlbmQgdXNlci4gQWx0ZXJuYXRpdmVseSwgYW4gb2JqZWN0IHdpdGggZmllbGQgYHVzZXJJZGAgYW5kIHZhbHVlIHRoZSB1c2VyIGlkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXRHcm91cHNGb3JVc2VyOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKHBhcmFtcyk7XG4gICAgICAgICAgICBpZiAoIWlzU3RyaW5nICYmICFvYmpQYXJhbXMudXNlcklkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyB1c2VySWQgc3BlY2lmaWVkLicpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZ2V0UGFybXMgPSBpc1N0cmluZyA/IHsgdXNlcklkOiBwYXJhbXMgfSA6IF9waWNrKG9ialBhcmFtcywgJ3VzZXJJZCcpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGdldFBhcm1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBvbmUgZ3JvdXAsIGluY2x1ZGluZyBhbiBhcnJheSBvZiBhbGwgaXRzIG1lbWJlcnMuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLmdldEdyb3VwRGV0YWlscygnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oZ3JvdXApe1xuICAgICAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpPGdyb3VwLm1lbWJlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhncm91cC5tZW1iZXJzW2ldLnVzZXJOYW1lKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIH1cbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBtYS5nZXRHcm91cERldGFpbHMoeyBncm91cElkOiAnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd8b2JqZWN0fSBgcGFyYW1zYCBUaGUgZ3JvdXAgaWQuIEFsdGVybmF0aXZlbHksIGFuIG9iamVjdCB3aXRoIGZpZWxkIGBncm91cElkYCBhbmQgdmFsdWUgdGhlIGdyb3VwIGlkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0R3JvdXBEZXRhaWxzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKHBhcmFtcyk7XG4gICAgICAgICAgICBpZiAoIWlzU3RyaW5nICYmICFvYmpQYXJhbXMuZ3JvdXBJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gZ3JvdXBJZCBzcGVjaWZpZWQuJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBncm91cElkID0gaXNTdHJpbmcgPyBwYXJhbXMgOiBvYmpQYXJhbXMuZ3JvdXBJZDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIGdyb3VwSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogU2V0IGEgcGFydGljdWxhciBlbmQgdXNlciBhcyBgYWN0aXZlYC4gQWN0aXZlIGVuZCB1c2VycyBjYW4gYmUgYXNzaWduZWQgdG8gW3dvcmxkc10oLi4vd29ybGQtbWFuYWdlci8pIGluIG11bHRpcGxheWVyIGdhbWVzIGR1cmluZyBhdXRvbWF0aWMgYXNzaWdubWVudC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEubWFrZVVzZXJBY3RpdmUoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBUaGUgZW5kIHVzZXIgYW5kIGdyb3VwIGluZm9ybWF0aW9uLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnVzZXJJZGAgVGhlIGlkIG9mIHRoZSBlbmQgdXNlciB0byBtYWtlIGFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5ncm91cElkYCBUaGUgaWQgb2YgdGhlIGdyb3VwIHRvIHdoaWNoIHRoaXMgZW5kIHVzZXIgYmVsb25ncywgYW5kIGluIHdoaWNoIHRoZSBlbmQgdXNlciBzaG91bGQgYmVjb21lIGFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIG1ha2VVc2VyQWN0aXZlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcGF0Y2hVc2VyQWN0aXZlRmllbGQocGFyYW1zLCB0cnVlLCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBTZXQgYSBwYXJ0aWN1bGFyIGVuZCB1c2VyIGFzIGBpbmFjdGl2ZWAuIEluYWN0aXZlIGVuZCB1c2VycyBhcmUgbm90IGFzc2lnbmVkIHRvIFt3b3JsZHNdKC4uL3dvcmxkLW1hbmFnZXIvKSBpbiBtdWx0aXBsYXllciBnYW1lcyBkdXJpbmcgYXV0b21hdGljIGFzc2lnbm1lbnQuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLm1ha2VVc2VySW5hY3RpdmUoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBUaGUgZW5kIHVzZXIgYW5kIGdyb3VwIGluZm9ybWF0aW9uLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnVzZXJJZGAgVGhlIGlkIG9mIHRoZSBlbmQgdXNlciB0byBtYWtlIGluYWN0aXZlLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmdyb3VwSWRgIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggdGhpcyBlbmQgdXNlciBiZWxvbmdzLCBhbmQgaW4gd2hpY2ggdGhlIGVuZCB1c2VyIHNob3VsZCBiZWNvbWUgaW5hY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBtYWtlVXNlckluYWN0aXZlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcGF0Y2hVc2VyQWN0aXZlRmllbGQocGFyYW1zLCBmYWxzZSwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjI1J1biBBUEkgU2VydmljZVxuICpcbiAqIFRoZSBSdW4gQVBJIFNlcnZpY2UgYWxsb3dzIHlvdSB0byBwZXJmb3JtIGNvbW1vbiB0YXNrcyBhcm91bmQgY3JlYXRpbmcgYW5kIHVwZGF0aW5nIHJ1bnMsIHZhcmlhYmxlcywgYW5kIGRhdGEuXG4gKlxuICogV2hlbiBidWlsZGluZyBpbnRlcmZhY2VzIHRvIHNob3cgcnVuIG9uZSBhdCBhIHRpbWUgKGFzIGZvciBzdGFuZGFyZCBlbmQgdXNlcnMpLCB0eXBpY2FsbHkgeW91IGZpcnN0IGluc3RhbnRpYXRlIGEgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGFuZCB0aGVuIGFjY2VzcyB0aGUgUnVuIFNlcnZpY2UgdGhhdCBpcyBhdXRvbWF0aWNhbGx5IHBhcnQgb2YgdGhlIG1hbmFnZXIsIHJhdGhlciB0aGFuIGluc3RhbnRpYXRpbmcgdGhlIFJ1biBTZXJ2aWNlIGRpcmVjdGx5LiBUaGlzIGlzIGJlY2F1c2UgdGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBjb250cm9sIG92ZXIgcnVuIGNyZWF0aW9uIGRlcGVuZGluZyBvbiBydW4gc3RhdGVzLlxuICpcbiAqIEhvd2V2ZXIsIG1hbnkgb2YgdGhlIEVwaWNlbnRlciBzYW1wbGUgcHJvamVjdHMgdXNlIGEgUnVuIFNlcnZpY2UsIGJlY2F1c2UgZ2VuZXJhbGx5IHRoZSBzYW1wbGUgcHJvamVjdHMgYXJlIHBsYXllZCBpbiBvbmUgZW5kIHVzZXIgc2Vzc2lvbiBhbmQgZG9uJ3QgY2FyZSBhYm91dCBydW4gc3RhdGVzIG9yIFtydW4gc3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKS4gVGhlIFJ1biBBUEkgU2VydmljZSBpcyBhbHNvIHVzZWZ1bCBmb3IgYnVpbGRpbmcgYW4gaW50ZXJmYWNlIGZvciBhIGZhY2lsaXRhdG9yLCBiZWNhdXNlIGl0IG1ha2VzIGl0IGVhc3kgdG8gbGlzdCBkYXRhIGFjcm9zcyBtdWx0aXBsZSBydW5zICh1c2luZyB0aGUgYGZpbHRlcigpYCBhbmQgYHF1ZXJ5KClgIG1ldGhvZHMpLlxuICpcbiAqIFRvIHVzZSB0aGUgUnVuIEFQSSBTZXJ2aWNlLCBpbnN0YW50aWF0ZSBpdCBieSBwYXNzaW5nIGluOlxuICpcbiAqICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gKiAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4gKlxuICogRm9yIGV4YW1wbGUsXG4gKlxuICogICAgICAgdmFyIHJzID0gbmV3IEYuc2VydmljZS5SdW4oe1xuICogICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgIH0pO1xuICogICAgICBycy5jcmVhdGUoJ3N1cHBseV9jaGFpbl9nYW1lLnB5JykudGhlbihmdW5jdGlvbihydW4pIHtcbiAqICAgICAgICAgICAgIHJzLmRvKCdzb21lT3BlcmF0aW9uJyk7XG4gKiAgICAgIH0pO1xuICpcbiAqXG4gKiBBZGRpdGlvbmFsbHksIGFsbCBBUEkgY2FsbHMgdGFrZSBpbiBhbiBcIm9wdGlvbnNcIiBvYmplY3QgYXMgdGhlIGxhc3QgcGFyYW1ldGVyLiBUaGUgb3B0aW9ucyBjYW4gYmUgdXNlZCB0byBleHRlbmQvb3ZlcnJpZGUgdGhlIFJ1biBBUEkgU2VydmljZSBkZWZhdWx0cyBsaXN0ZWQgYmVsb3cuXG4gKlxuICogTm90ZSB0aGF0IGluIGFkZGl0aW9uIHRvIHRoZSBgYWNjb3VudGAsIGBwcm9qZWN0YCwgYW5kIGBtb2RlbGAsIHRoZSBSdW4gU2VydmljZSBwYXJhbWV0ZXJzIG9wdGlvbmFsbHkgaW5jbHVkZSBhIGBzZXJ2ZXJgIG9iamVjdCwgd2hvc2UgYGhvc3RgIGZpZWxkIGNvbnRhaW5zIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4gKlxuICogICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiAqICAgICAgICAgICBydW46IHtcbiAqICAgICAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgICAgICBtb2RlbDogJ3N1cHBseV9jaGFpbl9nYW1lLnB5JyxcbiAqICAgICAgICAgICAgICAgc2VydmVyOiB7IGhvc3Q6ICdhcGkuZm9yaW8uY29tJyB9XG4gKiAgICAgICAgICAgfVxuICogICAgICAgfSk7XG4gKiAgICAgICBybS5nZXRSdW4oKVxuICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1bikge1xuICogICAgICAgICAgICAgICAvLyB0aGUgUnVuTWFuYWdlci5ydW4gY29udGFpbnMgdGhlIGluc3RhbnRpYXRlZCBSdW4gU2VydmljZSxcbiAqICAgICAgICAgICAgICAgLy8gc28gYW55IFJ1biBTZXJ2aWNlIG1ldGhvZCBpcyB2YWxpZCBoZXJlXG4gKiAgICAgICAgICAgICAgIHZhciBycyA9IHJtLnJ1bjtcbiAqICAgICAgICAgICAgICAgcnMuZG8oJ3NvbWVPcGVyYXRpb24nKTtcbiAqICAgICAgIH0pXG4gKlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgcnV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3J1bi11dGlsJyk7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgVmFyaWFibGVzU2VydmljZSA9IHJlcXVpcmUoJy4vdmFyaWFibGVzLWFwaS1zZXJ2aWNlJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIC8vIGNvbmZpZyB8fCAoY29uZmlnID0gY29uZmlnU2VydmljZS5nZXQoKSk7XG4gICAgdmFyIHN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHsgc3luY2hyb25vdXM6IHRydWUgfSk7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KCdlcGljZW50ZXIucHJvamVjdC50b2tlbicpIHx8IHN0b3JlLmdldCgnZXBpY2VudGVyLnRva2VuJykgfHwgJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDcml0ZXJpYSBieSB3aGljaCB0byBmaWx0ZXIgcnVucy4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZmlsdGVyOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVuaWVuY2UgYWxpYXMgZm9yIGZpbHRlci5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGlkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRmxhZyBkZXRlcm1pbmVzIGlmIGBYLUF1dG9SZXN0b3JlOiB0cnVlYCBoZWFkZXIgaXMgc2VudCB0byBFcGljZW50ZXIuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBhdXRvUmVzdG9yZTogdHJ1ZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgY29tcGxldGVzIHN1Y2Nlc3NmdWxseS4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIHN1Y2Nlc3M6ICQubm9vcCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgZmFpbHMuIERlZmF1bHRzIHRvIGAkLm5vb3BgLlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICBlcnJvcjogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgdXJsQ29uZmlnLmFjY291bnRQYXRoID0gc2VydmljZU9wdGlvbnMuYWNjb3VudDtcbiAgICB9XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgdXJsQ29uZmlnLnByb2plY3RQYXRoID0gc2VydmljZU9wdGlvbnMucHJvamVjdDtcbiAgICB9XG5cbiAgICB1cmxDb25maWcuZmlsdGVyID0gJzsnO1xuICAgIHVybENvbmZpZy5nZXRGaWx0ZXJVUkwgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJyk7XG4gICAgICAgIHZhciBmaWx0ZXIgPSBxdXRpbC50b01hdHJpeEZvcm1hdChzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpO1xuXG4gICAgICAgIGlmIChmaWx0ZXIpIHtcbiAgICAgICAgICAgIHVybCArPSBmaWx0ZXIgKyAnLyc7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGZpbHRlciA9IHNlcnZpY2VPcHRpb25zLmZpbHRlcjtcbiAgICAgICAgLy8gVGhlIHNlbWljb2xvbiBzZXBhcmF0ZWQgZmlsdGVyIGlzIHVzZWQgd2hlbiBmaWx0ZXIgaXMgYW4gb2JqZWN0XG4gICAgICAgIHZhciBpc0ZpbHRlclJ1bklkID0gZmlsdGVyICYmICQudHlwZShmaWx0ZXIpID09PSAnc3RyaW5nJztcbiAgICAgICAgaWYgKHNlcnZpY2VPcHRpb25zLmF1dG9SZXN0b3JlICYmIGlzRmlsdGVyUnVuSWQpIHtcbiAgICAgICAgICAgIC8vIEJ5IGRlZmF1bHQgYXV0b3JlcGxheSB0aGUgcnVuIGJ5IHNlbmRpbmcgdGhpcyBoZWFkZXIgdG8gZXBpY2VudGVyXG4gICAgICAgICAgICAvLyBodHRwczovL2ZvcmlvLmNvbS9lcGljZW50ZXIvZG9jcy9wdWJsaWMvcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNyZXRyaWV2aW5nXG4gICAgICAgICAgICB2YXIgYXV0b3Jlc3RvcmVPcHRzID0ge1xuICAgICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICAgICAgJ1gtQXV0b1Jlc3RvcmUnOiB0cnVlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCBhdXRvcmVzdG9yZU9wdHMsIG9wdGlvbnMpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG9wdGlvbnM7XG4gICAgfTtcblxuICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0RmlsdGVyVVJMXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG4gICAgaHR0cC5zcGxpdEdldCA9IHJ1dGlsLnNwbGl0R2V0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgc2V0RmlsdGVyT3JUaHJvd0Vycm9yID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMuaWQpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IG9wdGlvbnMuaWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmZpbHRlcjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBmaWx0ZXIgc3BlY2lmaWVkIHRvIGFwcGx5IG9wZXJhdGlvbnMgYWdhaW5zdCcpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBc3luY0FQSSA9IHtcbiAgICAgICAgdXJsQ29uZmlnOiB1cmxDb25maWcsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENyZWF0ZSBhIG5ldyBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqIE5PVEU6IFR5cGljYWxseSB0aGlzIGlzIG5vdCB1c2VkISBVc2UgYFJ1bk1hbmFnZXIuZ2V0UnVuKClgIHdpdGggYSBgc3RyYXRlZ3lgIG9mIGBhbHdheXMtbmV3YCwgb3IgdXNlIGBSdW5NYW5hZ2VyLnJlc2V0KClgLiBTZWUgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGZvciBtb3JlIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHJzLmNyZWF0ZSgnaGVsbG9fd29ybGQuamwnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYHBhcmFtc2AgSWYgYSBzdHJpbmcsIHRoZSBuYW1lIG9mIHRoZSBwcmltYXJ5IFttb2RlbCBmaWxlXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4gVGhpcyBpcyB0aGUgb25lIGZpbGUgaW4gdGhlIHByb2plY3QgdGhhdCBleHBsaWNpdGx5IGV4cG9zZXMgdmFyaWFibGVzIGFuZCBtZXRob2RzLCBhbmQgaXQgbXVzdCBiZSBzdG9yZWQgaW4gdGhlIE1vZGVsIGZvbGRlciBvZiB5b3VyIEVwaWNlbnRlciBwcm9qZWN0LiBJZiBhbiBvYmplY3QsIG1heSBpbmNsdWRlIGBtb2RlbGAsIGBzY29wZWAsIGFuZCBgZmlsZXNgLiAoU2VlIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bl9tYW5hZ2VyLykgZm9yIG1vcmUgaW5mb3JtYXRpb24gb24gYHNjb3BlYCBhbmQgYGZpbGVzYC4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICpcbiAgICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJykgfSk7XG4gICAgICAgICAgICB2YXIgcnVuQXBpUGFyYW1zID0gWydtb2RlbCcsICdzY29wZScsICdmaWxlcyddO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgLy8gdGhpcyBpcyBqdXN0IHRoZSBtb2RlbCBuYW1lXG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBtb2RlbDogcGFyYW1zIH07XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIHdoaXRlbGlzdCB0aGUgZmllbGRzIHRoYXQgd2UgYWN0dWFsbHkgY2FuIHNlbmQgdG8gdGhlIGFwaVxuICAgICAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgcnVuQXBpUGFyYW1zKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBjcmVhdGVPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgICAgICBjcmVhdGVPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSByZXNwb25zZS5pZDsgLy9hbGwgZnV0dXJlIGNoYWluZWQgY2FsbHMgdG8gb3BlcmF0ZSBvbiB0aGlzIGlkXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHJ1bnMsIGJhc2VkIG9uIGNvbmRpdGlvbnMgc3BlY2lmaWVkIGluIHRoZSBgcXNgIG9iamVjdC5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGVsZW1lbnRzIG9mIHRoZSBgcXNgIG9iamVjdCBhcmUgQU5EZWQgdG9nZXRoZXIgd2l0aGluIGEgc2luZ2xlIGNhbGwgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyByZXR1cm5zIHJ1bnMgd2l0aCBzYXZlZCA9IHRydWUgYW5kIHZhcmlhYmxlcy5wcmljZSA+IDEsXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgdmFyaWFibGVzLnByaWNlIGhhcyBiZWVuIHBlcnNpc3RlZCAocmVjb3JkZWQpXG4gICAgICAgICAqICAgICAgLy8gaW4gdGhlIG1vZGVsLlxuICAgICAgICAgKiAgICAgcnMucXVlcnkoe1xuICAgICAgICAgKiAgICAgICAgICAnc2F2ZWQnOiAndHJ1ZScsXG4gICAgICAgICAqICAgICAgICAgICcucHJpY2UnOiAnPjEnXG4gICAgICAgICAqICAgICAgIH0sXG4gICAgICAgICAqICAgICAgIHtcbiAgICAgICAgICogICAgICAgICAgc3RhcnRyZWNvcmQ6IDIsXG4gICAgICAgICAqICAgICAgICAgIGVuZHJlY29yZDogNVxuICAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBxc2AgUXVlcnkgb2JqZWN0LiBFYWNoIGtleSBjYW4gYmUgYSBwcm9wZXJ0eSBvZiB0aGUgcnVuIG9yIHRoZSBuYW1lIG9mIHZhcmlhYmxlIHRoYXQgaGFzIGJlZW4gc2F2ZWQgaW4gdGhlIHJ1biAocHJlZmFjZWQgYnkgYHZhcmlhYmxlcy5gKS4gRWFjaCB2YWx1ZSBjYW4gYmUgYSBsaXRlcmFsIHZhbHVlLCBvciBhIGNvbXBhcmlzb24gb3BlcmF0b3IgYW5kIHZhbHVlLiAoU2VlIFttb3JlIG9uIGZpbHRlcmluZ10oLi4vLi4vLi4vcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNmaWx0ZXJzKSBhbGxvd2VkIGluIHRoZSB1bmRlcmx5aW5nIFJ1biBBUEkuKSBRdWVyeWluZyBmb3IgdmFyaWFibGVzIGlzIGF2YWlsYWJsZSBmb3IgcnVucyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBhbmQgZm9yIHJ1bnMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgaWYgdGhlIHZhcmlhYmxlcyBhcmUgcGVyc2lzdGVkIChlLmcuIHRoYXQgaGF2ZSBiZWVuIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHF1ZXJ5OiBmdW5jdGlvbiAocXMsIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBxczsgLy9zaG91bGRuJ3QgYmUgYWJsZSB0byBvdmVyLXJpZGVcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucyA9IHVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlcihodHRwT3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJldHVybnMgcGFydGljdWxhciBydW5zLCBiYXNlZCBvbiBjb25kaXRpb25zIHNwZWNpZmllZCBpbiB0aGUgYHFzYCBvYmplY3QuXG4gICAgICAgICAqXG4gICAgICAgICAqIFNpbWlsYXIgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBmaWx0ZXJgIEZpbHRlciBvYmplY3QuIEVhY2gga2V5IGNhbiBiZSBhIHByb3BlcnR5IG9mIHRoZSBydW4gb3IgdGhlIG5hbWUgb2YgdmFyaWFibGUgdGhhdCBoYXMgYmVlbiBzYXZlZCBpbiB0aGUgcnVuIChwcmVmYWNlZCBieSBgdmFyaWFibGVzLmApLiBFYWNoIHZhbHVlIGNhbiBiZSBhIGxpdGVyYWwgdmFsdWUsIG9yIGEgY29tcGFyaXNvbiBvcGVyYXRvciBhbmQgdmFsdWUuIChTZWUgW21vcmUgb24gZmlsdGVyaW5nXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkvI2ZpbHRlcnMpIGFsbG93ZWQgaW4gdGhlIHVuZGVybHlpbmcgUnVuIEFQSS4pIEZpbHRlcmluZyBmb3IgdmFyaWFibGVzIGlzIGF2YWlsYWJsZSBmb3IgcnVucyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBhbmQgZm9yIHJ1bnMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgaWYgdGhlIHZhcmlhYmxlcyBhcmUgcGVyc2lzdGVkIChlLmcuIHRoYXQgaGF2ZSBiZWVuIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogZnVuY3Rpb24gKGZpbHRlciwgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qoc2VydmljZU9wdGlvbnMuZmlsdGVyKSkge1xuICAgICAgICAgICAgICAgICQuZXh0ZW5kKHNlcnZpY2VPcHRpb25zLmZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gZmlsdGVyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBkYXRhIGZvciBhIHNwZWNpZmljIHJ1bi4gVGhpcyBpbmNsdWRlcyBzdGFuZGFyZCBydW4gZGF0YSBzdWNoIGFzIHRoZSBhY2NvdW50LCBtb2RlbCwgcHJvamVjdCwgYW5kIGNyZWF0ZWQgYW5kIGxhc3QgbW9kaWZpZWQgZGF0ZXMuIFRvIHJlcXVlc3Qgc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLCBwYXNzIHRoZW0gYXMgcGFydCBvZiB0aGUgYGZpbHRlcnNgIHBhcmFtZXRlci5cbiAgICAgICAgICpcbiAgICAgICAgICogTm90ZSB0aGF0IGlmIHRoZSBydW4gaXMgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSksIGFueSBtb2RlbCB2YXJpYWJsZXMgYXJlIGF2YWlsYWJsZTsgaWYgdGhlIHJ1biBpcyBbaW4gdGhlIGRhdGFiYXNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tZGIpLCBvbmx5IG1vZGVsIHZhcmlhYmxlcyB0aGF0IGhhdmUgYmVlbiBwZXJzaXN0ZWQgJm1kYXNoOyB0aGF0IGlzLCBgcmVjb3JkYGVkIGluIHlvdXIgSnVsaWEgbW9kZWwgJm1kYXNoOyBhcmUgYXZhaWxhYmxlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgcnMubG9hZCgnYmI1ODk2NzctZDQ3Ni00OTcxLWE2OGUtMGM1OGQxOTFlNDUwJywgeyBpbmNsdWRlOiBbJy5wcmljZScsICcuc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGBydW5JRGAgVGhlIHJ1biBpZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBmaWx0ZXJzYCAoT3B0aW9uYWwpIE9iamVjdCBjb250YWluaW5nIGZpbHRlcnMgYW5kIG9wZXJhdGlvbiBtb2RpZmllcnMuIFVzZSBrZXkgYGluY2x1ZGVgIHRvIGxpc3QgbW9kZWwgdmFyaWFibGVzIHRoYXQgeW91IHdhbnQgdG8gaW5jbHVkZSBpbiB0aGUgcmVzcG9uc2UuIE90aGVyIGF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAocnVuSUQsIGZpbHRlcnMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmIChydW5JRCkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHJ1bklEOyAvL3Nob3VsZG4ndCBiZSBhYmxlIHRvIG92ZXItcmlkZVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cblxuICAgICAgICAvKipcbiAgICAgICAgICogU2F2ZSBhdHRyaWJ1dGVzIChkYXRhLCBtb2RlbCB2YXJpYWJsZXMpIG9mIHRoZSBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgLy8gYWRkICdjb21wbGV0ZWQnIGZpZWxkIHRvIHJ1biByZWNvcmRcbiAgICAgICAgICogICAgIHJzLnNhdmUoeyBjb21wbGV0ZWQ6IHRydWUgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAvLyB1cGRhdGUgJ3NhdmVkJyBmaWVsZCBvZiBydW4gcmVjb3JkLCBhbmQgdXBkYXRlIHZhbHVlcyBvZiBtb2RlbCB2YXJpYWJsZXMgZm9yIHRoaXMgcnVuXG4gICAgICAgICAqICAgICBycy5zYXZlKHsgc2F2ZWQ6IHRydWUsIHZhcmlhYmxlczogeyBhOiAyMywgYjogMjMgfSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBhdHRyaWJ1dGVzYCBUaGUgcnVuIGRhdGEgYW5kIHZhcmlhYmxlcyB0byBzYXZlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYGF0dHJpYnV0ZXMudmFyaWFibGVzYCBNb2RlbCB2YXJpYWJsZXMgbXVzdCBiZSBpbmNsdWRlZCBpbiBhIGB2YXJpYWJsZXNgIGZpZWxkIHdpdGhpbiB0aGUgYGF0dHJpYnV0ZXNgIG9iamVjdC4gKE90aGVyd2lzZSB0aGV5IGFyZSB0cmVhdGVkIGFzIHJ1biBkYXRhIGFuZCBhZGRlZCB0byB0aGUgcnVuIHJlY29yZCBkaXJlY3RseS4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uIChhdHRyaWJ1dGVzLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgc2V0RmlsdGVyT3JUaHJvd0Vycm9yKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKGF0dHJpYnV0ZXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBhIG1ldGhvZCBmcm9tIHRoZSBtb2RlbC5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2QgbWF5IG5lZWQgdG8gYmUgZXhwb3NlZCAoZS5nLiBgZXhwb3J0YCBmb3IgYSBKdWxpYSBtb2RlbCkgaW4gdGhlIG1vZGVsIGZpbGUgaW4gb3JkZXIgdG8gYmUgY2FsbGVkIHRocm91Z2ggdGhlIEFQSS4gU2VlIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pKS5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGBwYXJhbXNgIGFyZ3VtZW50IGlzIG5vcm1hbGx5IGFuIGFycmF5IG9mIGFyZ3VtZW50cyB0byB0aGUgYG9wZXJhdGlvbmAuIEluIHRoZSBzcGVjaWFsIGNhc2Ugd2hlcmUgYG9wZXJhdGlvbmAgb25seSB0YWtlcyBvbmUgYXJndW1lbnQsIHlvdSBhcmUgbm90IHJlcXVpcmVkIHRvIHB1dCB0aGF0IGFyZ3VtZW50IGludG8gYW4gYXJyYXkuXG4gICAgICAgICAqXG4gICAgICAgICAqIE5vdGUgdGhhdCB5b3UgY2FuIGNvbWJpbmUgdGhlIGBvcGVyYXRpb25gIGFuZCBgcGFyYW1zYCBhcmd1bWVudHMgaW50byBhIHNpbmdsZSBvYmplY3QgaWYgeW91IHByZWZlciwgYXMgaW4gdGhlIGxhc3QgZXhhbXBsZS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlcyoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwic29sdmVcIiB0YWtlcyBubyBhcmd1bWVudHNcbiAgICAgICAgICogICAgIHJzLmRvKCdzb2x2ZScpO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImVjaG9cIiB0YWtlcyBvbmUgYXJndW1lbnQsIGEgc3RyaW5nXG4gICAgICAgICAqICAgICBycy5kbygnZWNobycsIFsnaGVsbG8nXSk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwiZWNob1wiIHRha2VzIG9uZSBhcmd1bWVudCwgYSBzdHJpbmdcbiAgICAgICAgICogICAgIHJzLmRvKCdlY2hvJywgJ2hlbGxvJyk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwic3VtQXJyYXlcIiB0YWtlcyBvbmUgYXJndW1lbnQsIGFuIGFycmF5XG4gICAgICAgICAqICAgICBycy5kbygnc3VtQXJyYXknLCBbWzQsMiwxXV0pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImFkZFwiIHRha2VzIHR3byBhcmd1bWVudHMsIGJvdGggaW50ZWdlcnNcbiAgICAgICAgICogICAgIHJzLmRvKHsgbmFtZTonYWRkJywgcGFyYW1zOlsyLDRdIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYG9wZXJhdGlvbmAgTmFtZSBvZiBtZXRob2QuXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGBwYXJhbXNgIChPcHRpb25hbCkgQW55IHBhcmFtZXRlcnMgdGhlIG9wZXJhdGlvbiB0YWtlcywgcGFzc2VkIGFzIGFuIGFycmF5LiBJbiB0aGUgc3BlY2lhbCBjYXNlIHdoZXJlIGBvcGVyYXRpb25gIG9ubHkgdGFrZXMgb25lIGFyZ3VtZW50LCB5b3UgYXJlIG5vdCByZXF1aXJlZCB0byBwdXQgdGhhdCBhcmd1bWVudCBpbnRvIGFuIGFycmF5LCBhbmQgY2FuIGp1c3QgcGFzcyBpdCBkaXJlY3RseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgZG86IGZ1bmN0aW9uIChvcGVyYXRpb24sIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coJ2RvJywgb3BlcmF0aW9uLCBwYXJhbXMpO1xuICAgICAgICAgICAgdmFyIG9wc0FyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnM7XG4gICAgICAgICAgICBpZiAob3B0aW9ucykge1xuICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMgPSBvcHRpb25zO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHBhcmFtcykpIHtcbiAgICAgICAgICAgICAgICAgICAgb3BzQXJncyA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zID0gcGFyYW1zO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9uLCBvcHNBcmdzKTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgcG9zdE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBzZXRGaWx0ZXJPclRocm93RXJyb3IoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcHJtcyA9IChyZXN1bHQuYXJnc1swXS5sZW5ndGggJiYgKHJlc3VsdC5hcmdzWzBdICE9PSBudWxsICYmIHJlc3VsdC5hcmdzWzBdICE9PSB1bmRlZmluZWQpKSA/IHJlc3VsdC5hcmdzWzBdIDogW107XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHsgYXJndW1lbnRzOiBwcm1zIH0sICQuZXh0ZW5kKHRydWUsIHt9LCBodHRwT3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ29wZXJhdGlvbnMvJyArIHJlc3VsdC5vcHNbMF0gKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBzZXZlcmFsIG1ldGhvZHMgZnJvbSB0aGUgbW9kZWwsIHNlcXVlbnRpYWxseS5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2RzIG1heSBuZWVkIHRvIGJlIGV4cG9zZWQgKGUuZy4gYGV4cG9ydGAgZm9yIGEgSnVsaWEgbW9kZWwpIGluIHRoZSBtb2RlbCBmaWxlIGluIG9yZGVyIHRvIGJlIGNhbGxlZCB0aHJvdWdoIHRoZSBBUEkuIFNlZSBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKSkuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJpbml0aWFsaXplXCIgYW5kIFwic29sdmVcIiBkbyBub3QgdGFrZSBhbnkgYXJndW1lbnRzXG4gICAgICAgICAqICAgICBycy5zZXJpYWwoWydpbml0aWFsaXplJywgJ3NvbHZlJ10pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJpbml0XCIgYW5kIFwicmVzZXRcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMuc2VyaWFsKFsgIHsgbmFtZTogJ2luaXQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgeyBuYW1lOiAncmVzZXQnLCBwYXJhbXM6IFsyLDNdIH1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJpbml0XCIgdGFrZXMgdHdvIGFyZ3VtZW50cyxcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJydW5tb2RlbFwiIHRha2VzIG5vbmVcbiAgICAgICAgICogICAgIHJzLnNlcmlhbChbICB7IG5hbWU6ICdpbml0JywgcGFyYW1zOiBbMSwyXSB9LFxuICAgICAgICAgKiAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3J1bm1vZGVsJywgcGFyYW1zOiBbXSB9XSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGBvcGVyYXRpb25zYCBJZiBub25lIG9mIHRoZSBtZXRob2RzIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiB0aGUgbWV0aG9kIG5hbWVzIChzdHJpbmdzKS4gSWYgYW55IG9mIHRoZSBtZXRob2RzIGRvIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiBvYmplY3RzLCBlYWNoIG9mIHdoaWNoIGNvbnRhaW5zIGEgbWV0aG9kIG5hbWUgYW5kIGl0cyBvd24gKHBvc3NpYmx5IGVtcHR5KSBhcnJheSBvZiBwYXJhbWV0ZXJzLlxuICAgICAgICAgKiBAcGFyYW0geyp9IGBwYXJhbXNgIFBhcmFtZXRlcnMgdG8gcGFzcyB0byBvcGVyYXRpb25zLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBzZXJpYWw6IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBvcFBhcmFtcyA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHMgPSBvcFBhcmFtcy5vcHM7XG4gICAgICAgICAgICB2YXIgYXJncyA9IG9wUGFyYW1zLmFyZ3M7XG4gICAgICAgICAgICB2YXIgbWUgPSB0aGlzO1xuXG4gICAgICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZG9TaW5nbGVPcCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB2YXIgb3AgPSBvcHMuc2hpZnQoKTtcbiAgICAgICAgICAgICAgICB2YXIgYXJnID0gYXJncy5zaGlmdCgpO1xuXG4gICAgICAgICAgICAgICAgbWUuZG8ob3AsIGFyZywge1xuICAgICAgICAgICAgICAgICAgICBzdWNjZXNzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAob3BzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvU2luZ2xlT3AoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zLnN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICRkLnJlamVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuZXJyb3IuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgZG9TaW5nbGVPcCgpO1xuXG4gICAgICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsIHNldmVyYWwgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbCwgZXhlY3V0aW5nIHRoZW0gaW4gcGFyYWxsZWwuXG4gICAgICAgICAqXG4gICAgICAgICAqIERlcGVuZGluZyBvbiB0aGUgbGFuZ3VhZ2UgaW4gd2hpY2ggeW91IGhhdmUgd3JpdHRlbiB5b3VyIG1vZGVsLCB0aGUgbWV0aG9kcyBtYXkgbmVlZCB0byBiZSBleHBvc2VkIChlLmcuIGBleHBvcnRgIGZvciBhIEp1bGlhIG1vZGVsKSBpbiB0aGUgbW9kZWwgZmlsZSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdGhyb3VnaCB0aGUgQVBJLiBTZWUgW1dyaXRpbmcgeW91ciBNb2RlbF0oLi4vLi4vLi4vd3JpdGluZ195b3VyX21vZGVsLykpLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJzb2x2ZVwiIGFuZCBcInJlc2V0XCIgZG8gbm90IHRha2UgYW55IGFyZ3VtZW50c1xuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoWydzb2x2ZScsICdyZXNldCddKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiYWRkXCIgYW5kIFwic3VidHJhY3RcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoWyB7IG5hbWU6ICdhZGQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3N1YnRyYWN0JywgcGFyYW1zOlsyLDNdIH1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiYWRkXCIgYW5kIFwic3VidHJhY3RcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoeyBhZGQ6IFsxLDJdLCBzdWJ0cmFjdDogWzIsNF0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fSBgb3BlcmF0aW9uc2AgSWYgbm9uZSBvZiB0aGUgbWV0aG9kcyB0YWtlIHBhcmFtZXRlcnMsIHBhc3MgYW4gYXJyYXkgb2YgdGhlIG1ldGhvZCBuYW1lcyAoYXMgc3RyaW5ncykuIElmIGFueSBvZiB0aGUgbWV0aG9kcyBkbyB0YWtlIHBhcmFtZXRlcnMsIHlvdSBoYXZlIHR3byBvcHRpb25zLiBZb3UgY2FuIHBhc3MgYW4gYXJyYXkgb2Ygb2JqZWN0cywgZWFjaCBvZiB3aGljaCBjb250YWlucyBhIG1ldGhvZCBuYW1lIGFuZCBpdHMgb3duIChwb3NzaWJseSBlbXB0eSkgYXJyYXkgb2YgcGFyYW1ldGVycy4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBwYXNzIGEgc2luZ2xlIG9iamVjdCB3aXRoIHRoZSBtZXRob2QgbmFtZSBhbmQgYSAocG9zc2libHkgZW1wdHkpIGFycmF5IG9mIHBhcmFtZXRlcnMuXG4gICAgICAgICAqIEBwYXJhbSB7Kn0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBwYXNzIHRvIG9wZXJhdGlvbnMuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHBhcmFsbGVsOiBmdW5jdGlvbiAob3BlcmF0aW9ucywgcGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG5cbiAgICAgICAgICAgIHZhciBvcFBhcmFtcyA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHMgPSBvcFBhcmFtcy5vcHM7XG4gICAgICAgICAgICB2YXIgYXJncyA9IG9wUGFyYW1zLmFyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcXVldWUgID0gW107XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaTwgb3BzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgcXVldWUucHVzaChcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kbyhvcHNbaV0sIGFyZ3NbaV0pXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgICQud2hlbi5hcHBseSh0aGlzLCBxdWV1ZSlcbiAgICAgICAgICAgICAgICAuZG9uZShmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlc29sdmUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuc3VjY2Vzcy5hcHBseSh0aGlzLmFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZmFpbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlamVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucy5lcnJvci5hcHBseSh0aGlzLmFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY1N5bmNBUEkgPSB7XG4gICAgICAgIGdldEN1cnJlbnRDb25maWc6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucztcbiAgICAgICAgfSxcbiAgICAgICAgLyoqXG4gICAgICAgICAgKiBSZXR1cm5zIGEgVmFyaWFibGVzIFNlcnZpY2UgaW5zdGFuY2UuIFVzZSB0aGUgdmFyaWFibGVzIGluc3RhbmNlIHRvIGxvYWQsIHNhdmUsIGFuZCBxdWVyeSBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLiBTZWUgdGhlIFtWYXJpYWJsZSBBUEkgU2VydmljZV0oLi4vdmFyaWFibGVzLWFwaS1zZXJ2aWNlLykgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG4gICAgICAgICAgKlxuICAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAgICAgIHZhciB2cyA9IHJzLnZhcmlhYmxlcygpO1xuICAgICAgICAgICogICAgICB2cy5zYXZlKHsgc2FtcGxlX2ludDogNCB9KTtcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBjb25maWdgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAgKi9cbiAgICAgICAgdmFyaWFibGVzOiBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICAgICAgICB2YXIgdnMgPSBuZXcgVmFyaWFibGVzU2VydmljZSgkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIGNvbmZpZywge1xuICAgICAgICAgICAgICAgIHJ1blNlcnZpY2U6IHRoaXNcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgIHJldHVybiB2cztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBc3luY0FQSSk7XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljU3luY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4gKiAjI1N0YXRlIEFQSSBBZGFwdGVyXG4gKlxuICogVGhlIFN0YXRlIEFQSSBBZGFwdGVyIGFsbG93cyB5b3UgdG8gcmVwbGF5IG9yIGNsb25lIHJ1bnMuIEl0IGJyaW5ncyBleGlzdGluZywgcGVyc2lzdGVkIHJ1biBkYXRhIGZyb20gdGhlIGRhdGFiYXNlIGJhY2sgaW50byBtZW1vcnksIHVzaW5nIHRoZSBzYW1lIHJ1biBpZCAoYHJlcGxheWApIG9yIGEgbmV3IHJ1biBpZCAoYGNsb25lYCkuIFJ1bnMgbXVzdCBiZSBpbiBtZW1vcnkgaW4gb3JkZXIgZm9yIHlvdSB0byB1cGRhdGUgdmFyaWFibGVzIG9yIGNhbGwgb3BlcmF0aW9ucyBvbiB0aGVtLlxuICpcbiAqIFNwZWNpZmljYWxseSwgdGhlIFN0YXRlIEFQSSBBZGFwdGVyIHdvcmtzIGJ5IFwicmUtcnVubmluZ1wiIHRoZSBydW4gKHVzZXIgaW50ZXJhY3Rpb25zKSBmcm9tIHRoZSBjcmVhdGlvbiBvZiB0aGUgcnVuIHVwIHRvIHRoZSB0aW1lIGl0IHdhcyBsYXN0IHBlcnNpc3RlZCBpbiB0aGUgZGF0YWJhc2UuIFRoaXMgcHJvY2VzcyB1c2VzIHRoZSBjdXJyZW50IHZlcnNpb24gb2YgdGhlIHJ1bidzIG1vZGVsLiBUaGVyZWZvcmUsIGlmIHRoZSBtb2RlbCBoYXMgY2hhbmdlZCBzaW5jZSB0aGUgb3JpZ2luYWwgcnVuIHdhcyBjcmVhdGVkLCB0aGUgcmV0cmlldmVkIHJ1biB3aWxsIHVzZSB0aGUgbmV3IG1vZGVsIOKAlCBhbmQgbWF5IGVuZCB1cCBoYXZpbmcgZGlmZmVyZW50IHZhbHVlcyBvciBiZWhhdmlvciBhcyBhIHJlc3VsdC4gVXNlIHdpdGggY2FyZSFcbiAqXG4gKiBUbyB1c2UgdGhlIFN0YXRlIEFQSSBBZGFwdGVyLCBpbnN0YW50aWF0ZSBpdCBhbmQgdGhlbiBjYWxsIGl0cyBtZXRob2RzOlxuICpcbiAqICAgICAgdmFyIHNhID0gbmV3IEYuc2VydmljZS5TdGF0ZSgpO1xuICogICAgICBzYS5yZXBsYXkoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJ30pO1xuICpcbiAqIFRoZSBjb25zdHJ1Y3RvciB0YWtlcyBhbiBvcHRpb25hbCBgb3B0aW9uc2AgcGFyYW1ldGVyIGluIHdoaWNoIHlvdSBjYW4gc3BlY2lmeSB0aGUgYGFjY291bnRgIGFuZCBgcHJvamVjdGAgaWYgdGhleSBhcmUgbm90IGFscmVhZHkgYXZhaWxhYmxlIGluIHRoZSBjdXJyZW50IGNvbnRleHQuXG4gKlxuICovXG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBhcGlFbmRwb2ludCA9ICdtb2RlbC9zdGF0ZSc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgfTtcblxuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcbiAgICB2YXIgcGFyc2VSdW5JZE9yRXJyb3IgPSBmdW5jdGlvbiAocGFyYW1zKSB7XG4gICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3QocGFyYW1zKSAmJiBwYXJhbXMucnVuSWQpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXJhbXMucnVuSWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwYXNzIGluIGEgcnVuIGlkJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICogUmVwbGF5IGEgcnVuLiBBZnRlciB0aGlzIGNhbGwsIHRoZSBydW4sIHdpdGggaXRzIG9yaWdpbmFsIHJ1biBpZCwgaXMgbm93IGF2YWlsYWJsZSBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KS4gKEl0IGNvbnRpbnVlcyB0byBiZSBwZXJzaXN0ZWQgaW50byB0aGUgRXBpY2VudGVyIGRhdGFiYXNlIGF0IHJlZ3VsYXIgaW50ZXJ2YWxzLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gICAgICAgICogICAgICBzYS5yZXBsYXkoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJywgc3RvcEJlZm9yZTogJ2NhbGN1bGF0ZVNjb3JlJ30pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFBhcmFtZXRlcnMgb2JqZWN0LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnJ1bklkYCBUaGUgaWQgb2YgdGhlIHJ1biB0byBicmluZyBiYWNrIHRvIG1lbW9yeS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5zdG9wQmVmb3JlYCAoT3B0aW9uYWwpIFRoZSBydW4gaXMgYWR2YW5jZWQgb25seSB1cCB0byB0aGUgZmlyc3Qgb2NjdXJyZW5jZSBvZiB0aGlzIG1ldGhvZC5cbiAgICAgICAgKiBAcGFyYW0ge2FycmF5fSBgcGFyYW1zLmV4Y2x1ZGVgIChPcHRpb25hbCkgQXJyYXkgb2YgbWV0aG9kcyB0byBleGNsdWRlIHdoZW4gYWR2YW5jaW5nIHRoZSBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICByZXBsYXk6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBydW5JZCA9IHBhcnNlUnVuSWRPckVycm9yKHBhcmFtcyk7XG5cbiAgICAgICAgICAgIHZhciByZXBsYXlPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcnVuSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gJC5leHRlbmQodHJ1ZSwgeyBhY3Rpb246ICdyZXBsYXknIH0sIF9waWNrKHBhcmFtcywgWydzdG9wQmVmb3JlJywgJ2V4Y2x1ZGUnXSkpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgcmVwbGF5T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ2xvbmUgYSBnaXZlbiBydW4gYW5kIHJldHVybiBhIG5ldyBydW4gaW4gdGhlIHNhbWUgc3RhdGUgYXMgdGhlIGdpdmVuIHJ1bi5cbiAgICAgICAgKlxuICAgICAgICAqIFRoZSBuZXcgcnVuIGlkIGlzIG5vdyBhdmFpbGFibGUgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkuIFRoZSBuZXcgcnVuIGluY2x1ZGVzIGEgY29weSBvZiBhbGwgb2YgdGhlIGRhdGEgZnJvbSB0aGUgb3JpZ2luYWwgcnVuLCBFWENFUFQ6XG4gICAgICAgICpcbiAgICAgICAgKiAqIFRoZSBgc2F2ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyBub3QgY29waWVkIGZyb20gdGhlIG9yaWdpbmFsIHJ1biByZWNvcmQuIEl0IGRlZmF1bHRzIHRvIGBmYWxzZWAuXG4gICAgICAgICogKiBUaGUgYGluaXRpYWxpemVkYCBmaWVsZCBpbiB0aGUgbmV3IHJ1biByZWNvcmQgaXMgbm90IGNvcGllZCBmcm9tIHRoZSBvcmlnaW5hbCBydW4gcmVjb3JkLiBJdCBkZWZhdWx0cyB0byBgZmFsc2VgIGJ1dCBtYXkgY2hhbmdlIHRvIGB0cnVlYCBhcyB0aGUgbmV3IHJ1biBpcyBhZHZhbmNlZC4gRm9yIGV4YW1wbGUsIGlmIHRoZXJlIGhhcyBiZWVuIGEgY2FsbCB0byB0aGUgYHN0ZXBgIGZ1bmN0aW9uIChmb3IgVmVuc2ltIG1vZGVscyksIHRoZSBgaW5pdGlhbGl6ZWRgIGZpZWxkIGlzIHNldCB0byBgdHJ1ZWAuXG4gICAgICAgICogKiBUaGUgYGNyZWF0ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyB0aGUgZGF0ZSBhbmQgdGltZSBhdCB3aGljaCB0aGUgY2xvbmUgd2FzIGNyZWF0ZWQgKG5vdCB0aGUgdGltZSB0aGF0IHRoZSBvcmlnaW5hbCBydW4gd2FzIGNyZWF0ZWQuKVxuICAgICAgICAqXG4gICAgICAgICogVGhlIG9yaWdpbmFsIHJ1biByZW1haW5zIG9ubHkgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLWRiKS5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gICAgICAgICogICAgICBzYS5jbG9uZSh7cnVuSWQ6ICcxODQyYmI1Yy04M2FkLTRiYTgtYTk1NS1iZDEzY2MyZmRiNGYnLCBzdG9wQmVmb3JlOiAnY2FsY3VsYXRlU2NvcmUnLCBleGNsdWRlOiBbJ2ludGVyaW1DYWxjdWxhdGlvbiddIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFBhcmFtZXRlcnMgb2JqZWN0LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnJ1bklkYCBUaGUgaWQgb2YgdGhlIHJ1biB0byBjbG9uZSBmcm9tIG1lbW9yeS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5zdG9wQmVmb3JlYCAoT3B0aW9uYWwpIFRoZSBuZXdseSBjbG9uZWQgcnVuIGlzIGFkdmFuY2VkIG9ubHkgdXAgdG8gdGhlIGZpcnN0IG9jY3VycmVuY2Ugb2YgdGhpcyBtZXRob2QuXG4gICAgICAgICogQHBhcmFtIHthcnJheX0gYHBhcmFtcy5leGNsdWRlYCAoT3B0aW9uYWwpIEFycmF5IG9mIG1ldGhvZHMgdG8gZXhjbHVkZSB3aGVuIGFkdmFuY2luZyB0aGUgbmV3bHkgY2xvbmVkIHJ1bi5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGNsb25lOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcnVuSWQgPSBwYXJzZVJ1bklkT3JFcnJvcihwYXJhbXMpO1xuXG4gICAgICAgICAgICB2YXIgcmVwbGF5T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHJ1bklkIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgYWN0aW9uOiAnY2xvbmUnIH0sIF9waWNrKHBhcmFtcywgWydzdG9wQmVmb3JlJywgJ2V4Y2x1ZGUnXSkpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgcmVwbGF5T3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBlcGlWZXJzaW9uID0gcmVxdWlyZSgnLi4vYXBpLXZlcnNpb24uanNvbicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAvL1RPRE86IHVybHV0aWxzIHRvIGdldCBob3N0LCBzaW5jZSBubyB3aW5kb3cgb24gbm9kZVxuXG4gICAgdmFyIEFQSV9QUk9UT0NPTCA9ICdodHRwcyc7XG4gICAgdmFyIEhPU1RfQVBJX01BUFBJTkcgPSB7XG4gICAgICAgICdmb3Jpby5jb20nOiAnYXBpLmZvcmlvLmNvbScsXG4gICAgICAgICdmb3Jpb2Rldi5jb20nOiAnYXBpLmVwaWNlbnRlci5mb3Jpb2Rldi5jb20nXG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNFeHBvcnRzID0ge1xuICAgICAgICBwcm90b2NvbDogQVBJX1BST1RPQ09MLFxuXG4gICAgICAgIGFwaTogJycsXG5cbiAgICAgICAgaG9zdDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBob3N0ID0gd2luZG93LmxvY2F0aW9uLmhvc3Q7XG4gICAgICAgICAgICBpZiAoIWhvc3QgfHwgaG9zdC5pbmRleE9mKCdsb2NhbCcpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIGhvc3QgPSAnZm9yaW8uY29tJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAoSE9TVF9BUElfTUFQUElOR1tob3N0XSkgPyBIT1NUX0FQSV9NQVBQSU5HW2hvc3RdIDogJ2FwaS4nICsgaG9zdDtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBhcHBQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHBhdGggPSB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUuc3BsaXQoJ1xcLycpO1xuXG4gICAgICAgICAgICByZXR1cm4gcGF0aCAmJiBwYXRoWzFdIHx8ICcnO1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIGFjY291bnRQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFjY250ID0gJyc7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZS5zcGxpdCgnXFwvJyk7XG4gICAgICAgICAgICBpZiAocGF0aCAmJiBwYXRoWzFdID09PSAnYXBwJykge1xuICAgICAgICAgICAgICAgIGFjY250ID0gcGF0aFsyXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhY2NudDtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBwcm9qZWN0UGF0aDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBwcmogPSAnJztcbiAgICAgICAgICAgIHZhciBwYXRoID0gd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLnNwbGl0KCdcXC8nKTtcbiAgICAgICAgICAgIGlmIChwYXRoICYmIHBhdGhbMV0gPT09ICdhcHAnKSB7XG4gICAgICAgICAgICAgICAgcHJqID0gcGF0aFszXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBwcmo7XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgdmVyc2lvblBhdGg6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgdmVyc2lvbiA9IGVwaVZlcnNpb24udmVyc2lvbiA/IGVwaVZlcnNpb24udmVyc2lvbiArICcvJyA6ICcnO1xuICAgICAgICAgICAgcmV0dXJuIHZlcnNpb247XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgaXNMb2NhbGhvc3Q6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBob3N0ID0gd2luZG93LmxvY2F0aW9uLmhvc3Q7XG4gICAgICAgICAgICByZXR1cm4gKCFob3N0IHx8IGhvc3QuaW5kZXhPZignbG9jYWwnKSAhPT0gLTEpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGdldEFQSVBhdGg6IGZ1bmN0aW9uIChhcGkpIHtcbiAgICAgICAgICAgIHZhciBQUk9KRUNUX0FQSVMgPSBbJ3J1bicsICdkYXRhJywgJ2ZpbGUnXTtcblxuICAgICAgICAgICAgdmFyIGFwaVBhdGggPSB0aGlzLnByb3RvY29sICsgJzovLycgKyB0aGlzLmhvc3QgKyAnLycgKyB0aGlzLnZlcnNpb25QYXRoICsgYXBpICsgJy8nO1xuXG4gICAgICAgICAgICBpZiAoJC5pbkFycmF5KGFwaSwgUFJPSkVDVF9BUElTKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICBhcGlQYXRoICs9IHRoaXMuYWNjb3VudFBhdGggKyAnLycgKyB0aGlzLnByb2plY3RQYXRoICArICcvJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhcGlQYXRoO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHB1YmxpY0V4cG9ydHMsIGNvbmZpZyk7XG4gICAgcmV0dXJuIHB1YmxpY0V4cG9ydHM7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4qICMjVXNlciBBUEkgQWRhcHRlclxuKlxuKiBUaGUgVXNlciBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHJldHJpZXZlIGRldGFpbHMgYWJvdXQgZW5kIHVzZXJzIGluIHlvdXIgdGVhbSAoYWNjb3VudCkuIEl0IGlzIGJhc2VkIG9uIHRoZSBxdWVyeWluZyBjYXBhYmlsaXRpZXMgb2YgdGhlIHVuZGVybHlpbmcgUkVTVGZ1bCBbVXNlciBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy91c2VyX21hbmFnZW1lbnQvdXNlci8pLlxuKlxuKiBUbyB1c2UgdGhlIFVzZXIgQVBJIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGNhbGwgaXRzIG1ldGhvZHMuXG4qXG4qICAgICAgIHZhciB1YSA9IG5ldyBGLnNlcnZpY2UuVXNlcih7XG4qICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgICB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nXG4qICAgICAgIH0pO1xuKiAgICAgICB1YS5nZXRCeUlkKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKTtcbiogICAgICAgdWEuZ2V0KHsgdXNlck5hbWU6ICdqc21pdGgnIH0pO1xuKiAgICAgICB1YS5nZXQoeyBpZDogWyc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuKiAgICAgICAgICAgICAgICAgICAnNGVhNzU2MzEtNGM4ZC00ODcyLTlkODAtYjQ2MDAxNDY0NzhlJ10gfSk7XG4qXG4qIFRoZSBjb25zdHJ1Y3RvciB0YWtlcyBhbiBvcHRpb25hbCBgb3B0aW9uc2AgcGFyYW1ldGVyIGluIHdoaWNoIHlvdSBjYW4gc3BlY2lmeSB0aGUgYGFjY291bnRgIGFuZCBgdG9rZW5gIGlmIHRoZXkgYXJlIG5vdCBhbHJlYWR5IGF2YWlsYWJsZSBpbiB0aGUgY3VycmVudCBjb250ZXh0LlxuKi9cblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2Nlc3MgdG9rZW4gdG8gdXNlIHdoZW4gc2VhcmNoaW5nIGZvciBlbmQgdXNlcnMuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgdG9rZW46ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgcGFydGljdWxhciBlbmQgdXNlcnMgaW4geW91ciB0ZWFtLCBiYXNlZCBvbiB1c2VyIG5hbWUgb3IgdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXQoeyB1c2VyTmFtZTogJ2pzbWl0aCcgfSk7XG4gICAgICAgICogICAgICAgdWEuZ2V0KHsgaWQ6IFsnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAnNGVhNzU2MzEtNGM4ZC00ODcyLTlkODAtYjQ2MDAxNDY0NzhlJ10gfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgZmlsdGVyYCBPYmplY3Qgd2l0aCBmaWVsZCBgdXNlck5hbWVgIGFuZCB2YWx1ZSBvZiB0aGUgdXNlcm5hbWUuIEFsdGVybmF0aXZlbHksIG9iamVjdCB3aXRoIGZpZWxkIGBpZGAgYW5kIHZhbHVlIG9mIGFuIGFycmF5IG9mIHVzZXIgaWRzLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChmaWx0ZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICAgICAgZmlsdGVyID0gZmlsdGVyIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnNcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciB0b1FGaWx0ZXIgPSBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJlcyA9IHt9O1xuXG4gICAgICAgICAgICAgICAgLy8gQVBJIG9ubHkgc3VwcG9ydHMgZmlsdGVyaW5nIGJ5IHVzZXJuYW1lIGZvciBub3dcbiAgICAgICAgICAgICAgICBpZiAoZmlsdGVyLnVzZXJOYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlcy5xID0gZmlsdGVyLnVzZXJOYW1lO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgdG9JZEZpbHRlcnMgPSBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZCA9ICQuaXNBcnJheShpZCkgPyBpZCA6IFtpZF07XG4gICAgICAgICAgICAgICAgcmV0dXJuICdpZD0nICsgaWQuam9pbignJmlkPScpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIGdldEZpbHRlcnMgPSBbXG4gICAgICAgICAgICAgICAgJ2FjY291bnQ9JyArIGdldE9wdGlvbnMuYWNjb3VudCxcbiAgICAgICAgICAgICAgICB0b0lkRmlsdGVycyhmaWx0ZXIuaWQpLFxuICAgICAgICAgICAgICAgIHF1dGlsLnRvUXVlcnlGb3JtYXQodG9RRmlsdGVyKGZpbHRlcikpXG4gICAgICAgICAgICBdLmpvaW4oJyYnKTtcblxuICAgICAgICAgICAgLy8gc3BlY2lhbCBjYXNlIGZvciBxdWVyaWVzIHdpdGggbGFyZ2UgbnVtYmVyIG9mIGlkc1xuICAgICAgICAgICAgLy8gbWFrZSBpdCBhcyBhIHBvc3Qgd2l0aCBHRVQgc2VtYW50aWNzXG4gICAgICAgICAgICB2YXIgdGhyZXNob2xkID0gMzA7XG4gICAgICAgICAgICBpZiAoZmlsdGVyLmlkICYmICQuaXNBcnJheShmaWx0ZXIuaWQpICYmIGZpbHRlci5pZC5sZW5ndGggPj0gdGhyZXNob2xkKSB7XG4gICAgICAgICAgICAgICAgZ2V0T3B0aW9ucy51cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpICsgJz9fbWV0aG9kPUdFVCc7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdCh7IGlkOiBmaWx0ZXIuaWQgfSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChnZXRGaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXRyaWV2ZSBkZXRhaWxzIGFib3V0IGEgc2luZ2xlIGVuZCB1c2VyIGluIHlvdXIgdGVhbSwgYmFzZWQgb24gdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXRCeUlkKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSB1c2VyIGlkIGZvciB0aGUgZW5kIHVzZXIgaW4geW91ciB0ZWFtLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXRCeUlkOiBmdW5jdGlvbiAodXNlcklkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcHVibGljQVBJLmdldCh7IGlkOiB1c2VySWQgfSwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG5cblxuXG5cbiIsIi8qKlxuICpcbiAqICMjVmFyaWFibGVzIEFQSSBTZXJ2aWNlXG4gKlxuICogVXNlZCBpbiBjb25qdW5jdGlvbiB3aXRoIHRoZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSB0byByZWFkLCB3cml0ZSwgYW5kIHNlYXJjaCBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLlxuICpcbiAqICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuICogICAgICAgICAgIHJ1bjoge1xuICogICAgICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5LWNoYWluLW1vZGVsLmpsJ1xuICogICAgICAgICAgIH1cbiAqICAgICAgfSk7XG4gKiAgICAgcm0uZ2V0UnVuKClcbiAqICAgICAgIC50aGVuKGZ1bmN0aW9uKCkge1xuICogICAgICAgICAgdmFyIHZzID0gcm0ucnVuLnZhcmlhYmxlcygpO1xuICogICAgICAgICAgdnMuc2F2ZSh7c2FtcGxlX2ludDogNH0pO1xuICogICAgICAgIH0pO1xuICpcbiAqL1xuXG5cbiAndXNlIHN0cmljdCc7XG5cbiB2YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG4gdmFyIHJ1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9ydW4tdXRpbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcnVucyBvYmplY3QgdG8gd2hpY2ggdGhlIHZhcmlhYmxlIGZpbHRlcnMgYXBwbHkuIERlZmF1bHRzIHRvIG51bGwuXG4gICAgICAgICAqIEB0eXBlIHtydW5TZXJ2aWNlfVxuICAgICAgICAgKi9cbiAgICAgICAgcnVuU2VydmljZTogbnVsbFxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIGdldFVSTCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zLnJ1blNlcnZpY2UudXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ3ZhcmlhYmxlcy8nO1xuICAgIH07XG5cbiAgICB2YXIgYWRkQXV0b1Jlc3RvcmVIZWFkZXIgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnMucnVuU2VydmljZS51cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIob3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBodHRwT3B0aW9ucyA9IHtcbiAgICAgICAgdXJsOiBnZXRVUkxcbiAgICB9O1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcbiAgICBodHRwLnNwbGl0R2V0ID0gcnV0aWwuc3BsaXRHZXRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCB2YWx1ZXMgZm9yIGEgdmFyaWFibGUuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMubG9hZCgnc2FtcGxlX2ludCcpXG4gICAgICAgICAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHZhbCl7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgY29udGFpbnMgdGhlIHZhbHVlIG9mIHNhbXBsZV9pbnRcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgdmFyaWFibGVgIE5hbWUgb2YgdmFyaWFibGUgdG8gbG9hZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9hZDogZnVuY3Rpb24gKHZhcmlhYmxlLCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KG91dHB1dE1vZGlmaWVyLCAkLmV4dGVuZCh7fSwgaHR0cE9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IGdldFVSTCgpICsgdmFyaWFibGUgKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHZhcmlhYmxlcywgYmFzZWQgb24gY29uZGl0aW9ucyBzcGVjaWZpZWQgaW4gdGhlIGBxdWVyeWAgb2JqZWN0LlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHZzLnF1ZXJ5KFsncHJpY2UnLCAnc2FsZXMnXSlcbiAgICAgICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24odmFsKSB7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgaXMgYW4gb2JqZWN0IHdpdGggdGhlIHZhbHVlcyBvZiB0aGUgcmVxdWVzdGVkIHZhcmlhYmxlczogdmFsLnByaWNlLCB2YWwuc2FsZXNcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMucXVlcnkoeyBpbmNsdWRlOlsncHJpY2UnLCAnc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8QXJyYXl9IGBxdWVyeWAgVGhlIG5hbWVzIG9mIHRoZSB2YXJpYWJsZXMgcmVxdWVzdGVkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG91dHB1dE1vZGlmaWVyYCAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqXG4gICAgICAgICAqL1xuICAgICAgICBxdWVyeTogZnVuY3Rpb24gKHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgLy9RdWVyeSBhbmQgb3V0cHV0TW9kaWZpZXIgYXJlIGJvdGggcXVlcnlzdHJpbmdzIGluIHRoZSB1cmw7IG9ubHkgY2FsbGluZyB0aGVtIG91dCBzZXBhcmF0ZWx5IGhlcmUgdG8gYmUgY29uc2lzdGVudCB3aXRoIHRoZSBvdGhlciBjYWxsc1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KHF1ZXJ5KSkge1xuICAgICAgICAgICAgICAgIHF1ZXJ5ID0geyBpbmNsdWRlOiBxdWVyeSB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgJC5leHRlbmQocXVlcnksIG91dHB1dE1vZGlmaWVyKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KHF1ZXJ5LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgdmFsdWVzIHRvIG1vZGVsIHZhcmlhYmxlcy4gT3ZlcndyaXRlcyBleGlzdGluZyB2YWx1ZXMuIE5vdGUgdGhhdCB5b3UgY2FuIG9ubHkgdXBkYXRlIG1vZGVsIHZhcmlhYmxlcyBpZiB0aGUgcnVuIGlzIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLiAoQW4gYWx0ZXJuYXRlIHdheSB0byB1cGRhdGUgbW9kZWwgdmFyaWFibGVzIGlzIHRvIGNhbGwgYSBtZXRob2QgZnJvbSB0aGUgbW9kZWwgYW5kIG1ha2Ugc3VyZSB0aGF0IHRoZSBtZXRob2QgcGVyc2lzdHMgdGhlIHZhcmlhYmxlcy4gU2VlIGBkb2AsIGBzZXJpYWxgLCBhbmQgYHBhcmFsbGVsYCBpbiB0aGUgW1J1biBBUEkgU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykgZm9yIGNhbGxpbmcgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbC4pXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMuc2F2ZSgncHJpY2UnLCA0KTtcbiAgICAgICAgICogICAgICB2cy5zYXZlKHsgcHJpY2U6IDQsIHF1YW50aXR5OiA1LCBwcm9kdWN0czogWzIsMyw0XSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgdmFyaWFibGVgIEFuIG9iamVjdCBjb21wb3NlZCBvZiB0aGUgbW9kZWwgdmFyaWFibGVzIGFuZCB0aGUgdmFsdWVzIHRvIHNhdmUuIEFsdGVybmF0aXZlbHksIGEgc3RyaW5nIHdpdGggdGhlIG5hbWUgb2YgdGhlIHZhcmlhYmxlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbGAgKE9wdGlvbmFsKSBJZiBwYXNzaW5nIGEgc3RyaW5nIGZvciBgdmFyaWFibGVgLCB1c2UgdGhpcyBhcmd1bWVudCBmb3IgdGhlIHZhbHVlIHRvIHNhdmUuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uICh2YXJpYWJsZSwgdmFsLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHZhcmlhYmxlID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHZhbDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW3ZhcmlhYmxlXSA9IHZhbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoLmNhbGwodGhpcywgYXR0cnMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIE5vdCBBdmFpbGFibGUgdW50aWwgdW5kZXJseWluZyBBUEkgc3VwcG9ydHMgUFVULiBPdGhlcndpc2Ugc2F2ZSB3b3VsZCBiZSBQVVQgYW5kIG1lcmdlIHdvdWxkIGJlIFBBVENIXG4gICAgICAgIC8vICpcbiAgICAgICAgLy8gICogU2F2ZSB2YWx1ZXMgdG8gdGhlIGFwaS4gTWVyZ2VzIGFycmF5cywgYnV0IG90aGVyd2lzZSBzYW1lIGFzIHNhdmVcbiAgICAgICAgLy8gICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSB2YXJpYWJsZSBPYmplY3Qgd2l0aCBhdHRyaWJ1dGVzLCBvciBzdHJpbmcga2V5XG4gICAgICAgIC8vICAqIEBwYXJhbSB7T2JqZWN0fSB2YWwgT3B0aW9uYWwgaWYgcHJldiBwYXJhbWV0ZXIgd2FzIGEgc3RyaW5nLCBzZXQgdmFsdWUgaGVyZVxuICAgICAgICAvLyAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xuICAgICAgICAvLyAgKlxuICAgICAgICAvLyAgKiBAZXhhbXBsZVxuICAgICAgICAvLyAgKiAgICAgdnMubWVyZ2UoeyBwcmljZTogNCwgcXVhbnRpdHk6IDUsIHByb2R1Y3RzOiBbMiwzLDRdIH0pXG4gICAgICAgIC8vICAqICAgICB2cy5tZXJnZSgncHJpY2UnLCA0KTtcblxuICAgICAgICAvLyBtZXJnZTogZnVuY3Rpb24gKHZhcmlhYmxlLCB2YWwsIG9wdGlvbnMpIHtcbiAgICAgICAgLy8gICAgIHZhciBhdHRycztcbiAgICAgICAgLy8gICAgIGlmICh0eXBlb2YgdmFyaWFibGUgPT09ICdvYmplY3QnKSB7XG4gICAgICAgIC8vICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgIC8vICAgICAgIG9wdGlvbnMgPSB2YWw7XG4gICAgICAgIC8vICAgICB9IGVsc2Uge1xuICAgICAgICAvLyAgICAgICAoYXR0cnMgPSB7fSlbdmFyaWFibGVdID0gdmFsO1xuICAgICAgICAvLyAgICAgfVxuICAgICAgICAvLyAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAvLyAgICAgcmV0dXJuIGh0dHAucGF0Y2guY2FsbCh0aGlzLCBhdHRycywgaHR0cE9wdGlvbnMpO1xuICAgICAgICAvLyB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICogIyNXb3JsZCBBUEkgQWRhcHRlclxuICpcbiAqIEEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsIC0tIGluY2x1ZGluZyBzZXR0aW5nIHZhcmlhYmxlcywgbWFraW5nIGRlY2lzaW9ucywgYW5kIGNhbGxpbmcgb3BlcmF0aW9ucy4gRm9yIGJ1aWxkaW5nIG11bHRpcGxheWVyIHNpbXVsYXRpb25zIHlvdSB0eXBpY2FsbHkgd2FudCBtdWx0aXBsZSBlbmQgdXNlcnMgdG8gc2hhcmUgdGhlIHNhbWUgc2V0IG9mIGludGVyYWN0aW9ucywgYW5kIHdvcmsgd2l0aGluIGEgY29tbW9uIHN0YXRlLiBFcGljZW50ZXIgYWxsb3dzIHlvdSB0byBjcmVhdGUgXCJ3b3JsZHNcIiB0byBoYW5kbGUgc3VjaCBjYXNlcy4gT25seSBbdGVhbSBwcm9qZWN0c10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIGNhbiBiZSBtdWx0aXBsYXllci5cbiAqXG4gKiBUaGUgV29ybGQgQVBJIEFkYXB0ZXIgYWxsb3dzIHlvdSB0byBjcmVhdGUsIGFjY2VzcywgYW5kIG1hbmlwdWxhdGUgbXVsdGlwbGF5ZXIgd29ybGRzIHdpdGhpbiB5b3VyIEVwaWNlbnRlciBwcm9qZWN0LiBZb3UgY2FuIHVzZSB0aGlzIHRvIGFkZCBhbmQgcmVtb3ZlIGVuZCB1c2VycyBmcm9tIHRoZSB3b3JsZCwgYW5kIHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgcmVtb3ZlIHRoZWlyIHJ1bnMuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4gKFRoZSByZWxhdGVkIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyLykgcHJvdmlkZXMgYW4gZWFzeSB3YXkgdG8gYWNjZXNzIHJ1bnMgYW5kIHdvcmxkcyBmb3IgcGFydGljdWxhciBlbmQgdXNlcnMsIHNvIGlzIHR5cGljYWxseSB1c2VkIGluIHBhZ2VzIHRoYXQgZW5kIHVzZXJzIHdpbGwgaW50ZXJhY3Qgd2l0aC4pXG4gKlxuICogQXMgd2l0aCBhbGwgdGhlIG90aGVyIFtBUEkgQWRhcHRlcnNdKC4uLy4uLyksIGFsbCBtZXRob2RzIHRha2UgaW4gYW4gXCJvcHRpb25zXCIgb2JqZWN0IGFzIHRoZSBsYXN0IHBhcmFtZXRlci4gVGhlIG9wdGlvbnMgY2FuIGJlIHVzZWQgdG8gZXh0ZW5kL292ZXJyaWRlIHRoZSBXb3JsZCBBUEkgU2VydmljZSBkZWZhdWx0cy5cbiAqXG4gKiBUbyB1c2UgdGhlIFdvcmxkIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSksIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKSwgYW5kIGdyb3VwICgqKkdyb3VwIE5hbWUqKikuXG4gKlxuICogICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gKiAgICAgICB3YS5jcmVhdGUoKVxuICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAqICAgICAgICAgICAgICAvLyBjYWxsIG1ldGhvZHMsIGUuZy4gd2EuYWRkVXNlcnMoKVxuICogICAgICAgICAgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG4vLyB2YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcblxudmFyIGFwaUJhc2UgPSAnbXVsdGlwbGF5ZXIvJztcbnZhciBhc3NpZ25tZW50RW5kcG9pbnQgPSBhcGlCYXNlICsgJ2Fzc2lnbic7XG52YXIgYXBpRW5kcG9pbnQgPSBhcGlCYXNlICsgJ3dvcmxkJztcbnZhciBwcm9qZWN0RW5kcG9pbnQgPSBhcGlCYXNlICsgJ3Byb2plY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkoeyBzeW5jaHJvbm91czogdHJ1ZSB9KTtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgdG9rZW46IHN0b3JlLmdldCgnZXBpY2VudGVyLnByb2plY3QudG9rZW4nKSB8fCAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGdyb3VwIG5hbWUuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgZ3JvdXA6IHVuZGVmaW5lZCxcblxuICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbW9kZWwgZmlsZSB0byB1c2UgdG8gY3JlYXRlIHJ1bnMgaW4gdGhpcyB3b3JsZC4gRGVmYXVsdHMgdG8gdW5kZWZpbmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgbW9kZWw6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ3JpdGVyaWEgYnkgd2hpY2ggdG8gZmlsdGVyIHdvcmxkLiBDdXJyZW50bHkgb25seSBzdXBwb3J0cyB3b3JsZC1pZHMgYXMgZmlsdGVycy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlbmllbmNlIGFsaWFzIGZvciBmaWx0ZXJcbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGlkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBjb21wbGV0ZXMgc3VjY2Vzc2Z1bGx5LiBEZWZhdWx0cyB0byBgJC5ub29wYC5cbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgc3VjY2VzczogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBmYWlscy4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIGVycm9yOiAkLm5vb3BcbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMucHJvamVjdCA9IHVybENvbmZpZy5wcm9qZWN0UGF0aDtcbiAgICB9XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBzZXRJZEZpbHRlck9yVGhyb3dFcnJvciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGlmIChvcHRpb25zLmlkKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmlkO1xuICAgICAgICB9XG4gICAgICAgIGlmIChvcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gb3B0aW9ucy5maWx0ZXI7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gd29ybGQgaWQgc3BlY2lmaWVkIHRvIGFwcGx5IG9wZXJhdGlvbnMgYWdhaW5zdC4gVGhpcyBjb3VsZCBoYXBwZW4gaWYgdGhlIHVzZXIgaXMgbm90IGFzc2lnbmVkIHRvIGEgd29ybGQgYW5kIGlzIHRyeWluZyB0byB3b3JrIHdpdGggcnVucyBmcm9tIHRoYXQgd29ybGQuJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICBpZiAoIW9wdGlvbnMubW9kZWwpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gbW9kZWwgc3BlY2lmaWVkIHRvIGdldCB0aGUgY3VycmVudCBydW4nKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIENyZWF0ZXMgYSBuZXcgV29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBVc2luZyB0aGlzIG1ldGhvZCBpcyByYXJlLiBJdCBpcyBtb3JlIGNvbW1vbiB0byBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkgd2hpbGUgeW91IGBhdXRvQXNzaWduKClgIGVuZCB1c2VycyB0byB3b3JsZHMuIChJbiB0aGlzIGNhc2UsIGNvbmZpZ3VyYXRpb24gZGF0YSBmb3IgdGhlIHdvcmxkLCBzdWNoIGFzIHRoZSByb2xlcywgYXJlIHJlYWQgZnJvbSB0aGUgcHJvamVjdC1sZXZlbCB3b3JsZCBjb25maWd1cmF0aW9uIGluZm9ybWF0aW9uLCBmb3IgZXhhbXBsZSBieSBgZ2V0UHJvamVjdFNldHRpbmdzKClgLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSh7XG4gICAgICAgICogICAgICAgICAgIHJvbGVzOiBbJ1ZQIE1hcmtldGluZycsICdWUCBTYWxlcycsICdWUCBFbmdpbmVlcmluZyddXG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBjcmVhdGUgdGhlIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmdyb3VwYCAoT3B0aW9uYWwpIFRoZSAqKkdyb3VwIE5hbWUqKiB0byBjcmVhdGUgdGhpcyB3b3JsZCB1bmRlci4gT25seSBlbmQgdXNlcnMgaW4gdGhpcyBncm91cCBhcmUgZWxpZ2libGUgdG8gam9pbiB0aGUgd29ybGQuIE9wdGlvbmFsIGhlcmU7IHJlcXVpcmVkIHdoZW4gaW5zdGFudGlhdGluZyB0aGUgc2VydmljZSAoYG5ldyBGLnNlcnZpY2UuV29ybGQoKWApLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zLnJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbXVzdCoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIHJvbGVzIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMub3B0aW9uYWxSb2xlc2AgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gYHBhcmFtcy5taW5Vc2Vyc2AgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgfSk7XG4gICAgICAgICAgICB2YXIgd29ybGRBcGlQYXJhbXMgPSBbJ3Njb3BlJywgJ2ZpbGVzJywgJ3JvbGVzJywgJ29wdGlvbmFsUm9sZXMnLCAnbWluVXNlcnMnLCAnZ3JvdXAnLCAnbmFtZSddO1xuICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIHdvcmxkQXBpUGFyYW1zKTtcblxuICAgICAgICAgICAgLy8gYWNjb3VudCBhbmQgcHJvamVjdCBnbyBpbiB0aGUgYm9keSwgbm90IGluIHRoZSB1cmxcbiAgICAgICAgICAgICQuZXh0ZW5kKHBhcmFtcywgX3BpY2soc2VydmljZU9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pKTtcblxuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBjcmVhdGVPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgICAgICBjcmVhdGVPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSByZXNwb25zZS5pZDsgLy9hbGwgZnV0dXJlIGNoYWluZWQgY2FsbHMgdG8gb3BlcmF0ZSBvbiB0aGlzIGlkXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBVcGRhdGVzIGEgV29ybGQsIGZvciBleGFtcGxlIHRvIHJlcGxhY2UgdGhlIHJvbGVzIGluIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgeW91IGNvbXBsZXRlIHdvcmxkIGNvbmZpZ3VyYXRpb24gYXQgdGhlIHByb2plY3QgbGV2ZWwsIHJhdGhlciB0aGFuIGF0IHRoZSB3b3JsZCBsZXZlbC4gRm9yIGV4YW1wbGUsIGVhY2ggd29ybGQgaW4geW91ciBwcm9qZWN0IHByb2JhYmx5IGhhcyB0aGUgc2FtZSByb2xlcyBmb3IgZW5kIHVzZXJzLiBBbmQgeW91ciBwcm9qZWN0IGlzIHByb2JhYmx5IGVpdGhlciBjb25maWd1cmVkIHNvIHRoYXQgYWxsIGVuZCB1c2VycyBzaGFyZSB0aGUgc2FtZSB3b3JsZCAoYW5kIHJ1biksIG9yIHNtYWxsZXIgc2V0cyBvZiBlbmQgdXNlcnMgc2hhcmUgd29ybGRzIOKAlCBidXQgbm90IGJvdGguIEhvd2V2ZXIsIHRoaXMgbWV0aG9kIGlzIGF2YWlsYWJsZSBpZiB5b3UgbmVlZCB0byB1cGRhdGUgdGhlIGNvbmZpZ3VyYXRpb24gb2YgYSBwYXJ0aWN1bGFyIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnVwZGF0ZSh7IHJvbGVzOiBbJ1ZQIE1hcmtldGluZycsICdWUCBTYWxlcycsICdWUCBFbmdpbmVlcmluZyddIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBQYXJhbWV0ZXJzIHRvIHVwZGF0ZSB0aGUgd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMubmFtZWAgQSBzdHJpbmcgaWRlbnRpZmllciBmb3IgdGhlIGxpbmtlZCBlbmQgdXNlcnMsIGZvciBleGFtcGxlLCBcIm5hbWVcIjogXCJPdXIgVGVhbVwiLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zLnJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbXVzdCoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIHJvbGVzIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMub3B0aW9uYWxSb2xlc2AgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gYHBhcmFtcy5taW5Vc2Vyc2AgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHdoaXRlbGlzdCA9IFsncm9sZXMnLCAnb3B0aW9uYWxSb2xlcycsICdtaW5Vc2VycyddO1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIHVwZGF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gX3BpY2socGFyYW1zIHx8IHt9LCB3aGl0ZWxpc3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wYXRjaChwYXJhbXMsIHVwZGF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgYW4gZXhpc3Rpbmcgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBUaGlzIGZ1bmN0aW9uIG9wdGlvbmFsbHkgdGFrZXMgb25lIGFyZ3VtZW50LiBJZiB0aGUgYXJndW1lbnQgaXMgYSBzdHJpbmcsIGl0IGlzIHRoZSBpZCBvZiB0aGUgd29ybGQgdG8gZGVsZXRlLiBJZiB0aGUgYXJndW1lbnQgaXMgYW4gb2JqZWN0LCBpdCBpcyB0aGUgb3ZlcnJpZGUgZm9yIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmRlbGV0ZSgpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBkZWxldGUsIG9yIG9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSAob3B0aW9ucyAmJiAodHlwZW9mIG9wdGlvbnMgPT09ICdzdHJpbmcnKSkgPyB7IGZpbHRlcjogb3B0aW9ucyB9IDoge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRlbGV0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGRlbGV0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBjdXJyZW50IGluc3RhbmNlIG9mIHRoZSBXb3JsZCBBUEkgQWRhcHRlciAoaW5jbHVkaW5nIGFsbCBzdWJzZXF1ZW50IGZ1bmN0aW9uIGNhbGxzLCB1bnRpbCB0aGUgY29uZmlndXJhdGlvbiBpcyB1cGRhdGVkIGFnYWluKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoey4uLn0pLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogJzEyMycgfSkuYWRkVXNlcih7IHVzZXJJZDogJzEyMycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgY29uZmlnYCBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgdG8gdXNlIGluIHVwZGF0aW5nIGV4aXN0aW5nIGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZUNvbmZpZzogZnVuY3Rpb24gKGNvbmZpZykge1xuICAgICAgICAgICAgJC5leHRlbmQoc2VydmljZU9wdGlvbnMsIGNvbmZpZyk7XG5cbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIExpc3RzIGFsbCB3b3JsZHMgZm9yIGEgZ2l2ZW4gYWNjb3VudCwgcHJvamVjdCwgYW5kIGdyb3VwLiBBbGwgdGhyZWUgYXJlIHJlcXVpcmVkLCBhbmQgaWYgbm90IHNwZWNpZmllZCBhcyBwYXJhbWV0ZXJzLCBhcmUgcmVhZCBmcm9tIHRoZSBzZXJ2aWNlLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGxpc3RzIGFsbCB3b3JsZHMgaW4gZ3JvdXAgXCJ0ZWFtMVwiXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5saXN0KCk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGxpc3RzIGFsbCB3b3JsZHMgaW4gZ3JvdXAgXCJvdGhlci1ncm91cC1uYW1lXCJcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmxpc3QoeyBncm91cDogJ290aGVyLWdyb3VwLW5hbWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBsaXN0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBmaWx0ZXJzID0gX3BpY2soZ2V0T3B0aW9ucywgWydhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGFsbCB3b3JsZHMgdGhhdCBhbiBlbmQgdXNlciBiZWxvbmdzIHRvIGZvciBhIGdpdmVuIGFjY291bnQgKHRlYW0pLCBwcm9qZWN0LCBhbmQgZ3JvdXAuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuZ2V0V29ybGRzRm9yVXNlcignYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJylcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZHMgYXJlIGJlaW5nIHJldHJpZXZlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGdldFdvcmxkc0ZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB2YXIgZmlsdGVycyA9ICQuZXh0ZW5kKFxuICAgICAgICAgICAgICAgIF9waWNrKGdldE9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pLFxuICAgICAgICAgICAgICAgIHsgdXNlcklkOiB1c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGZpbHRlcnMsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2FkIGluZm9ybWF0aW9uIGZvciBhIHNwZWNpZmljIHdvcmxkLiBBbGwgZnVydGhlciBjYWxscyB0byB0aGUgd29ybGQgc2VydmljZSB3aWxsIHVzZSB0aGUgaWQgcHJvdmlkZWQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgd29ybGRJZGAgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBsb2FkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSB3b3JsZElkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwcm92aWRlIGEgd29ybGRpZCB0byBsb2FkJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy8nIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQWRkcyBhbiBlbmQgdXNlciBvciBsaXN0IG9mIGVuZCB1c2VycyB0byBhIGdpdmVuIHdvcmxkLiBUaGUgZW5kIHVzZXIgbXVzdCBiZSBhIG1lbWJlciBvZiB0aGUgYGdyb3VwYCB0aGF0IGlzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBvbmUgdXNlclxuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoWydiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2Vycyh7IHVzZXJJZDogJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHJvbGU6ICdWUCBTYWxlcycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBzZXZlcmFsIHVzZXJzXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgeyB1c2VySWQ6ICdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgcm9sZTogJ1ZQIE1hcmtldGluZycgfSxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICB7IHVzZXJJZDogJzhmMjYwNGNmLTk2Y2QtNDQ5Zi04MmZhLWUzMzE1MzA3MzRlZScsXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgICByb2xlOiAnVlAgRW5naW5lZXJpbmcnIH1cbiAgICAgICAgKiAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgICAgICAgICAvLyBhZGQgb25lIHVzZXIgdG8gYSBzcGVjaWZpYyB3b3JsZFxuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB7IGZpbHRlcjogd29ybGQuaWQgfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKiogUGFyYW1ldGVycyAqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdHxhcnJheX0gYHVzZXJzYCBVc2VyIGlkLCBhcnJheSBvZiB1c2VyIGlkcywgb2JqZWN0LCBvciBhcnJheSBvZiBvYmplY3RzIG9mIHRoZSB1c2VycyB0byBhZGQgdG8gdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJzLnJvbGVgIFRoZSBgcm9sZWAgdGhlIHVzZXIgc2hvdWxkIGhhdmUgaW4gdGhlIHdvcmxkLiBJdCBpcyB1cCB0byB0aGUgY2FsbGVyIHRvIGVuc3VyZSwgaWYgbmVlZGVkLCB0aGF0IHRoZSBgcm9sZWAgcGFzc2VkIGluIGlzIG9uZSBvZiB0aGUgYHJvbGVzYCBvciBgb3B0aW9uYWxSb2xlc2Agb2YgdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHdvcmxkSWRgIFRoZSB3b3JsZCB0byB3aGljaCB0aGUgdXNlcnMgc2hvdWxkIGJlIGFkZGVkLiBJZiBub3Qgc3BlY2lmaWVkLCB0aGUgZmlsdGVyIHBhcmFtZXRlciBvZiB0aGUgYG9wdGlvbnNgIG9iamVjdCBpcyB1c2VkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgYWRkVXNlcnM6IGZ1bmN0aW9uICh1c2Vycywgd29ybGRJZCwgb3B0aW9ucykge1xuXG4gICAgICAgICAgICBpZiAoIXVzZXJzKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhIGxpc3Qgb2YgdXNlcnMgdG8gYWRkIHRvIHRoZSB3b3JsZCcpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBub3JtYWxpemUgdGhlIGxpc3Qgb2YgdXNlcnMgdG8gYW4gYXJyYXkgb2YgdXNlciBvYmplY3RzXG4gICAgICAgICAgICB1c2VycyA9ICQubWFwKFtdLmNvbmNhdCh1c2VycyksIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgdmFyIGlzT2JqZWN0ID0gJC5pc1BsYWluT2JqZWN0KHUpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB1ICE9PSAnc3RyaW5nJyAmJiAhaXNPYmplY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTb21lIG9mIHRoZSB1c2VycyBpbiB0aGUgbGlzdCBhcmUgbm90IGluIHRoZSB2YWxpZCBmb3JtYXQ6ICcgKyB1KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gaXNPYmplY3QgPyB1IDogeyB1c2VySWQ6IHUgfTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyBjaGVjayBpZiBvcHRpb25zIHdlcmUgcGFzc2VkIGFzIHRoZSBzZWNvbmQgcGFyYW1ldGVyXG4gICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHdvcmxkSWQpICYmICFvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHdvcmxkSWQ7XG4gICAgICAgICAgICAgICAgd29ybGRJZCA9IG51bGw7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICAvLyB3ZSBtdXN0IGhhdmUgb3B0aW9ucyBieSBub3dcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygd29ybGRJZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgdXBkYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvdXNlcnMnIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QodXNlcnMsIHVwZGF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIHJvbGUgb2YgYW4gZW5kIHVzZXIgaW4gYSBnaXZlbiB3b3JsZC4gKFlvdSBjYW4gb25seSB1cGRhdGUgb25lIGVuZCB1c2VyIGF0IGEgdGltZS4pXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuY3JlYXRlKCkudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJyk7XG4gICAgICAgICogICAgICAgICAgIHdhLnVwZGF0ZVVzZXIoeyB1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCByb2xlOiAnbGVhZGVyJyB9KTtcbiAgICAgICAgKiAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHVzZXJgIFVzZXIgb2JqZWN0IHdpdGggYHVzZXJJZGAgYW5kIHRoZSBuZXcgYHJvbGVgLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICB1cGRhdGVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICghdXNlciB8fCAhdXNlci51c2VySWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1lvdSBuZWVkIHRvIHBhc3MgYSB1c2VySWQgdG8gdXBkYXRlIGZyb20gdGhlIHdvcmxkJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcGF0Y2hPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goX3BpY2sodXNlciwgJ3JvbGUnKSwgcGF0Y2hPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZW1vdmVzIGFuIGVuZCB1c2VyIGZyb20gYSBnaXZlbiB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbJ2E2ZmUwYzFlLWY0YjgtNGYwMS05ZjVmLTAxY2NmNGMyZWQ0NCcsICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5yZW1vdmVVc2VyKCdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnJlbW92ZVVzZXIoeyB1c2VySWQ6ICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdHxzdHJpbmd9IGB1c2VyYCBUaGUgYHVzZXJJZGAgb2YgdGhlIHVzZXIgdG8gcmVtb3ZlIGZyb20gdGhlIHdvcmxkLCBvciBhbiBvYmplY3QgY29udGFpbmluZyB0aGUgYHVzZXJJZGAgZmllbGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICByZW1vdmVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICh0eXBlb2YgdXNlciA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICB1c2VyID0geyB1c2VySWQ6IHVzZXIgfTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCF1c2VyLnVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignWW91IG5lZWQgdG8gcGFzcyBhIHVzZXJJZCB0byByZW1vdmUgZnJvbSB0aGUgd29ybGQnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIHJ1biBpZCBvZiBjdXJyZW50IHJ1biBmb3IgdGhlIGdpdmVuIHdvcmxkLiBJZiB0aGUgd29ybGQgZG9lcyBub3QgaGF2ZSBhIHJ1biwgY3JlYXRlcyBhIG5ldyBvbmUgYW5kIHJldHVybnMgdGhlIHJ1biBpZC5cbiAgICAgICAgKlxuICAgICAgICAqIFJlbWVtYmVyIHRoYXQgYSBbcnVuXSguLi8uLi9nbG9zc2FyeS8jcnVuKSBpcyBhIGNvbGxlY3Rpb24gb2YgaW50ZXJhY3Rpb25zIHdpdGggYSBwcm9qZWN0IGFuZCBpdHMgbW9kZWwuIEluIHRoZSBjYXNlIG9mIG11bHRpcGxheWVyIHByb2plY3RzLCB0aGUgcnVuIGlzIHNoYXJlZCBieSBhbGwgZW5kIHVzZXJzIGluIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5nZXRDdXJyZW50UnVuSWQoeyBtb2RlbDogJ21vZGVsLnB5JyB9KTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9ucy5tb2RlbGAgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRSdW5JZDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3J1bicgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvcihnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QoX3BpY2soZ2V0T3B0aW9ucywgJ21vZGVsJyksIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIGN1cnJlbnQgKG1vc3QgcmVjZW50KSB3b3JsZCBmb3IgdGhlIGdpdmVuIGVuZCB1c2VyIGluIHRoZSBnaXZlbiBncm91cC4gQnJpbmdzIHRoaXMgbW9zdCByZWNlbnQgd29ybGQgaW50byBtZW1vcnkgaWYgbmVlZGVkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIHVzZSBkYXRhIGZyb20gd29ybGRcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSBjdXJyZW50IChtb3N0IHJlY2VudCkgd29ybGQgaXMgYmVpbmcgcmV0cmlldmVkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIFRoZSBuYW1lIG9mIHRoZSBncm91cC4gSWYgbm90IHByb3ZpZGVkLCBkZWZhdWx0cyB0byB0aGUgZ3JvdXAgdXNlZCB0byBjcmVhdGUgdGhlIHNlcnZpY2UuXG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRXb3JsZEZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIGdyb3VwTmFtZSkge1xuICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgICAgICB0aGlzLmdldFdvcmxkc0ZvclVzZXIodXNlcklkLCB7IGdyb3VwOiBncm91cE5hbWUgfSlcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGRzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGFzc3VtZSB0aGUgbW9zdCByZWNlbnQgd29ybGQgYXMgdGhlICdhY3RpdmUnIHdvcmxkXG4gICAgICAgICAgICAgICAgICAgIHdvcmxkcy5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7IHJldHVybiBuZXcgRGF0ZShiLmxhc3RNb2RpZmllZCkgLSBuZXcgRGF0ZShhLmxhc3RNb2RpZmllZCk7IH0pO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3VycmVudFdvcmxkID0gd29ybGRzWzBdO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChjdXJyZW50V29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9ICBjdXJyZW50V29ybGQuaWQ7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShjdXJyZW50V29ybGQsIG1lKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBEZWxldGVzIHRoZSBjdXJyZW50IHJ1biBmcm9tIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIChOb3RlIHRoYXQgdGhlIHdvcmxkIGlkIHJlbWFpbnMgcGFydCBvZiB0aGUgcnVuIHJlY29yZCwgaW5kaWNhdGluZyB0aGF0IHRoZSBydW4gd2FzIGZvcm1lcmx5IGFuIGFjdGl2ZSBydW4gZm9yIHRoZSB3b3JsZC4pXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmRlbGV0ZVJ1bignc2FtcGxlLXdvcmxkLWlkJyk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHdvcmxkSWRgIFRoZSBgd29ybGRJZGAgb2YgdGhlIHdvcmxkIGZyb20gd2hpY2ggdGhlIGN1cnJlbnQgcnVuIGlzIGJlaW5nIGRlbGV0ZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBkZWxldGVSdW46IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZGVsZXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvcnVuJyB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZGVsZXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIG5ldyBydW4gZm9yIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgd2EubmV3UnVuRm9yV29ybGQod29ybGQuaWQpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgd29ybGRJZGAgd29ybGRJZCBpbiB3aGljaCB3ZSBjcmVhdGUgdGhlIG5ldyBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9ucy5tb2RlbGAgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICovXG4gICAgICAgIG5ld1J1bkZvcldvcmxkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGN1cnJlbnRSdW5PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IGZpbHRlcjogd29ybGRJZCB8fCBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgICAgIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IoY3VycmVudFJ1bk9wdGlvbnMpO1xuXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5kZWxldGVSdW4od29ybGRJZCwgb3B0aW9ucylcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5nZXRDdXJyZW50UnVuSWQoY3VycmVudFJ1bk9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEFzc2lnbnMgZW5kIHVzZXJzIHRvIHdvcmxkcywgY3JlYXRpbmcgbmV3IHdvcmxkcyBhcyBhcHByb3ByaWF0ZSwgYXV0b21hdGljYWxseS4gQXNzaWducyBhbGwgZW5kIHVzZXJzIGluIHRoZSBncm91cCwgYW5kIGNyZWF0ZXMgbmV3IHdvcmxkcyBhcyBuZWVkZWQgYmFzZWQgb24gdGhlIHByb2plY3QtbGV2ZWwgd29ybGQgY29uZmlndXJhdGlvbiAocm9sZXMsIG9wdGlvbmFsIHJvbGVzLCBhbmQgbWluaW11bSBlbmQgdXNlcnMgcGVyIHdvcmxkKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5hdXRvQXNzaWduKCk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBhdXRvQXNzaWduOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhc3NpZ25tZW50RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBwYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgYWNjb3VudDogb3B0LmFjY291bnQsXG4gICAgICAgICAgICAgICAgcHJvamVjdDogb3B0LnByb2plY3QsXG4gICAgICAgICAgICAgICAgZ3JvdXA6IG9wdC5ncm91cFxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKG9wdC5tYXhVc2Vycykge1xuICAgICAgICAgICAgICAgIHBhcmFtcy5tYXhVc2VycyA9IG9wdC5tYXhVc2VycztcbiAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgb3B0KTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIHRoZSBwcm9qZWN0J3Mgd29ybGQgY29uZmlndXJhdGlvbi5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgZXZlcnkgaW50ZXJhY3Rpb24gd2l0aCB5b3VyIHByb2plY3QgdXNlcyB0aGUgc2FtZSBjb25maWd1cmF0aW9uIG9mIGVhY2ggd29ybGQuIEZvciBleGFtcGxlLCBlYWNoIHdvcmxkIGluIHlvdXIgcHJvamVjdCBwcm9iYWJseSBoYXMgdGhlIHNhbWUgcm9sZXMgZm9yIGVuZCB1c2Vycy4gQW5kIHlvdXIgcHJvamVjdCBpcyBwcm9iYWJseSBlaXRoZXIgY29uZmlndXJlZCBzbyB0aGF0IGFsbCBlbmQgdXNlcnMgc2hhcmUgdGhlIHNhbWUgd29ybGQgKGFuZCBydW4pLCBvciBzbWFsbGVyIHNldHMgb2YgZW5kIHVzZXJzIHNoYXJlIHdvcmxkcyDigJQgYnV0IG5vdCBib3RoLlxuICAgICAgICAqXG4gICAgICAgICogKFRoZSBbTXVsdGlwbGF5ZXIgUHJvamVjdCBSRVNUIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL211bHRpcGxheWVyX3Byb2plY3QvKSBhbGxvd3MgeW91IHRvIHNldCB0aGVzZSBwcm9qZWN0LWxldmVsIHdvcmxkIGNvbmZpZ3VyYXRpb25zLiBUaGUgV29ybGQgQWRhcHRlciBzaW1wbHkgcmV0cmlldmVzIHRoZW0sIGZvciBleGFtcGxlIHNvIHRoZXkgY2FuIGJlIHVzZWQgaW4gYXV0by1hc3NpZ25tZW50IG9mIGVuZCB1c2VycyB0byB3b3JsZHMuKVxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmdldFByb2plY3RTZXR0aW5ncygpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHNldHRpbmdzKSB7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5yb2xlcyk7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5vcHRpb25hbFJvbGVzKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0UHJvamVjdFNldHRpbmdzOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChwcm9qZWN0RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIG9wdC51cmwgKz0gW29wdC5hY2NvdW50LCBvcHQucHJvamVjdF0uam9pbignLycpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQobnVsbCwgb3B0KTtcbiAgICAgICAgfVxuXG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKiBAY2xhc3MgQ29va2llIFN0b3JhZ2UgU2VydmljZVxuICpcbiAqIEBleGFtcGxlXG4gKiAgICAgIHZhciBwZW9wbGUgPSByZXF1aXJlKCdjb29raWUtc3RvcmUnKSh7IHJvb3Q6ICdwZW9wbGUnIH0pO1xuICAgICAgICBwZW9wbGVcbiAgICAgICAgICAgIC5zYXZlKHtsYXN0TmFtZTogJ3NtaXRoJyB9KVxuXG4gKi9cblxuXG4ndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIE5hbWUgb2YgY29sbGVjdGlvblxuICAgICAgICAgKiBAdHlwZSB7IHN0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHJvb3Q6ICcvJyxcblxuICAgICAgICBkb21haW46ICcuZm9yaW8uY29tJ1xuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLy8gKiBUQkRcbiAgICAgICAgLy8gICogUXVlcnkgY29sbGVjdGlvbjsgdXNlcyBNb25nb0RCIHN5bnRheFxuICAgICAgICAvLyAgKiBAc2VlICA8VEJEOiBEYXRhIEFQSSBVUkw+XG4gICAgICAgIC8vICAqXG4gICAgICAgIC8vICAqIEBwYXJhbSB7IHN0cmluZ30gcXMgUXVlcnkgRmlsdGVyXG4gICAgICAgIC8vICAqIEBwYXJhbSB7IHN0cmluZ30gbGltaXRlcnMgQHNlZSA8VEJEOiB1cmwgZm9yIGxpbWl0cywgcGFnaW5nIGV0Yz5cbiAgICAgICAgLy8gICpcbiAgICAgICAgLy8gICogQGV4YW1wbGVcbiAgICAgICAgLy8gICogICAgIGNzLnF1ZXJ5KFxuICAgICAgICAvLyAgKiAgICAgIHsgbmFtZTogJ0pvaG4nLCBjbGFzc05hbWU6ICdDU0MxMDEnIH0sXG4gICAgICAgIC8vICAqICAgICAge2xpbWl0OiAxMH1cbiAgICAgICAgLy8gICogICAgIClcblxuICAgICAgICAvLyBxdWVyeTogZnVuY3Rpb24gKHFzLCBsaW1pdGVycykge1xuXG4gICAgICAgIC8vIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgY29va2llIHZhbHVlXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8T2JqZWN0fSBrZXkgICBJZiBnaXZlbiBhIGtleSBzYXZlIHZhbHVlcyB1bmRlciBpdCwgaWYgZ2l2ZW4gYW4gb2JqZWN0IGRpcmVjdGx5LCBzYXZlIHRvIHRvcC1sZXZlbCBhcGlcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSB2YWx1ZSAoT3B0aW9uYWwpXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIE92ZXJyaWRlcyBmb3Igc2VydmljZSBvcHRpb25zXG4gICAgICAgICAqXG4gICAgICAgICAqIEByZXR1cm4geyp9IFRoZSBzYXZlZCB2YWx1ZVxuICAgICAgICAgKlxuICAgICAgICAgKiBAZXhhbXBsZVxuICAgICAgICAgKiAgICAgY3Muc2V0KCdwZXJzb24nLCB7IGZpcnN0TmFtZTogJ2pvaG4nLCBsYXN0TmFtZTogJ3NtaXRoJyB9KTtcbiAgICAgICAgICogICAgIGNzLnNldCh7IG5hbWU6J3NtaXRoJywgYWdlOiczMicgfSk7XG4gICAgICAgICAqL1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbHVlLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgc2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBkb21haW4gPSBzZXRPcHRpb25zLmRvbWFpbjtcbiAgICAgICAgICAgIHZhciBwYXRoID0gc2V0T3B0aW9ucy5yb290O1xuXG4gICAgICAgICAgICBkb2N1bWVudC5jb29raWUgPSBlbmNvZGVVUklDb21wb25lbnQoa2V5KSArICc9JyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuY29kZVVSSUNvbXBvbmVudCh2YWx1ZSkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZG9tYWluID8gJzsgZG9tYWluPScgKyBkb21haW4gOiAnJykgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocGF0aCA/ICc7IHBhdGg9JyArIHBhdGggOiAnJyk7XG5cbiAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTG9hZCBjb29raWUgdmFsdWVcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xPYmplY3R9IGtleSAgIElmIGdpdmVuIGEga2V5IHNhdmUgdmFsdWVzIHVuZGVyIGl0LCBpZiBnaXZlbiBhbiBvYmplY3QgZGlyZWN0bHksIHNhdmUgdG8gdG9wLWxldmVsIGFwaVxuICAgICAgICAgKiBAcmV0dXJuIHsqfSBUaGUgdmFsdWUgc3RvcmVkXG4gICAgICAgICAqXG4gICAgICAgICAqIEBleGFtcGxlXG4gICAgICAgICAqICAgICBjcy5nZXQoJ3BlcnNvbicpO1xuICAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgICAgICB2YXIgY29va2llUmVnID0gbmV3IFJlZ0V4cCgnKD86KD86XnwuKjspXFxcXHMqJyArIGVuY29kZVVSSUNvbXBvbmVudChrZXkpLnJlcGxhY2UoL1tcXC1cXC5cXCtcXCpdL2csICdcXFxcJCYnKSArICdcXFxccypcXFxcPVxcXFxzKihbXjtdKikuKiQpfF4uKiQnKTtcbiAgICAgICAgICAgIHZhciB2YWwgPSBkb2N1bWVudC5jb29raWUucmVwbGFjZShjb29raWVSZWcsICckMScpO1xuICAgICAgICAgICAgdmFsID0gZGVjb2RlVVJJQ29tcG9uZW50KHZhbCkgfHwgbnVsbDtcbiAgICAgICAgICAgIHJldHVybiB2YWw7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMga2V5IGZyb20gY29sbGVjdGlvblxuICAgICAgICAgKiBAcGFyYW0geyBzdHJpbmd9IGtleSBrZXkgdG8gcmVtb3ZlXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9IGtleSBUaGUga2V5IHJlbW92ZWRcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLnJlbW92ZSgncGVyc29uJyk7XG4gICAgICAgICAqL1xuICAgICAgICByZW1vdmU6IGZ1bmN0aW9uIChrZXksIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciByZW1PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRvbWFpbiA9IHJlbU9wdGlvbnMuZG9tYWluO1xuICAgICAgICAgICAgdmFyIHBhdGggPSByZW1PcHRpb25zLnJvb3Q7XG5cbiAgICAgICAgICAgIGRvY3VtZW50LmNvb2tpZSA9IGVuY29kZVVSSUNvbXBvbmVudChrZXkpICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnPTsgZXhwaXJlcz1UaHUsIDAxIEphbiAxOTcwIDAwOjAwOjAwIEdNVCcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChkb21haW4gPyAnOyBkb21haW49JyArIGRvbWFpbiA6ICcnKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKHBhdGggPyAnOyBwYXRoPScgKyBwYXRoIDogJycpO1xuICAgICAgICAgICAgcmV0dXJuIGtleTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBjb2xsZWN0aW9uIGJlaW5nIHJlZmVyZW5jZWRcbiAgICAgICAgICogQHJldHVybiB7IGFycmF5fSBrZXlzIEFsbCB0aGUga2V5cyByZW1vdmVkXG4gICAgICAgICAqL1xuICAgICAgICBkZXN0cm95OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgYUtleXMgPSBkb2N1bWVudC5jb29raWUucmVwbGFjZSgvKCg/Ol58XFxzKjspW15cXD1dKykoPz07fCQpfF5cXHMqfFxccyooPzpcXD1bXjtdKik/KD86XFwxfCQpL2csICcnKS5zcGxpdCgvXFxzKig/OlxcPVteO10qKT87XFxzKi8pO1xuICAgICAgICAgICAgZm9yICh2YXIgbklkeCA9IDA7IG5JZHggPCBhS2V5cy5sZW5ndGg7IG5JZHgrKykge1xuICAgICAgICAgICAgICAgIHZhciBjb29raWVLZXkgPSBkZWNvZGVVUklDb21wb25lbnQoYUtleXNbbklkeF0pO1xuICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKGNvb2tpZUtleSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gYUtleXM7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAgICBEZWNpZGVzIHR5cGUgb2Ygc3RvcmUgdG8gcHJvdmlkZVxuKi9cblxuJ3VzZSBzdHJpY3QnO1xuLy8gdmFyIGlzTm9kZSA9IGZhbHNlOyBGSVhNRTogQnJvd3NlcmlmeS9taW5pZnlpZnkgaGFzIGlzc3VlcyB3aXRoIHRoZSBuZXh0IGxpbmtcbi8vIHZhciBzdG9yZSA9IChpc05vZGUpID8gcmVxdWlyZSgnLi9zZXNzaW9uLXN0b3JlJykgOiByZXF1aXJlKCcuL2Nvb2tpZS1zdG9yZScpO1xudmFyIHN0b3JlID0gcmVxdWlyZSgnLi9jb29raWUtc3RvcmUnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBzdG9yZTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIHF1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgdXJsOiAnJyxcblxuICAgICAgICBjb250ZW50VHlwZTogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICBoZWFkZXJzOiB7fSxcbiAgICAgICAgc3RhdHVzQ29kZToge1xuICAgICAgICAgICAgNDA0OiAkLm5vb3BcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT05MWSBmb3Igc3RyaW5ncyBpbiB0aGUgdXJsLiBBbGwgR0VUICYgREVMRVRFIHBhcmFtcyBhcmUgcnVuIHRocm91Z2ggdGhpc1xuICAgICAgICAgKiBAdHlwZSB7W3R5cGVdIH1cbiAgICAgICAgICovXG4gICAgICAgIHBhcmFtZXRlclBhcnNlcjogcXV0aWxzLnRvUXVlcnlGb3JtYXQsXG5cbiAgICAgICAgLy8gVG8gYWxsb3cgZXBpY2VudGVyLnRva2VuIGFuZCBvdGhlciBzZXNzaW9uIGNvb2tpZXMgdG8gYmUgcGFzc2VkXG4gICAgICAgIC8vIHdpdGggdGhlIHJlcXVlc3RzXG4gICAgICAgIHhockZpZWxkczoge1xuICAgICAgICAgICAgd2l0aENyZWRlbnRpYWxzOiB0cnVlXG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG5cbiAgICB2YXIgcmVzdWx0ID0gZnVuY3Rpb24gKGQpIHtcbiAgICAgICAgcmV0dXJuICgkLmlzRnVuY3Rpb24oZCkpID8gZCgpIDogZDtcbiAgICB9O1xuXG4gICAgdmFyIGNvbm5lY3QgPSBmdW5jdGlvbiAobWV0aG9kLCBwYXJhbXMsIGNvbm5lY3RPcHRpb25zKSB7XG4gICAgICAgIHBhcmFtcyA9IHJlc3VsdChwYXJhbXMpO1xuICAgICAgICBwYXJhbXMgPSAoJC5pc1BsYWluT2JqZWN0KHBhcmFtcykgfHwgJC5pc0FycmF5KHBhcmFtcykpID8gSlNPTi5zdHJpbmdpZnkocGFyYW1zKSA6IHBhcmFtcztcblxuICAgICAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB0cmFuc3BvcnRPcHRpb25zLCBjb25uZWN0T3B0aW9ucywge1xuICAgICAgICAgICAgdHlwZTogbWV0aG9kLFxuICAgICAgICAgICAgZGF0YTogcGFyYW1zXG4gICAgICAgIH0pO1xuICAgICAgICB2YXIgQUxMT1dFRF9UT19CRV9GVU5DVElPTlMgPSBbJ2RhdGEnLCAndXJsJ107XG4gICAgICAgICQuZWFjaChvcHRpb25zLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgaWYgKCQuaXNGdW5jdGlvbih2YWx1ZSkgJiYgJC5pbkFycmF5KGtleSwgQUxMT1dFRF9UT19CRV9GVU5DVElPTlMpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIG9wdGlvbnNba2V5XSA9IHZhbHVlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChvcHRpb25zLmxvZ0xldmVsICYmIG9wdGlvbnMubG9nTGV2ZWwgPT09ICdERUJVRycpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKG9wdGlvbnMudXJsKTtcbiAgICAgICAgICAgIHZhciBvbGRTdWNjZXNzRm4gPSBvcHRpb25zLnN1Y2Nlc3MgfHwgJC5ub29wO1xuICAgICAgICAgICAgb3B0aW9ucy5zdWNjZXNzID0gZnVuY3Rpb24gKHJlc3BvbnNlLCBhamF4U3RhdHVzLCBhamF4UmVxKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2cocmVzcG9uc2UpO1xuICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3NGbi5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBiZWZvcmVTZW5kID0gb3B0aW9ucy5iZWZvcmVTZW5kO1xuICAgICAgICBvcHRpb25zLmJlZm9yZVNlbmQgPSBmdW5jdGlvbiAoeGhyLCBzZXR0aW5ncykge1xuICAgICAgICAgICAgeGhyLnJlcXVlc3RVcmwgPSAoY29ubmVjdE9wdGlvbnMgfHwge30pLnVybDtcbiAgICAgICAgICAgIGlmIChiZWZvcmVTZW5kKSB7XG4gICAgICAgICAgICAgICAgYmVmb3JlU2VuZC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiAkLmFqYXgob3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG4gICAgICAgIGdldDpmdW5jdGlvbiAocGFyYW1zLCBhamF4T3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIG9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgdHJhbnNwb3J0T3B0aW9ucywgYWpheE9wdGlvbnMpO1xuICAgICAgICAgICAgcGFyYW1zID0gb3B0aW9ucy5wYXJhbWV0ZXJQYXJzZXIocmVzdWx0KHBhcmFtcykpO1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuY2FsbCh0aGlzLCAnR0VUJywgcGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgfSxcbiAgICAgICAgc3BsaXRHZXQ6IGZ1bmN0aW9uICgpIHtcblxuICAgICAgICB9LFxuICAgICAgICBwb3N0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ3Bvc3QnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIHBhdGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ3BhdGNoJ10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9LFxuICAgICAgICBwdXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncHV0J10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9LFxuICAgICAgICBkZWxldGU6IGZ1bmN0aW9uIChwYXJhbXMsIGFqYXhPcHRpb25zKSB7XG4gICAgICAgICAgICAvL0RFTEVURSBkb2Vzbid0IHN1cHBvcnQgYm9keSBwYXJhbXMsIGJ1dCBqUXVlcnkgdGhpbmtzIGl0IGRvZXMuXG4gICAgICAgICAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCB0cmFuc3BvcnRPcHRpb25zLCBhamF4T3B0aW9ucyk7XG4gICAgICAgICAgICBwYXJhbXMgPSBvcHRpb25zLnBhcmFtZXRlclBhcnNlcihyZXN1bHQocGFyYW1zKSk7XG4gICAgICAgICAgICBpZiAoJC50cmltKHBhcmFtcykpIHtcbiAgICAgICAgICAgICAgICB2YXIgZGVsaW1pdGVyID0gKHJlc3VsdChvcHRpb25zLnVybCkuaW5kZXhPZignPycpID09PSAtMSkgPyAnPycgOiAnJic7XG4gICAgICAgICAgICAgICAgb3B0aW9ucy51cmwgPSByZXN1bHQob3B0aW9ucy51cmwpICsgZGVsaW1pdGVyICsgcGFyYW1zO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuY2FsbCh0aGlzLCAnREVMRVRFJywgbnVsbCwgb3B0aW9ucyk7XG4gICAgICAgIH0sXG4gICAgICAgIGhlYWQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsnaGVhZCddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfSxcbiAgICAgICAgb3B0aW9uczogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydvcHRpb25zJ10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHJldHVybiAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxuLy8gdmFyIGlzTm9kZSA9IGZhbHNlOyBGSVhNRTogQnJvd3NlcmlmeS9taW5pZnlpZnkgaGFzIGlzc3VlcyB3aXRoIHRoZSBuZXh0IGxpbmtcbi8vIHZhciB0cmFuc3BvcnQgPSAoaXNOb2RlKSA/IHJlcXVpcmUoJy4vbm9kZS1odHRwLXRyYW5zcG9ydCcpIDogcmVxdWlyZSgnLi9hamF4LWh0dHAtdHJhbnNwb3J0Jyk7XG52YXIgdHJhbnNwb3J0ID0gcmVxdWlyZSgnLi9hamF4LWh0dHAtdHJhbnNwb3J0Jyk7XG5tb2R1bGUuZXhwb3J0cyA9IHRyYW5zcG9ydDtcbiIsIi8qKlxuLyogSW5oZXJpdCBmcm9tIGEgY2xhc3MgKHVzaW5nIHByb3RvdHlwZSBib3Jyb3dpbmcpXG4qL1xuJ3VzZSBzdHJpY3QnO1xuXG5mdW5jdGlvbiBpbmhlcml0KEMsIFApIHtcbiAgICB2YXIgRiA9IGZ1bmN0aW9uICgpIHt9O1xuICAgIEYucHJvdG90eXBlID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUgPSBuZXcgRigpO1xuICAgIEMuX19zdXBlciA9IFAucHJvdG90eXBlO1xuICAgIEMucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQztcbn1cblxuLyoqXG4qIFNoYWxsb3cgY29weSBvZiBhbiBvYmplY3RcbiovXG52YXIgZXh0ZW5kID0gZnVuY3Rpb24gKGRlc3QgLyosIHZhcl9hcmdzKi8pIHtcbiAgICB2YXIgb2JqID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICB2YXIgY3VycmVudDtcbiAgICBmb3IgKHZhciBqID0gMDsgajxvYmoubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKCEoY3VycmVudCA9IG9ialtqXSkpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZG8gbm90IHdyYXAgaW5uZXIgaW4gZGVzdC5oYXNPd25Qcm9wZXJ0eSBvciBiYWQgdGhpbmdzIHdpbGwgaGFwcGVuXG4gICAgICAgIC8qanNoaW50IC1XMDg5ICovXG4gICAgICAgIGZvciAodmFyIGtleSBpbiBjdXJyZW50KSB7XG4gICAgICAgICAgICBkZXN0W2tleV0gPSBjdXJyZW50W2tleV07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZGVzdDtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGJhc2UsIHByb3BzLCBzdGF0aWNQcm9wcykge1xuICAgIHZhciBwYXJlbnQgPSBiYXNlO1xuICAgIHZhciBjaGlsZDtcblxuICAgIGNoaWxkID0gcHJvcHMgJiYgcHJvcHMuaGFzT3duUHJvcGVydHkoJ2NvbnN0cnVjdG9yJykgPyBwcm9wcy5jb25zdHJ1Y3RvciA6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHBhcmVudC5hcHBseSh0aGlzLCBhcmd1bWVudHMpOyB9O1xuXG4gICAgLy8gYWRkIHN0YXRpYyBwcm9wZXJ0aWVzIHRvIHRoZSBjaGlsZCBjb25zdHJ1Y3RvciBmdW5jdGlvblxuICAgIGV4dGVuZChjaGlsZCwgcGFyZW50LCBzdGF0aWNQcm9wcyk7XG5cbiAgICAvLyBhc3NvY2lhdGUgcHJvdG90eXBlIGNoYWluXG4gICAgaW5oZXJpdChjaGlsZCwgcGFyZW50KTtcblxuICAgIC8vIGFkZCBpbnN0YW5jZSBwcm9wZXJ0aWVzXG4gICAgaWYgKHByb3BzKSB7XG4gICAgICAgIGV4dGVuZChjaGlsZC5wcm90b3R5cGUsIHByb3BzKTtcbiAgICB9XG5cbiAgICAvLyBkb25lXG4gICAgcmV0dXJuIGNoaWxkO1xufTtcbiIsIid1c2Ugc3RyaWN0Jztcbi8qanNoaW50IGxvb3BmdW5jOmZhbHNlICovXG5cbmZ1bmN0aW9uIF93KHZhbCkge1xuICAgIGlmICh2YWwgJiYgdmFsLnRoZW4pIHtcbiAgICAgICAgcmV0dXJuIHZhbDtcbiAgICB9XG4gICAgdmFyIHAgPSAkLkRlZmVycmVkKCk7XG4gICAgcC5yZXNvbHZlKHZhbCk7XG5cbiAgICByZXR1cm4gcC5wcm9taXNlKCk7XG59XG5cbmZ1bmN0aW9uIHNlcSgpIHtcbiAgICB2YXIgbGlzdCA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5hcHBseShhcmd1bWVudHMpO1xuXG4gICAgZnVuY3Rpb24gbmV4dChwKSB7XG4gICAgICAgIHZhciBjdXIgPSBsaXN0LnNwbGljZSgwLDEpWzBdO1xuXG4gICAgICAgIGlmICghY3VyKSB7XG4gICAgICAgICAgICByZXR1cm4gcDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBfdyhjdXIocCkpLnRoZW4obmV4dCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZ1bmN0aW9uIChzZWVkKSB7XG4gICAgICAgIHJldHVybiBuZXh0KHNlZWQpLmZhaWwoc2VxLmZhaWwpO1xuICAgIH07XG59XG5cbmZ1bmN0aW9uIE1ha2VTZXEob2JqKSB7XG4gICAgdmFyIHJlcyA9IHtcbiAgICAgICAgX19jYWxsczogW10sXG5cbiAgICAgICAgb3JpZ2luYWw6IG9iaixcblxuICAgICAgICB0aGVuOiBmdW5jdGlvbiAoZm4pIHtcbiAgICAgICAgICAgIHRoaXMuX19jYWxscy5wdXNoKGZuKTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuXG4gICAgICAgIHN0YXJ0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICAgICAgICAvLyBjbGVhbiB1cFxuICAgICAgICAgICAgdGhpcy50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICBfdGhpcy5fX2NhbGxzLmxlbmd0aCA9IDA7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gc2VxLmFwcGx5KG51bGwsIHRoaXMuX19jYWxscykoKTtcbiAgICAgICAgfSxcblxuICAgICAgICBmYWlsOiBmdW5jdGlvbiAoZm4pIHtcbiAgICAgICAgICAgIHNlcS5mYWlsID0gZm47XG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgZnVuY01ha2VyID0gZnVuY3Rpb24gKHAsIG9iaikge1xuICAgICAgICB2YXIgZm4gPSBvYmpbcF0uYmluZChvYmopO1xuICAgICAgICByZXR1cm4gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuYXBwbHkoYXJndW1lbnRzKTtcbiAgICAgICAgICAgIHRoaXMuX19jYWxscy5wdXNoKEZ1bmN0aW9uLmJpbmQuYXBwbHkoZm4sIFtudWxsXS5jb25jYXQoYXJncykpKTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9O1xuICAgIH07XG5cbiAgICBmb3IgKHZhciBwcm9wIGluIG9iaikge1xuICAgICAgICBpZiAodHlwZW9mIG9ialtwcm9wXSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgcmVzW3Byb3BdID0gZnVuY01ha2VyKHByb3AsIG9iaik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXNbcHJvcF0gPSBvYmpbcHJvcF07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gcmVzO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IE1ha2VTZXE7XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIF9waWNrOiBmdW5jdGlvbiAob2JqLCBwcm9wcykge1xuICAgICAgICB2YXIgcmVzID0ge307XG4gICAgICAgIGZvciAodmFyIHAgaW4gb2JqKSB7XG4gICAgICAgICAgICBpZiAocHJvcHMuaW5kZXhPZihwKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICByZXNbcF0gPSBvYmpbcF07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcmVzO1xuICAgIH1cbn07XG4iLCIvKipcbiAqIFV0aWxpdGllcyBmb3Igd29ya2luZyB3aXRoIHF1ZXJ5IHN0cmluZ3NcbiovXG4ndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gKGZ1bmN0aW9uICgpIHtcblxuICAgIHJldHVybiB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZXJ0cyB0byBtYXRyaXggZm9ybWF0XG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gcXMgT2JqZWN0IHRvIGNvbnZlcnQgdG8gcXVlcnkgc3RyaW5nXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9ICAgIE1hdHJpeC1mb3JtYXQgcXVlcnkgcGFyYW1ldGVyc1xuICAgICAgICAgKi9cbiAgICAgICAgdG9NYXRyaXhGb3JtYXQ6IGZ1bmN0aW9uIChxcykge1xuICAgICAgICAgICAgaWYgKHFzID09PSBudWxsIHx8IHFzID09PSB1bmRlZmluZWQgfHwgcXMgPT09ICcnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICc7JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0eXBlb2YgcXMgPT09ICdzdHJpbmcnIHx8IHFzIGluc3RhbmNlb2YgU3RyaW5nKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHFzO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcmV0dXJuQXJyYXkgPSBbXTtcbiAgICAgICAgICAgIHZhciBPUEVSQVRPUlMgPSBbJzwnLCAnPicsICchJ107XG4gICAgICAgICAgICAkLmVhY2gocXMsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gJ3N0cmluZycgfHwgJC5pbkFycmF5KCQudHJpbSh2YWx1ZSkuY2hhckF0KDApLCBPUEVSQVRPUlMpID09PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9ICc9JyArIHZhbHVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5BcnJheS5wdXNoKGtleSArIHZhbHVlKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICB2YXIgbXRyeCA9ICc7JyArIHJldHVybkFycmF5LmpvaW4oJzsnKTtcbiAgICAgICAgICAgIHJldHVybiBtdHJ4O1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZXJ0cyBzdHJpbmdzL2FycmF5cy9vYmplY3RzIHRvIHR5cGUgJ2E9YiZiPWMnXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8QXJyYXl8T2JqZWN0fSBxc1xuICAgICAgICAgKiBAcmV0dXJuIHsgc3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdG9RdWVyeUZvcm1hdDogZnVuY3Rpb24gKHFzKSB7XG4gICAgICAgICAgICBpZiAocXMgPT09IG51bGwgfHwgcXMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0eXBlb2YgcXMgPT09ICdzdHJpbmcnIHx8IHFzIGluc3RhbmNlb2YgU3RyaW5nKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHFzO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcmV0dXJuQXJyYXkgPSBbXTtcbiAgICAgICAgICAgICQuZWFjaChxcywgZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgICAgICAgICAgICAgICBpZiAoJC5pc0FycmF5KHZhbHVlKSkge1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IHZhbHVlLmpvaW4oJywnKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdCh2YWx1ZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgLy9Nb3N0bHkgZm9yIGRhdGEgYXBpXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gSlNPTi5zdHJpbmdpZnkodmFsdWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5BcnJheS5wdXNoKGtleSArICc9JyArIHZhbHVlKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gcmV0dXJuQXJyYXkuam9pbignJicpO1xuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVydHMgc3RyaW5ncyBvZiB0eXBlICdhPWImYj1jJyB0byB7IGE6YiwgYjpjfVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfSBxc1xuICAgICAgICAgKiBAcmV0dXJuIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBxc1RvT2JqZWN0OiBmdW5jdGlvbiAocXMpIHtcbiAgICAgICAgICAgIGlmIChxcyA9PT0gbnVsbCB8fCBxcyA9PT0gdW5kZWZpbmVkIHx8IHFzID09PSAnJykge1xuICAgICAgICAgICAgICAgIHJldHVybiB7fTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHFzQXJyYXkgPSBxcy5zcGxpdCgnJicpO1xuICAgICAgICAgICAgdmFyIHJldHVybk9iaiA9IHt9O1xuICAgICAgICAgICAgJC5lYWNoKHFzQXJyYXksIGZ1bmN0aW9uIChpbmRleCwgdmFsdWUpIHtcbiAgICAgICAgICAgICAgICB2YXIgcUtleSA9IHZhbHVlLnNwbGl0KCc9JylbMF07XG4gICAgICAgICAgICAgICAgdmFyIHFWYWwgPSB2YWx1ZS5zcGxpdCgnPScpWzFdO1xuXG4gICAgICAgICAgICAgICAgaWYgKHFWYWwuaW5kZXhPZignLCcpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICBxVmFsID0gcVZhbC5zcGxpdCgnLCcpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybk9ialtxS2V5XSA9IHFWYWw7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgcmV0dXJuIHJldHVybk9iajtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTm9ybWFsaXplcyBhbmQgbWVyZ2VzIHN0cmluZ3Mgb2YgdHlwZSAnYT1iJywgeyBiOmN9IHRvIHsgYTpiLCBiOmN9XG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8QXJyYXl8T2JqZWN0fSBxczFcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xBcnJheXxPYmplY3R9IHFzMlxuICAgICAgICAgKiBAcmV0dXJuIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBtZXJnZVFTOiBmdW5jdGlvbiAocXMxLCBxczIpIHtcbiAgICAgICAgICAgIHZhciBvYmoxID0gdGhpcy5xc1RvT2JqZWN0KHRoaXMudG9RdWVyeUZvcm1hdChxczEpKTtcbiAgICAgICAgICAgIHZhciBvYmoyID0gdGhpcy5xc1RvT2JqZWN0KHRoaXMudG9RdWVyeUZvcm1hdChxczIpKTtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCB7fSwgb2JqMSwgb2JqMik7XG4gICAgICAgIH0sXG5cbiAgICAgICAgYWRkVHJhaWxpbmdTbGFzaDogZnVuY3Rpb24gKHVybCkge1xuICAgICAgICAgICAgaWYgKCF1cmwpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJyc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gKHVybC5jaGFyQXQodXJsLmxlbmd0aCAtIDEpID09PSAnLycpID8gdXJsIDogKHVybCArICcvJyk7XG4gICAgICAgIH1cbiAgICB9O1xufSgpKTtcblxuXG5cbiIsIi8qKlxuICogVXRpbGl0aWVzIGZvciB3b3JraW5nIHdpdGggdGhlIHJ1biBzZXJ2aWNlXG4qL1xuJ3VzZSBzdHJpY3QnO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi9xdWVyeS11dGlsJyk7XG52YXIgTUFYX1VSTF9MRU5HVEggPSAyMDQ4O1xuXG5tb2R1bGUuZXhwb3J0cyA9IChmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIHJldHVybnMgb3BlcmF0aW9ucyBvZiB0aGUgZm9ybSBgW1tvcDEsb3AyXSwgW2FyZzEsIGFyZzJdXWBcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fEFycmF5fFN0cmluZ30gYG9wZXJhdGlvbnNgIG9wZXJhdGlvbnMgdG8gcGVyZm9ybVxuICAgICAgICAgKiBAcGFyYW0gIHtBcnJheX0gYGFyZ3NgIGFyZ3VtZW50cyBmb3Igb3BlcmF0aW9uXG4gICAgICAgICAqIEByZXR1cm4ge1N0cmluZ30gICAgTWF0cml4LWZvcm1hdCBxdWVyeSBwYXJhbWV0ZXJzXG4gICAgICAgICAqL1xuICAgICAgICBub3JtYWxpemVPcGVyYXRpb25zOiBmdW5jdGlvbiAob3BlcmF0aW9ucywgYXJncykge1xuICAgICAgICAgICAgaWYgKCFhcmdzKSB7XG4gICAgICAgICAgICAgICAgYXJncyA9IFtdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHJldHVybkxpc3QgPSB7XG4gICAgICAgICAgICAgICAgb3BzOiBbXSxcbiAgICAgICAgICAgICAgICBhcmdzOiBbXVxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIF9jb25jYXQgPSBmdW5jdGlvbiAoYXJyKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIChhcnIgIT09IG51bGwgJiYgYXJyICE9PSB1bmRlZmluZWQpID8gW10uY29uY2F0KGFycikgOiBbXTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIC8veyBhZGQ6IFsxLDJdLCBzdWJ0cmFjdDogWzIsNF0gfVxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVQbGFpbk9iamVjdHMgPSBmdW5jdGlvbiAob3BlcmF0aW9ucywgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIGlmICghcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0ID0geyBvcHM6IFtdLCBhcmdzOiBbXSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAkLmVhY2gob3BlcmF0aW9ucywgZnVuY3Rpb24gKG9wbiwgYXJnKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3Qub3BzLnB1c2gob3BuKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5hcmdzLnB1c2goX2NvbmNhdChhcmcpKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICAvL3sgbmFtZTogJ2FkZCcsIHBhcmFtczogWzFdIH1cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplU3RydWN0dXJlZE9iamVjdHMgPSBmdW5jdGlvbiAob3BlcmF0aW9uLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkxpc3Qub3BzLnB1c2gob3BlcmF0aW9uLm5hbWUpO1xuICAgICAgICAgICAgICAgIHJldHVybkxpc3QuYXJncy5wdXNoKF9jb25jYXQob3BlcmF0aW9uLnBhcmFtcykpO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVPYmplY3QgPSBmdW5jdGlvbiAob3BlcmF0aW9uLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICgob3BlcmF0aW9uLm5hbWUpID8gX25vcm1hbGl6ZVN0cnVjdHVyZWRPYmplY3RzIDogX25vcm1hbGl6ZVBsYWluT2JqZWN0cykob3BlcmF0aW9uLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplTGl0ZXJhbHMgPSBmdW5jdGlvbiAob3BlcmF0aW9uLCBhcmdzLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkxpc3Qub3BzLnB1c2gob3BlcmF0aW9uKTtcbiAgICAgICAgICAgICAgICByZXR1cm5MaXN0LmFyZ3MucHVzaChfY29uY2F0KGFyZ3MpKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgICAgIH07XG5cblxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVBcnJheXMgPSBmdW5jdGlvbiAob3BlcmF0aW9ucywgYXJnLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICQuZWFjaChvcGVyYXRpb25zLCBmdW5jdGlvbiAoaW5kZXgsIG9wbikge1xuICAgICAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KG9wbikpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIF9ub3JtYWxpemVPYmplY3Qob3BuLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIF9ub3JtYWxpemVMaXRlcmFscyhvcG4sIGFyZ3NbaW5kZXhdLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdChvcGVyYXRpb25zKSkge1xuICAgICAgICAgICAgICAgIF9ub3JtYWxpemVPYmplY3Qob3BlcmF0aW9ucywgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCQuaXNBcnJheShvcGVyYXRpb25zKSkge1xuICAgICAgICAgICAgICAgIF9ub3JtYWxpemVBcnJheXMob3BlcmF0aW9ucywgYXJncywgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIF9ub3JtYWxpemVMaXRlcmFscyhvcGVyYXRpb25zLCBhcmdzLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgIH0sXG5cbiAgICAgICAgc3BsaXRHZXRGYWN0b3J5OiBmdW5jdGlvbiAoaHR0cE9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgdmFyIGh0dHAgPSB0aGlzO1xuICAgICAgICAgICAgICAgIHZhciBnZXRWYWx1ZSA9IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciB2YWx1ZSA9IG9wdGlvbnNbbmFtZV0gfHwgaHR0cE9wdGlvbnNbbmFtZV07XG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gdmFsdWUoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB2YXIgZ2V0RmluYWxVcmwgPSBmdW5jdGlvbiAocGFyYW1zKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciB1cmwgPSBnZXRWYWx1ZSgndXJsJywgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBkYXRhID0gcGFyYW1zO1xuICAgICAgICAgICAgICAgICAgICAvLyBUaGVyZSBpcyBlYXN5IChvciBrbm93bikgd2F5IHRvIGdldCB0aGUgZmluYWwgVVJMIGpxdWVyeSBpcyBnb2luZyB0byBzZW5kIHNvXG4gICAgICAgICAgICAgICAgICAgIC8vIHdlJ3JlIHJlcGxpY2F0aW5nIGl0LiBUaGUgcHJvY2VzcyBtaWdodCBjaGFuZ2UgYXQgc29tZSBwb2ludCBidXQgaXQgcHJvYmFibHkgd2lsbCBub3QuXG4gICAgICAgICAgICAgICAgICAgIC8vIDEuIFJlbW92ZSBoYXNoXG4gICAgICAgICAgICAgICAgICAgIHVybCA9IHVybC5yZXBsYWNlKC8jLiokLywgJycpO1xuICAgICAgICAgICAgICAgICAgICAvLyAxLiBBcHBlbmQgcXVlcnkgc3RyaW5nXG4gICAgICAgICAgICAgICAgICAgIHZhciBxdWVyeVBhcmFtcyA9IHF1dGlsLnRvUXVlcnlGb3JtYXQoZGF0YSk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBxdWVzdGlvbklkeCA9IHVybC5pbmRleE9mKCc/Jyk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChxdWVyeVBhcmFtcyAmJiBxdWVzdGlvbklkeCA+IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdXJsICsgJyYnICsgcXVlcnlQYXJhbXM7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAocXVlcnlQYXJhbXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB1cmwgKyAnPycgKyBxdWVyeVBhcmFtcztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdXJsO1xuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdmFyIHVybCA9IGdldEZpbmFsVXJsKHBhcmFtcyk7XG4gICAgICAgICAgICAgICAgLy8gV2UgbXVzdCBzcGxpdCB0aGUgR0VUIGluIG11bHRpcGxlIHNob3J0IFVSTCdzXG4gICAgICAgICAgICAgICAgLy8gVGhlIG9ubHkgcHJvcGVydHkgYWxsb3dlZCB0byBiZSBzcGxpdCBpcyBcImluY2x1ZGVcIlxuICAgICAgICAgICAgICAgIGlmIChwYXJhbXMgJiYgcGFyYW1zLmluY2x1ZGUgJiYgdXJsLmxlbmd0aCA+IE1BWF9VUkxfTEVOR1RIKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBwYXJhbXNDb3B5ID0gJC5leHRlbmQodHJ1ZSwge30sIHBhcmFtcyk7XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBwYXJhbXNDb3B5LmluY2x1ZGU7XG4gICAgICAgICAgICAgICAgICAgIHZhciB1cmxOb0luY2x1ZGVzID0gZ2V0RmluYWxVcmwocGFyYW1zQ29weSk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBkaWZmID0gTUFYX1VSTF9MRU5HVEggLSB1cmxOb0luY2x1ZGVzLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBvcHRpb25zLnN1Y2Nlc3MgfHwgaHR0cE9wdGlvbnMuc3VjY2VzcyB8fCAkLm5vb3A7XG4gICAgICAgICAgICAgICAgICAgIHZhciBvbGRFcnJvciA9IG9wdGlvbnMuZXJyb3IgfHwgaHR0cE9wdGlvbnMuZXJyb3IgfHwgJC5ub29wO1xuICAgICAgICAgICAgICAgICAgICAvLyByZW1vdmUgdGhlIG9yaWdpbmFsIHN1Y2Nlc3MgYW5kIGVycm9yIGNhbGxiYWNrc1xuICAgICAgICAgICAgICAgICAgICBvcHRpb25zLnN1Y2Nlc3MgPSAkLm5vb3A7XG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuZXJyb3IgPSAkLm5vb3A7XG5cbiAgICAgICAgICAgICAgICAgICAgdmFyIGluY2x1ZGUgPSBwYXJhbXMuaW5jbHVkZTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGN1cnJJbmNsdWRlcyA9IFtdO1xuICAgICAgICAgICAgICAgICAgICB2YXIgaW5jbHVkZU9wdHMgPSBbY3VyckluY2x1ZGVzXTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGN1cnJMZW5ndGggPSAnP2luY2x1ZGU9Jy5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgIHZhciB2YXJpYWJsZSA9IGluY2x1ZGUucG9wKCk7XG4gICAgICAgICAgICAgICAgICAgIHdoaWxlICh2YXJpYWJsZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVXNlIGEgZ3JlZWR5IGFwcHJvYWNoIGZvciBub3csIGNhbiBiZSBvcHRpbWl6ZWQgdG8gYmUgc29sdmVkIGluIGEgbW9yZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZWZmaWNpZW50IHdheVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gKyAxIGlzIHRoZSBjb21tYVxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGN1cnJMZW5ndGggKyB2YXJpYWJsZS5sZW5ndGggKyAxIDwgZGlmZikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJJbmNsdWRlcy5wdXNoKHZhcmlhYmxlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyTGVuZ3RoICs9IHZhcmlhYmxlLmxlbmd0aCArIDE7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJJbmNsdWRlcyA9IFt2YXJpYWJsZV07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZU9wdHMucHVzaChjdXJySW5jbHVkZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJMZW5ndGggPSAnP2luY2x1ZGU9Jy5sZW5ndGggKyB2YXJpYWJsZS5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZSA9IGluY2x1ZGUucG9wKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgdmFyIHJlcXMgPSAkLm1hcChpbmNsdWRlT3B0cywgZnVuY3Rpb24gKGluY2x1ZGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciByZXFQYXJhbXMgPSAkLmV4dGVuZCh7fSwgcGFyYW1zLCB7IGluY2x1ZGU6IGluY2x1ZGUgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQocmVxUGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICQud2hlbi5hcHBseSgkLCByZXFzKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEVhY2ggYXJndW1lbnQgYXJlIGFycmF5cyBvZiB0aGUgYXJndW1lbnRzIG9mIGVhY2ggZG9uZSByZXF1ZXN0XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBTbyB0aGUgZmlyc3QgYXJndW1lbnQgb2YgdGhlIGZpcnN0IGFycmF5IG9mIGFyZ3VtZW50cyBpcyB0aGUgZGF0YVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGlzVmFsaWQgPSBhcmd1bWVudHNbMF0gJiYgYXJndW1lbnRzWzBdWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFpc1ZhbGlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2hvdWxkIG5ldmVyIGhhcHBlbi4uLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZEVycm9yKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBmaXJzdFJlc3BvbnNlID0gYXJndW1lbnRzWzBdWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGlzT2JqZWN0ID0gJC5pc1BsYWluT2JqZWN0KGZpcnN0UmVzcG9uc2UpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGlzUnVuQVBJID0gKGlzT2JqZWN0ICYmICQuaXNQbGFpbk9iamVjdChmaXJzdFJlc3BvbnNlLnZhcmlhYmxlcykpIHx8ICFpc09iamVjdDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpc1J1bkFQSSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpc09iamVjdCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhZ2dyZWdhdGUgdGhlIHZhcmlhYmxlcyBwcm9wZXJ0eSBvbmx5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVSdW4gPSBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChhcmd1bWVudHMsIGZ1bmN0aW9uIChpZHgsIGFyZ3MpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBydW4gPSBhcmdzWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5leHRlbmQodHJ1ZSwgYWdncmVnYXRlUnVuLnZhcmlhYmxlcywgcnVuLnZhcmlhYmxlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRTdWNjZXNzKGFnZ3JlZ2F0ZVJ1biwgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShhZ2dyZWdhdGVSdW4sIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhcnJheSBvZiBydW5zXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFncmVnYXRlIHZhcmlhYmxlcyBpbiBlYWNoIHJ1blxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgYWdncmVnYXRlZFJ1bnMgPSB7fTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJ1bnMgPSBhcmdzWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCEkLmlzQXJyYXkocnVucykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2gocnVucywgZnVuY3Rpb24gKGlkeFJ1biwgcnVuKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJ1bi5pZCAmJiAhYWdncmVnYXRlZFJ1bnNbcnVuLmlkXSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBydW4udmFyaWFibGVzID0gcnVuLnZhcmlhYmxlcyB8fCB7fTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdncmVnYXRlZFJ1bnNbcnVuLmlkXSA9IHJ1bjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHJ1bi5pZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmV4dGVuZCh0cnVlLCBhZ2dyZWdhdGVkUnVuc1tydW4uaWRdLnZhcmlhYmxlcywgcnVuLnZhcmlhYmxlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0dXJuIGl0IGludG8gYW4gYXJyYXlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdncmVnYXRlZFJ1bnMgPSAkLm1hcChhZ2dyZWdhdGVkUnVucywgZnVuY3Rpb24gKHJ1bikgeyByZXR1cm4gcnVuOyB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkU3VjY2VzcyhhZ2dyZWdhdGVkUnVucywgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShhZ2dyZWdhdGVkUnVucywgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaXMgdmFyaWFibGVzIEFQSVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFnZ3JlZ2F0ZSB0aGUgcmVzcG9uc2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgYWdncmVnYXRlZFZhcmlhYmxlcyA9IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChhcmd1bWVudHMsIGZ1bmN0aW9uIChpZHgsIGFyZ3MpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHZhcnMgPSBhcmdzWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmV4dGVuZCh0cnVlLCBhZ2dyZWdhdGVkVmFyaWFibGVzLCB2YXJzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRTdWNjZXNzKGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShhZ2dyZWdhdGVkVmFyaWFibGVzLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0sIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG9sZEVycm9yLmFwcGx5KGh0dHAsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBkdGQucmVqZWN0LmFwcGx5KGR0ZCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICB9O1xufSgpKTtcbiJdfQ== +//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9ncnVudC1icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvZ3J1bnQtYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvYmFzZTY0LWpzL2xpYi9iNjQuanMiLCJub2RlX21vZHVsZXMvZ3J1bnQtYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL25vZGVfbW9kdWxlcy9pZWVlNzU0L2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvaXMtYXJyYXkvaW5kZXguanMiLCJzcmMvYXBpLXZlcnNpb24uanNvbiIsInNyYy9hcHAuanMiLCJzcmMvbWFuYWdlcnMvYXV0aC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2NoYW5uZWwtbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2tleS1uYW1lcy5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9hbHdheXMtbmV3LXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2lkZW50aXR5LXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL211bHRpcGxheWVyLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9zdHJhdGVnaWVzLW1hcC5qcyIsInNyYy9tYW5hZ2Vycy9zY2VuYXJpby1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL3NwZWNpYWwtb3BlcmF0aW9ucy5qcyIsInNyYy9tYW5hZ2Vycy93b3JsZC1tYW5hZ2VyLmpzIiwic3JjL3NlcnZpY2UvYWRtaW4tZmlsZS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvYXNzZXQtYXBpLWFkYXB0ZXIuanMiLCJzcmMvc2VydmljZS9hdXRoLWFwaS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvZGF0YS1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3J1bi1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3N0YXRlLWFwaS1hZGFwdGVyLmpzIiwic3JjL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3ZhcmlhYmxlcy1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyLmpzIiwic3JjL3N0b3JlL2Nvb2tpZS1zdG9yZS5qcyIsInNyYy9zdG9yZS9zdG9yZS1mYWN0b3J5LmpzIiwic3JjL3RyYW5zcG9ydC9hamF4LWh0dHAtdHJhbnNwb3J0LmpzIiwic3JjL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5LmpzIiwic3JjL3V0aWwvaW5oZXJpdC5qcyIsInNyYy91dGlsL21ha2Utc2VxdWVuY2UuanMiLCJzcmMvdXRpbC9vYmplY3QtdXRpbC5qcyIsInNyYy91dGlsL3F1ZXJ5LXV0aWwuanMiLCJzcmMvdXRpbC9ydW4tdXRpbC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUN4Z0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDL0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNVdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6T0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6S0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdYQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwT0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdFFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4ZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6SkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM3VCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIi8qIVxuICogVGhlIGJ1ZmZlciBtb2R1bGUgZnJvbSBub2RlLmpzLCBmb3IgdGhlIGJyb3dzZXIuXG4gKlxuICogQGF1dGhvciAgIEZlcm9zcyBBYm91a2hhZGlqZWggPGZlcm9zc0BmZXJvc3Mub3JnPiA8aHR0cDovL2Zlcm9zcy5vcmc+XG4gKiBAbGljZW5zZSAgTUlUXG4gKi9cbi8qIGVzbGludC1kaXNhYmxlIG5vLXByb3RvICovXG5cbnZhciBiYXNlNjQgPSByZXF1aXJlKCdiYXNlNjQtanMnKVxudmFyIGllZWU3NTQgPSByZXF1aXJlKCdpZWVlNzU0JylcbnZhciBpc0FycmF5ID0gcmVxdWlyZSgnaXMtYXJyYXknKVxuXG5leHBvcnRzLkJ1ZmZlciA9IEJ1ZmZlclxuZXhwb3J0cy5TbG93QnVmZmVyID0gU2xvd0J1ZmZlclxuZXhwb3J0cy5JTlNQRUNUX01BWF9CWVRFUyA9IDUwXG5CdWZmZXIucG9vbFNpemUgPSA4MTkyIC8vIG5vdCB1c2VkIGJ5IHRoaXMgaW1wbGVtZW50YXRpb25cblxudmFyIHJvb3RQYXJlbnQgPSB7fVxuXG4vKipcbiAqIElmIGBCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVGA6XG4gKiAgID09PSB0cnVlICAgIFVzZSBVaW50OEFycmF5IGltcGxlbWVudGF0aW9uIChmYXN0ZXN0KVxuICogICA9PT0gZmFsc2UgICBVc2UgT2JqZWN0IGltcGxlbWVudGF0aW9uIChtb3N0IGNvbXBhdGlibGUsIGV2ZW4gSUU2KVxuICpcbiAqIEJyb3dzZXJzIHRoYXQgc3VwcG9ydCB0eXBlZCBhcnJheXMgYXJlIElFIDEwKywgRmlyZWZveCA0KywgQ2hyb21lIDcrLCBTYWZhcmkgNS4xKyxcbiAqIE9wZXJhIDExLjYrLCBpT1MgNC4yKy5cbiAqXG4gKiBEdWUgdG8gdmFyaW91cyBicm93c2VyIGJ1Z3MsIHNvbWV0aW1lcyB0aGUgT2JqZWN0IGltcGxlbWVudGF0aW9uIHdpbGwgYmUgdXNlZCBldmVuXG4gKiB3aGVuIHRoZSBicm93c2VyIHN1cHBvcnRzIHR5cGVkIGFycmF5cy5cbiAqXG4gKiBOb3RlOlxuICpcbiAqICAgLSBGaXJlZm94IDQtMjkgbGFja3Mgc3VwcG9ydCBmb3IgYWRkaW5nIG5ldyBwcm9wZXJ0aWVzIHRvIGBVaW50OEFycmF5YCBpbnN0YW5jZXMsXG4gKiAgICAgU2VlOiBodHRwczovL2J1Z3ppbGxhLm1vemlsbGEub3JnL3Nob3dfYnVnLmNnaT9pZD02OTU0MzguXG4gKlxuICogICAtIFNhZmFyaSA1LTcgbGFja3Mgc3VwcG9ydCBmb3IgY2hhbmdpbmcgdGhlIGBPYmplY3QucHJvdG90eXBlLmNvbnN0cnVjdG9yYCBwcm9wZXJ0eVxuICogICAgIG9uIG9iamVjdHMuXG4gKlxuICogICAtIENocm9tZSA5LTEwIGlzIG1pc3NpbmcgdGhlIGBUeXBlZEFycmF5LnByb3RvdHlwZS5zdWJhcnJheWAgZnVuY3Rpb24uXG4gKlxuICogICAtIElFMTAgaGFzIGEgYnJva2VuIGBUeXBlZEFycmF5LnByb3RvdHlwZS5zdWJhcnJheWAgZnVuY3Rpb24gd2hpY2ggcmV0dXJucyBhcnJheXMgb2ZcbiAqICAgICBpbmNvcnJlY3QgbGVuZ3RoIGluIHNvbWUgc2l0dWF0aW9ucy5cblxuICogV2UgZGV0ZWN0IHRoZXNlIGJ1Z2d5IGJyb3dzZXJzIGFuZCBzZXQgYEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUYCB0byBgZmFsc2VgIHNvIHRoZXlcbiAqIGdldCB0aGUgT2JqZWN0IGltcGxlbWVudGF0aW9uLCB3aGljaCBpcyBzbG93ZXIgYnV0IGJlaGF2ZXMgY29ycmVjdGx5LlxuICovXG5CdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCA9IGdsb2JhbC5UWVBFRF9BUlJBWV9TVVBQT1JUICE9PSB1bmRlZmluZWRcbiAgPyBnbG9iYWwuVFlQRURfQVJSQVlfU1VQUE9SVFxuICA6IHR5cGVkQXJyYXlTdXBwb3J0KClcblxuZnVuY3Rpb24gdHlwZWRBcnJheVN1cHBvcnQgKCkge1xuICBmdW5jdGlvbiBCYXIgKCkge31cbiAgdHJ5IHtcbiAgICB2YXIgYXJyID0gbmV3IFVpbnQ4QXJyYXkoMSlcbiAgICBhcnIuZm9vID0gZnVuY3Rpb24gKCkgeyByZXR1cm4gNDIgfVxuICAgIGFyci5jb25zdHJ1Y3RvciA9IEJhclxuICAgIHJldHVybiBhcnIuZm9vKCkgPT09IDQyICYmIC8vIHR5cGVkIGFycmF5IGluc3RhbmNlcyBjYW4gYmUgYXVnbWVudGVkXG4gICAgICAgIGFyci5jb25zdHJ1Y3RvciA9PT0gQmFyICYmIC8vIGNvbnN0cnVjdG9yIGNhbiBiZSBzZXRcbiAgICAgICAgdHlwZW9mIGFyci5zdWJhcnJheSA9PT0gJ2Z1bmN0aW9uJyAmJiAvLyBjaHJvbWUgOS0xMCBsYWNrIGBzdWJhcnJheWBcbiAgICAgICAgYXJyLnN1YmFycmF5KDEsIDEpLmJ5dGVMZW5ndGggPT09IDAgLy8gaWUxMCBoYXMgYnJva2VuIGBzdWJhcnJheWBcbiAgfSBjYXRjaCAoZSkge1xuICAgIHJldHVybiBmYWxzZVxuICB9XG59XG5cbmZ1bmN0aW9uIGtNYXhMZW5ndGggKCkge1xuICByZXR1cm4gQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRcbiAgICA/IDB4N2ZmZmZmZmZcbiAgICA6IDB4M2ZmZmZmZmZcbn1cblxuLyoqXG4gKiBDbGFzczogQnVmZmVyXG4gKiA9PT09PT09PT09PT09XG4gKlxuICogVGhlIEJ1ZmZlciBjb25zdHJ1Y3RvciByZXR1cm5zIGluc3RhbmNlcyBvZiBgVWludDhBcnJheWAgdGhhdCBhcmUgYXVnbWVudGVkXG4gKiB3aXRoIGZ1bmN0aW9uIHByb3BlcnRpZXMgZm9yIGFsbCB0aGUgbm9kZSBgQnVmZmVyYCBBUEkgZnVuY3Rpb25zLiBXZSB1c2VcbiAqIGBVaW50OEFycmF5YCBzbyB0aGF0IHNxdWFyZSBicmFja2V0IG5vdGF0aW9uIHdvcmtzIGFzIGV4cGVjdGVkIC0tIGl0IHJldHVybnNcbiAqIGEgc2luZ2xlIG9jdGV0LlxuICpcbiAqIEJ5IGF1Z21lbnRpbmcgdGhlIGluc3RhbmNlcywgd2UgY2FuIGF2b2lkIG1vZGlmeWluZyB0aGUgYFVpbnQ4QXJyYXlgXG4gKiBwcm90b3R5cGUuXG4gKi9cbmZ1bmN0aW9uIEJ1ZmZlciAoYXJnKSB7XG4gIGlmICghKHRoaXMgaW5zdGFuY2VvZiBCdWZmZXIpKSB7XG4gICAgLy8gQXZvaWQgZ29pbmcgdGhyb3VnaCBhbiBBcmd1bWVudHNBZGFwdG9yVHJhbXBvbGluZSBpbiB0aGUgY29tbW9uIGNhc2UuXG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxKSByZXR1cm4gbmV3IEJ1ZmZlcihhcmcsIGFyZ3VtZW50c1sxXSlcbiAgICByZXR1cm4gbmV3IEJ1ZmZlcihhcmcpXG4gIH1cblxuICB0aGlzLmxlbmd0aCA9IDBcbiAgdGhpcy5wYXJlbnQgPSB1bmRlZmluZWRcblxuICAvLyBDb21tb24gY2FzZS5cbiAgaWYgKHR5cGVvZiBhcmcgPT09ICdudW1iZXInKSB7XG4gICAgcmV0dXJuIGZyb21OdW1iZXIodGhpcywgYXJnKVxuICB9XG5cbiAgLy8gU2xpZ2h0bHkgbGVzcyBjb21tb24gY2FzZS5cbiAgaWYgKHR5cGVvZiBhcmcgPT09ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIGZyb21TdHJpbmcodGhpcywgYXJnLCBhcmd1bWVudHMubGVuZ3RoID4gMSA/IGFyZ3VtZW50c1sxXSA6ICd1dGY4JylcbiAgfVxuXG4gIC8vIFVudXN1YWwuXG4gIHJldHVybiBmcm9tT2JqZWN0KHRoaXMsIGFyZylcbn1cblxuZnVuY3Rpb24gZnJvbU51bWJlciAodGhhdCwgbGVuZ3RoKSB7XG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGggPCAwID8gMCA6IGNoZWNrZWQobGVuZ3RoKSB8IDApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICB0aGF0W2ldID0gMFxuICAgIH1cbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tU3RyaW5nICh0aGF0LCBzdHJpbmcsIGVuY29kaW5nKSB7XG4gIGlmICh0eXBlb2YgZW5jb2RpbmcgIT09ICdzdHJpbmcnIHx8IGVuY29kaW5nID09PSAnJykgZW5jb2RpbmcgPSAndXRmOCdcblxuICAvLyBBc3N1bXB0aW9uOiBieXRlTGVuZ3RoKCkgcmV0dXJuIHZhbHVlIGlzIGFsd2F5cyA8IGtNYXhMZW5ndGguXG4gIHZhciBsZW5ndGggPSBieXRlTGVuZ3RoKHN0cmluZywgZW5jb2RpbmcpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuXG4gIHRoYXQud3JpdGUoc3RyaW5nLCBlbmNvZGluZylcbiAgcmV0dXJuIHRoYXRcbn1cblxuZnVuY3Rpb24gZnJvbU9iamVjdCAodGhhdCwgb2JqZWN0KSB7XG4gIGlmIChCdWZmZXIuaXNCdWZmZXIob2JqZWN0KSkgcmV0dXJuIGZyb21CdWZmZXIodGhhdCwgb2JqZWN0KVxuXG4gIGlmIChpc0FycmF5KG9iamVjdCkpIHJldHVybiBmcm9tQXJyYXkodGhhdCwgb2JqZWN0KVxuXG4gIGlmIChvYmplY3QgPT0gbnVsbCkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ211c3Qgc3RhcnQgd2l0aCBudW1iZXIsIGJ1ZmZlciwgYXJyYXkgb3Igc3RyaW5nJylcbiAgfVxuXG4gIGlmICh0eXBlb2YgQXJyYXlCdWZmZXIgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgaWYgKG9iamVjdC5idWZmZXIgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikge1xuICAgICAgcmV0dXJuIGZyb21UeXBlZEFycmF5KHRoYXQsIG9iamVjdClcbiAgICB9XG4gICAgaWYgKG9iamVjdCBpbnN0YW5jZW9mIEFycmF5QnVmZmVyKSB7XG4gICAgICByZXR1cm4gZnJvbUFycmF5QnVmZmVyKHRoYXQsIG9iamVjdClcbiAgICB9XG4gIH1cblxuICBpZiAob2JqZWN0Lmxlbmd0aCkgcmV0dXJuIGZyb21BcnJheUxpa2UodGhhdCwgb2JqZWN0KVxuXG4gIHJldHVybiBmcm9tSnNvbk9iamVjdCh0aGF0LCBvYmplY3QpXG59XG5cbmZ1bmN0aW9uIGZyb21CdWZmZXIgKHRoYXQsIGJ1ZmZlcikge1xuICB2YXIgbGVuZ3RoID0gY2hlY2tlZChidWZmZXIubGVuZ3RoKSB8IDBcbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aClcbiAgYnVmZmVyLmNvcHkodGhhdCwgMCwgMCwgbGVuZ3RoKVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tQXJyYXkgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGF0W2ldID0gYXJyYXlbaV0gJiAyNTVcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG4vLyBEdXBsaWNhdGUgb2YgZnJvbUFycmF5KCkgdG8ga2VlcCBmcm9tQXJyYXkoKSBtb25vbW9ycGhpYy5cbmZ1bmN0aW9uIGZyb21UeXBlZEFycmF5ICh0aGF0LCBhcnJheSkge1xuICB2YXIgbGVuZ3RoID0gY2hlY2tlZChhcnJheS5sZW5ndGgpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuICAvLyBUcnVuY2F0aW5nIHRoZSBlbGVtZW50cyBpcyBwcm9iYWJseSBub3Qgd2hhdCBwZW9wbGUgZXhwZWN0IGZyb20gdHlwZWRcbiAgLy8gYXJyYXlzIHdpdGggQllURVNfUEVSX0VMRU1FTlQgPiAxIGJ1dCBpdCdzIGNvbXBhdGlibGUgd2l0aCB0aGUgYmVoYXZpb3JcbiAgLy8gb2YgdGhlIG9sZCBCdWZmZXIgY29uc3RydWN0b3IuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGF0W2ldID0gYXJyYXlbaV0gJiAyNTVcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tQXJyYXlCdWZmZXIgKHRoYXQsIGFycmF5KSB7XG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIC8vIFJldHVybiBhbiBhdWdtZW50ZWQgYFVpbnQ4QXJyYXlgIGluc3RhbmNlLCBmb3IgYmVzdCBwZXJmb3JtYW5jZVxuICAgIGFycmF5LmJ5dGVMZW5ndGhcbiAgICB0aGF0ID0gQnVmZmVyLl9hdWdtZW50KG5ldyBVaW50OEFycmF5KGFycmF5KSlcbiAgfSBlbHNlIHtcbiAgICAvLyBGYWxsYmFjazogUmV0dXJuIGFuIG9iamVjdCBpbnN0YW5jZSBvZiB0aGUgQnVmZmVyIGNsYXNzXG4gICAgdGhhdCA9IGZyb21UeXBlZEFycmF5KHRoYXQsIG5ldyBVaW50OEFycmF5KGFycmF5KSlcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tQXJyYXlMaWtlICh0aGF0LCBhcnJheSkge1xuICB2YXIgbGVuZ3RoID0gY2hlY2tlZChhcnJheS5sZW5ndGgpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSArPSAxKSB7XG4gICAgdGhhdFtpXSA9IGFycmF5W2ldICYgMjU1XG4gIH1cbiAgcmV0dXJuIHRoYXRcbn1cblxuLy8gRGVzZXJpYWxpemUgeyB0eXBlOiAnQnVmZmVyJywgZGF0YTogWzEsMiwzLC4uLl0gfSBpbnRvIGEgQnVmZmVyIG9iamVjdC5cbi8vIFJldHVybnMgYSB6ZXJvLWxlbmd0aCBidWZmZXIgZm9yIGlucHV0cyB0aGF0IGRvbid0IGNvbmZvcm0gdG8gdGhlIHNwZWMuXG5mdW5jdGlvbiBmcm9tSnNvbk9iamVjdCAodGhhdCwgb2JqZWN0KSB7XG4gIHZhciBhcnJheVxuICB2YXIgbGVuZ3RoID0gMFxuXG4gIGlmIChvYmplY3QudHlwZSA9PT0gJ0J1ZmZlcicgJiYgaXNBcnJheShvYmplY3QuZGF0YSkpIHtcbiAgICBhcnJheSA9IG9iamVjdC5kYXRhXG4gICAgbGVuZ3RoID0gY2hlY2tlZChhcnJheS5sZW5ndGgpIHwgMFxuICB9XG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoYXRbaV0gPSBhcnJheVtpXSAmIDI1NVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICBCdWZmZXIucHJvdG90eXBlLl9fcHJvdG9fXyA9IFVpbnQ4QXJyYXkucHJvdG90eXBlXG4gIEJ1ZmZlci5fX3Byb3RvX18gPSBVaW50OEFycmF5XG59XG5cbmZ1bmN0aW9uIGFsbG9jYXRlICh0aGF0LCBsZW5ndGgpIHtcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gUmV0dXJuIGFuIGF1Z21lbnRlZCBgVWludDhBcnJheWAgaW5zdGFuY2UsIGZvciBiZXN0IHBlcmZvcm1hbmNlXG4gICAgdGhhdCA9IEJ1ZmZlci5fYXVnbWVudChuZXcgVWludDhBcnJheShsZW5ndGgpKVxuICAgIHRoYXQuX19wcm90b19fID0gQnVmZmVyLnByb3RvdHlwZVxuICB9IGVsc2Uge1xuICAgIC8vIEZhbGxiYWNrOiBSZXR1cm4gYW4gb2JqZWN0IGluc3RhbmNlIG9mIHRoZSBCdWZmZXIgY2xhc3NcbiAgICB0aGF0Lmxlbmd0aCA9IGxlbmd0aFxuICAgIHRoYXQuX2lzQnVmZmVyID0gdHJ1ZVxuICB9XG5cbiAgdmFyIGZyb21Qb29sID0gbGVuZ3RoICE9PSAwICYmIGxlbmd0aCA8PSBCdWZmZXIucG9vbFNpemUgPj4+IDFcbiAgaWYgKGZyb21Qb29sKSB0aGF0LnBhcmVudCA9IHJvb3RQYXJlbnRcblxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBjaGVja2VkIChsZW5ndGgpIHtcbiAgLy8gTm90ZTogY2Fubm90IHVzZSBgbGVuZ3RoIDwga01heExlbmd0aGAgaGVyZSBiZWNhdXNlIHRoYXQgZmFpbHMgd2hlblxuICAvLyBsZW5ndGggaXMgTmFOICh3aGljaCBpcyBvdGhlcndpc2UgY29lcmNlZCB0byB6ZXJvLilcbiAgaWYgKGxlbmd0aCA+PSBrTWF4TGVuZ3RoKCkpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignQXR0ZW1wdCB0byBhbGxvY2F0ZSBCdWZmZXIgbGFyZ2VyIHRoYW4gbWF4aW11bSAnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAnc2l6ZTogMHgnICsga01heExlbmd0aCgpLnRvU3RyaW5nKDE2KSArICcgYnl0ZXMnKVxuICB9XG4gIHJldHVybiBsZW5ndGggfCAwXG59XG5cbmZ1bmN0aW9uIFNsb3dCdWZmZXIgKHN1YmplY3QsIGVuY29kaW5nKSB7XG4gIGlmICghKHRoaXMgaW5zdGFuY2VvZiBTbG93QnVmZmVyKSkgcmV0dXJuIG5ldyBTbG93QnVmZmVyKHN1YmplY3QsIGVuY29kaW5nKVxuXG4gIHZhciBidWYgPSBuZXcgQnVmZmVyKHN1YmplY3QsIGVuY29kaW5nKVxuICBkZWxldGUgYnVmLnBhcmVudFxuICByZXR1cm4gYnVmXG59XG5cbkJ1ZmZlci5pc0J1ZmZlciA9IGZ1bmN0aW9uIGlzQnVmZmVyIChiKSB7XG4gIHJldHVybiAhIShiICE9IG51bGwgJiYgYi5faXNCdWZmZXIpXG59XG5cbkJ1ZmZlci5jb21wYXJlID0gZnVuY3Rpb24gY29tcGFyZSAoYSwgYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihhKSB8fCAhQnVmZmVyLmlzQnVmZmVyKGIpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnRzIG11c3QgYmUgQnVmZmVycycpXG4gIH1cblxuICBpZiAoYSA9PT0gYikgcmV0dXJuIDBcblxuICB2YXIgeCA9IGEubGVuZ3RoXG4gIHZhciB5ID0gYi5sZW5ndGhcblxuICB2YXIgaSA9IDBcbiAgdmFyIGxlbiA9IE1hdGgubWluKHgsIHkpXG4gIHdoaWxlIChpIDwgbGVuKSB7XG4gICAgaWYgKGFbaV0gIT09IGJbaV0pIGJyZWFrXG5cbiAgICArK2lcbiAgfVxuXG4gIGlmIChpICE9PSBsZW4pIHtcbiAgICB4ID0gYVtpXVxuICAgIHkgPSBiW2ldXG4gIH1cblxuICBpZiAoeCA8IHkpIHJldHVybiAtMVxuICBpZiAoeSA8IHgpIHJldHVybiAxXG4gIHJldHVybiAwXG59XG5cbkJ1ZmZlci5pc0VuY29kaW5nID0gZnVuY3Rpb24gaXNFbmNvZGluZyAoZW5jb2RpbmcpIHtcbiAgc3dpdGNoIChTdHJpbmcoZW5jb2RpbmcpLnRvTG93ZXJDYXNlKCkpIHtcbiAgICBjYXNlICdoZXgnOlxuICAgIGNhc2UgJ3V0ZjgnOlxuICAgIGNhc2UgJ3V0Zi04JzpcbiAgICBjYXNlICdhc2NpaSc6XG4gICAgY2FzZSAnYmluYXJ5JzpcbiAgICBjYXNlICdiYXNlNjQnOlxuICAgIGNhc2UgJ3Jhdyc6XG4gICAgY2FzZSAndWNzMic6XG4gICAgY2FzZSAndWNzLTInOlxuICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgIHJldHVybiB0cnVlXG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBmYWxzZVxuICB9XG59XG5cbkJ1ZmZlci5jb25jYXQgPSBmdW5jdGlvbiBjb25jYXQgKGxpc3QsIGxlbmd0aCkge1xuICBpZiAoIWlzQXJyYXkobGlzdCkpIHRocm93IG5ldyBUeXBlRXJyb3IoJ2xpc3QgYXJndW1lbnQgbXVzdCBiZSBhbiBBcnJheSBvZiBCdWZmZXJzLicpXG5cbiAgaWYgKGxpc3QubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIG5ldyBCdWZmZXIoMClcbiAgfVxuXG4gIHZhciBpXG4gIGlmIChsZW5ndGggPT09IHVuZGVmaW5lZCkge1xuICAgIGxlbmd0aCA9IDBcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGlzdC5sZW5ndGg7IGkrKykge1xuICAgICAgbGVuZ3RoICs9IGxpc3RbaV0ubGVuZ3RoXG4gICAgfVxuICB9XG5cbiAgdmFyIGJ1ZiA9IG5ldyBCdWZmZXIobGVuZ3RoKVxuICB2YXIgcG9zID0gMFxuICBmb3IgKGkgPSAwOyBpIDwgbGlzdC5sZW5ndGg7IGkrKykge1xuICAgIHZhciBpdGVtID0gbGlzdFtpXVxuICAgIGl0ZW0uY29weShidWYsIHBvcylcbiAgICBwb3MgKz0gaXRlbS5sZW5ndGhcbiAgfVxuICByZXR1cm4gYnVmXG59XG5cbmZ1bmN0aW9uIGJ5dGVMZW5ndGggKHN0cmluZywgZW5jb2RpbmcpIHtcbiAgaWYgKHR5cGVvZiBzdHJpbmcgIT09ICdzdHJpbmcnKSBzdHJpbmcgPSAnJyArIHN0cmluZ1xuXG4gIHZhciBsZW4gPSBzdHJpbmcubGVuZ3RoXG4gIGlmIChsZW4gPT09IDApIHJldHVybiAwXG5cbiAgLy8gVXNlIGEgZm9yIGxvb3AgdG8gYXZvaWQgcmVjdXJzaW9uXG4gIHZhciBsb3dlcmVkQ2FzZSA9IGZhbHNlXG4gIGZvciAoOzspIHtcbiAgICBzd2l0Y2ggKGVuY29kaW5nKSB7XG4gICAgICBjYXNlICdhc2NpaSc6XG4gICAgICBjYXNlICdiaW5hcnknOlxuICAgICAgLy8gRGVwcmVjYXRlZFxuICAgICAgY2FzZSAncmF3JzpcbiAgICAgIGNhc2UgJ3Jhd3MnOlxuICAgICAgICByZXR1cm4gbGVuXG4gICAgICBjYXNlICd1dGY4JzpcbiAgICAgIGNhc2UgJ3V0Zi04JzpcbiAgICAgICAgcmV0dXJuIHV0ZjhUb0J5dGVzKHN0cmluZykubGVuZ3RoXG4gICAgICBjYXNlICd1Y3MyJzpcbiAgICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgICByZXR1cm4gbGVuICogMlxuICAgICAgY2FzZSAnaGV4JzpcbiAgICAgICAgcmV0dXJuIGxlbiA+Pj4gMVxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgcmV0dXJuIGJhc2U2NFRvQnl0ZXMoc3RyaW5nKS5sZW5ndGhcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGlmIChsb3dlcmVkQ2FzZSkgcmV0dXJuIHV0ZjhUb0J5dGVzKHN0cmluZykubGVuZ3RoIC8vIGFzc3VtZSB1dGY4XG4gICAgICAgIGVuY29kaW5nID0gKCcnICsgZW5jb2RpbmcpLnRvTG93ZXJDYXNlKClcbiAgICAgICAgbG93ZXJlZENhc2UgPSB0cnVlXG4gICAgfVxuICB9XG59XG5CdWZmZXIuYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGhcblxuLy8gcHJlLXNldCBmb3IgdmFsdWVzIHRoYXQgbWF5IGV4aXN0IGluIHRoZSBmdXR1cmVcbkJ1ZmZlci5wcm90b3R5cGUubGVuZ3RoID0gdW5kZWZpbmVkXG5CdWZmZXIucHJvdG90eXBlLnBhcmVudCA9IHVuZGVmaW5lZFxuXG5mdW5jdGlvbiBzbG93VG9TdHJpbmcgKGVuY29kaW5nLCBzdGFydCwgZW5kKSB7XG4gIHZhciBsb3dlcmVkQ2FzZSA9IGZhbHNlXG5cbiAgc3RhcnQgPSBzdGFydCB8IDBcbiAgZW5kID0gZW5kID09PSB1bmRlZmluZWQgfHwgZW5kID09PSBJbmZpbml0eSA/IHRoaXMubGVuZ3RoIDogZW5kIHwgMFxuXG4gIGlmICghZW5jb2RpbmcpIGVuY29kaW5nID0gJ3V0ZjgnXG4gIGlmIChzdGFydCA8IDApIHN0YXJ0ID0gMFxuICBpZiAoZW5kID4gdGhpcy5sZW5ndGgpIGVuZCA9IHRoaXMubGVuZ3RoXG4gIGlmIChlbmQgPD0gc3RhcnQpIHJldHVybiAnJ1xuXG4gIHdoaWxlICh0cnVlKSB7XG4gICAgc3dpdGNoIChlbmNvZGluZykge1xuICAgICAgY2FzZSAnaGV4JzpcbiAgICAgICAgcmV0dXJuIGhleFNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgICByZXR1cm4gdXRmOFNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgICAgcmV0dXJuIGFzY2lpU2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnYmluYXJ5JzpcbiAgICAgICAgcmV0dXJuIGJpbmFyeVNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgICAgIHJldHVybiBiYXNlNjRTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICd1Y3MyJzpcbiAgICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgICByZXR1cm4gdXRmMTZsZVNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGlmIChsb3dlcmVkQ2FzZSkgdGhyb3cgbmV3IFR5cGVFcnJvcignVW5rbm93biBlbmNvZGluZzogJyArIGVuY29kaW5nKVxuICAgICAgICBlbmNvZGluZyA9IChlbmNvZGluZyArICcnKS50b0xvd2VyQ2FzZSgpXG4gICAgICAgIGxvd2VyZWRDYXNlID0gdHJ1ZVxuICAgIH1cbiAgfVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnRvU3RyaW5nID0gZnVuY3Rpb24gdG9TdHJpbmcgKCkge1xuICB2YXIgbGVuZ3RoID0gdGhpcy5sZW5ndGggfCAwXG4gIGlmIChsZW5ndGggPT09IDApIHJldHVybiAnJ1xuICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHV0ZjhTbGljZSh0aGlzLCAwLCBsZW5ndGgpXG4gIHJldHVybiBzbG93VG9TdHJpbmcuYXBwbHkodGhpcywgYXJndW1lbnRzKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLmVxdWFscyA9IGZ1bmN0aW9uIGVxdWFscyAoYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihiKSkgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnQgbXVzdCBiZSBhIEJ1ZmZlcicpXG4gIGlmICh0aGlzID09PSBiKSByZXR1cm4gdHJ1ZVxuICByZXR1cm4gQnVmZmVyLmNvbXBhcmUodGhpcywgYikgPT09IDBcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5pbnNwZWN0ID0gZnVuY3Rpb24gaW5zcGVjdCAoKSB7XG4gIHZhciBzdHIgPSAnJ1xuICB2YXIgbWF4ID0gZXhwb3J0cy5JTlNQRUNUX01BWF9CWVRFU1xuICBpZiAodGhpcy5sZW5ndGggPiAwKSB7XG4gICAgc3RyID0gdGhpcy50b1N0cmluZygnaGV4JywgMCwgbWF4KS5tYXRjaCgvLnsyfS9nKS5qb2luKCcgJylcbiAgICBpZiAodGhpcy5sZW5ndGggPiBtYXgpIHN0ciArPSAnIC4uLiAnXG4gIH1cbiAgcmV0dXJuICc8QnVmZmVyICcgKyBzdHIgKyAnPidcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5jb21wYXJlID0gZnVuY3Rpb24gY29tcGFyZSAoYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihiKSkgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnQgbXVzdCBiZSBhIEJ1ZmZlcicpXG4gIGlmICh0aGlzID09PSBiKSByZXR1cm4gMFxuICByZXR1cm4gQnVmZmVyLmNvbXBhcmUodGhpcywgYilcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5pbmRleE9mID0gZnVuY3Rpb24gaW5kZXhPZiAodmFsLCBieXRlT2Zmc2V0KSB7XG4gIGlmIChieXRlT2Zmc2V0ID4gMHg3ZmZmZmZmZikgYnl0ZU9mZnNldCA9IDB4N2ZmZmZmZmZcbiAgZWxzZSBpZiAoYnl0ZU9mZnNldCA8IC0weDgwMDAwMDAwKSBieXRlT2Zmc2V0ID0gLTB4ODAwMDAwMDBcbiAgYnl0ZU9mZnNldCA+Pj0gMFxuXG4gIGlmICh0aGlzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIC0xXG4gIGlmIChieXRlT2Zmc2V0ID49IHRoaXMubGVuZ3RoKSByZXR1cm4gLTFcblxuICAvLyBOZWdhdGl2ZSBvZmZzZXRzIHN0YXJ0IGZyb20gdGhlIGVuZCBvZiB0aGUgYnVmZmVyXG4gIGlmIChieXRlT2Zmc2V0IDwgMCkgYnl0ZU9mZnNldCA9IE1hdGgubWF4KHRoaXMubGVuZ3RoICsgYnl0ZU9mZnNldCwgMClcblxuICBpZiAodHlwZW9mIHZhbCA9PT0gJ3N0cmluZycpIHtcbiAgICBpZiAodmFsLmxlbmd0aCA9PT0gMCkgcmV0dXJuIC0xIC8vIHNwZWNpYWwgY2FzZTogbG9va2luZyBmb3IgZW1wdHkgc3RyaW5nIGFsd2F5cyBmYWlsc1xuICAgIHJldHVybiBTdHJpbmcucHJvdG90eXBlLmluZGV4T2YuY2FsbCh0aGlzLCB2YWwsIGJ5dGVPZmZzZXQpXG4gIH1cbiAgaWYgKEJ1ZmZlci5pc0J1ZmZlcih2YWwpKSB7XG4gICAgcmV0dXJuIGFycmF5SW5kZXhPZih0aGlzLCB2YWwsIGJ5dGVPZmZzZXQpXG4gIH1cbiAgaWYgKHR5cGVvZiB2YWwgPT09ICdudW1iZXInKSB7XG4gICAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUICYmIFVpbnQ4QXJyYXkucHJvdG90eXBlLmluZGV4T2YgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIHJldHVybiBVaW50OEFycmF5LnByb3RvdHlwZS5pbmRleE9mLmNhbGwodGhpcywgdmFsLCBieXRlT2Zmc2V0KVxuICAgIH1cbiAgICByZXR1cm4gYXJyYXlJbmRleE9mKHRoaXMsIFsgdmFsIF0sIGJ5dGVPZmZzZXQpXG4gIH1cblxuICBmdW5jdGlvbiBhcnJheUluZGV4T2YgKGFyciwgdmFsLCBieXRlT2Zmc2V0KSB7XG4gICAgdmFyIGZvdW5kSW5kZXggPSAtMVxuICAgIGZvciAodmFyIGkgPSAwOyBieXRlT2Zmc2V0ICsgaSA8IGFyci5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKGFycltieXRlT2Zmc2V0ICsgaV0gPT09IHZhbFtmb3VuZEluZGV4ID09PSAtMSA/IDAgOiBpIC0gZm91bmRJbmRleF0pIHtcbiAgICAgICAgaWYgKGZvdW5kSW5kZXggPT09IC0xKSBmb3VuZEluZGV4ID0gaVxuICAgICAgICBpZiAoaSAtIGZvdW5kSW5kZXggKyAxID09PSB2YWwubGVuZ3RoKSByZXR1cm4gYnl0ZU9mZnNldCArIGZvdW5kSW5kZXhcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGZvdW5kSW5kZXggPSAtMVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gLTFcbiAgfVxuXG4gIHRocm93IG5ldyBUeXBlRXJyb3IoJ3ZhbCBtdXN0IGJlIHN0cmluZywgbnVtYmVyIG9yIEJ1ZmZlcicpXG59XG5cbi8vIGBnZXRgIGlzIGRlcHJlY2F0ZWRcbkJ1ZmZlci5wcm90b3R5cGUuZ2V0ID0gZnVuY3Rpb24gZ2V0IChvZmZzZXQpIHtcbiAgY29uc29sZS5sb2coJy5nZXQoKSBpcyBkZXByZWNhdGVkLiBBY2Nlc3MgdXNpbmcgYXJyYXkgaW5kZXhlcyBpbnN0ZWFkLicpXG4gIHJldHVybiB0aGlzLnJlYWRVSW50OChvZmZzZXQpXG59XG5cbi8vIGBzZXRgIGlzIGRlcHJlY2F0ZWRcbkJ1ZmZlci5wcm90b3R5cGUuc2V0ID0gZnVuY3Rpb24gc2V0ICh2LCBvZmZzZXQpIHtcbiAgY29uc29sZS5sb2coJy5zZXQoKSBpcyBkZXByZWNhdGVkLiBBY2Nlc3MgdXNpbmcgYXJyYXkgaW5kZXhlcyBpbnN0ZWFkLicpXG4gIHJldHVybiB0aGlzLndyaXRlVUludDgodiwgb2Zmc2V0KVxufVxuXG5mdW5jdGlvbiBoZXhXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIG9mZnNldCA9IE51bWJlcihvZmZzZXQpIHx8IDBcbiAgdmFyIHJlbWFpbmluZyA9IGJ1Zi5sZW5ndGggLSBvZmZzZXRcbiAgaWYgKCFsZW5ndGgpIHtcbiAgICBsZW5ndGggPSByZW1haW5pbmdcbiAgfSBlbHNlIHtcbiAgICBsZW5ndGggPSBOdW1iZXIobGVuZ3RoKVxuICAgIGlmIChsZW5ndGggPiByZW1haW5pbmcpIHtcbiAgICAgIGxlbmd0aCA9IHJlbWFpbmluZ1xuICAgIH1cbiAgfVxuXG4gIC8vIG11c3QgYmUgYW4gZXZlbiBudW1iZXIgb2YgZGlnaXRzXG4gIHZhciBzdHJMZW4gPSBzdHJpbmcubGVuZ3RoXG4gIGlmIChzdHJMZW4gJSAyICE9PSAwKSB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgaGV4IHN0cmluZycpXG5cbiAgaWYgKGxlbmd0aCA+IHN0ckxlbiAvIDIpIHtcbiAgICBsZW5ndGggPSBzdHJMZW4gLyAyXG4gIH1cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgIHZhciBwYXJzZWQgPSBwYXJzZUludChzdHJpbmcuc3Vic3RyKGkgKiAyLCAyKSwgMTYpXG4gICAgaWYgKGlzTmFOKHBhcnNlZCkpIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBoZXggc3RyaW5nJylcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSBwYXJzZWRcbiAgfVxuICByZXR1cm4gaVxufVxuXG5mdW5jdGlvbiB1dGY4V3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcih1dGY4VG9CeXRlcyhzdHJpbmcsIGJ1Zi5sZW5ndGggLSBvZmZzZXQpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiBhc2NpaVdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIoYXNjaWlUb0J5dGVzKHN0cmluZyksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIGJpbmFyeVdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGFzY2lpV3JpdGUoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiBiYXNlNjRXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKGJhc2U2NFRvQnl0ZXMoc3RyaW5nKSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gdWNzMldyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIodXRmMTZsZVRvQnl0ZXMoc3RyaW5nLCBidWYubGVuZ3RoIC0gb2Zmc2V0KSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZSA9IGZ1bmN0aW9uIHdyaXRlIChzdHJpbmcsIG9mZnNldCwgbGVuZ3RoLCBlbmNvZGluZykge1xuICAvLyBCdWZmZXIjd3JpdGUoc3RyaW5nKVxuICBpZiAob2Zmc2V0ID09PSB1bmRlZmluZWQpIHtcbiAgICBlbmNvZGluZyA9ICd1dGY4J1xuICAgIGxlbmd0aCA9IHRoaXMubGVuZ3RoXG4gICAgb2Zmc2V0ID0gMFxuICAvLyBCdWZmZXIjd3JpdGUoc3RyaW5nLCBlbmNvZGluZylcbiAgfSBlbHNlIGlmIChsZW5ndGggPT09IHVuZGVmaW5lZCAmJiB0eXBlb2Ygb2Zmc2V0ID09PSAnc3RyaW5nJykge1xuICAgIGVuY29kaW5nID0gb2Zmc2V0XG4gICAgbGVuZ3RoID0gdGhpcy5sZW5ndGhcbiAgICBvZmZzZXQgPSAwXG4gIC8vIEJ1ZmZlciN3cml0ZShzdHJpbmcsIG9mZnNldFssIGxlbmd0aF1bLCBlbmNvZGluZ10pXG4gIH0gZWxzZSBpZiAoaXNGaW5pdGUob2Zmc2V0KSkge1xuICAgIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgICBpZiAoaXNGaW5pdGUobGVuZ3RoKSkge1xuICAgICAgbGVuZ3RoID0gbGVuZ3RoIHwgMFxuICAgICAgaWYgKGVuY29kaW5nID09PSB1bmRlZmluZWQpIGVuY29kaW5nID0gJ3V0ZjgnXG4gICAgfSBlbHNlIHtcbiAgICAgIGVuY29kaW5nID0gbGVuZ3RoXG4gICAgICBsZW5ndGggPSB1bmRlZmluZWRcbiAgICB9XG4gIC8vIGxlZ2FjeSB3cml0ZShzdHJpbmcsIGVuY29kaW5nLCBvZmZzZXQsIGxlbmd0aCkgLSByZW1vdmUgaW4gdjAuMTNcbiAgfSBlbHNlIHtcbiAgICB2YXIgc3dhcCA9IGVuY29kaW5nXG4gICAgZW5jb2RpbmcgPSBvZmZzZXRcbiAgICBvZmZzZXQgPSBsZW5ndGggfCAwXG4gICAgbGVuZ3RoID0gc3dhcFxuICB9XG5cbiAgdmFyIHJlbWFpbmluZyA9IHRoaXMubGVuZ3RoIC0gb2Zmc2V0XG4gIGlmIChsZW5ndGggPT09IHVuZGVmaW5lZCB8fCBsZW5ndGggPiByZW1haW5pbmcpIGxlbmd0aCA9IHJlbWFpbmluZ1xuXG4gIGlmICgoc3RyaW5nLmxlbmd0aCA+IDAgJiYgKGxlbmd0aCA8IDAgfHwgb2Zmc2V0IDwgMCkpIHx8IG9mZnNldCA+IHRoaXMubGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2F0dGVtcHQgdG8gd3JpdGUgb3V0c2lkZSBidWZmZXIgYm91bmRzJylcbiAgfVxuXG4gIGlmICghZW5jb2RpbmcpIGVuY29kaW5nID0gJ3V0ZjgnXG5cbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcbiAgZm9yICg7Oykge1xuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgIGNhc2UgJ2hleCc6XG4gICAgICAgIHJldHVybiBoZXhXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICd1dGY4JzpcbiAgICAgIGNhc2UgJ3V0Zi04JzpcbiAgICAgICAgcmV0dXJuIHV0ZjhXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICdhc2NpaSc6XG4gICAgICAgIHJldHVybiBhc2NpaVdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICAgIHJldHVybiBiaW5hcnlXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICdiYXNlNjQnOlxuICAgICAgICAvLyBXYXJuaW5nOiBtYXhMZW5ndGggbm90IHRha2VuIGludG8gYWNjb3VudCBpbiBiYXNlNjRXcml0ZVxuICAgICAgICByZXR1cm4gYmFzZTY0V3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAndWNzMic6XG4gICAgICBjYXNlICd1Y3MtMic6XG4gICAgICBjYXNlICd1dGYxNmxlJzpcbiAgICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgICAgcmV0dXJuIHVjczJXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBpZiAobG93ZXJlZENhc2UpIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Vua25vd24gZW5jb2Rpbmc6ICcgKyBlbmNvZGluZylcbiAgICAgICAgZW5jb2RpbmcgPSAoJycgKyBlbmNvZGluZykudG9Mb3dlckNhc2UoKVxuICAgICAgICBsb3dlcmVkQ2FzZSA9IHRydWVcbiAgICB9XG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS50b0pTT04gPSBmdW5jdGlvbiB0b0pTT04gKCkge1xuICByZXR1cm4ge1xuICAgIHR5cGU6ICdCdWZmZXInLFxuICAgIGRhdGE6IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKHRoaXMuX2FyciB8fCB0aGlzLCAwKVxuICB9XG59XG5cbmZ1bmN0aW9uIGJhc2U2NFNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgaWYgKHN0YXJ0ID09PSAwICYmIGVuZCA9PT0gYnVmLmxlbmd0aCkge1xuICAgIHJldHVybiBiYXNlNjQuZnJvbUJ5dGVBcnJheShidWYpXG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIGJhc2U2NC5mcm9tQnl0ZUFycmF5KGJ1Zi5zbGljZShzdGFydCwgZW5kKSlcbiAgfVxufVxuXG5mdW5jdGlvbiB1dGY4U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICBlbmQgPSBNYXRoLm1pbihidWYubGVuZ3RoLCBlbmQpXG4gIHZhciByZXMgPSBbXVxuXG4gIHZhciBpID0gc3RhcnRcbiAgd2hpbGUgKGkgPCBlbmQpIHtcbiAgICB2YXIgZmlyc3RCeXRlID0gYnVmW2ldXG4gICAgdmFyIGNvZGVQb2ludCA9IG51bGxcbiAgICB2YXIgYnl0ZXNQZXJTZXF1ZW5jZSA9IChmaXJzdEJ5dGUgPiAweEVGKSA/IDRcbiAgICAgIDogKGZpcnN0Qnl0ZSA+IDB4REYpID8gM1xuICAgICAgOiAoZmlyc3RCeXRlID4gMHhCRikgPyAyXG4gICAgICA6IDFcblxuICAgIGlmIChpICsgYnl0ZXNQZXJTZXF1ZW5jZSA8PSBlbmQpIHtcbiAgICAgIHZhciBzZWNvbmRCeXRlLCB0aGlyZEJ5dGUsIGZvdXJ0aEJ5dGUsIHRlbXBDb2RlUG9pbnRcblxuICAgICAgc3dpdGNoIChieXRlc1BlclNlcXVlbmNlKSB7XG4gICAgICAgIGNhc2UgMTpcbiAgICAgICAgICBpZiAoZmlyc3RCeXRlIDwgMHg4MCkge1xuICAgICAgICAgICAgY29kZVBvaW50ID0gZmlyc3RCeXRlXG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrXG4gICAgICAgIGNhc2UgMjpcbiAgICAgICAgICBzZWNvbmRCeXRlID0gYnVmW2kgKyAxXVxuICAgICAgICAgIGlmICgoc2Vjb25kQnl0ZSAmIDB4QzApID09PSAweDgwKSB7XG4gICAgICAgICAgICB0ZW1wQ29kZVBvaW50ID0gKGZpcnN0Qnl0ZSAmIDB4MUYpIDw8IDB4NiB8IChzZWNvbmRCeXRlICYgMHgzRilcbiAgICAgICAgICAgIGlmICh0ZW1wQ29kZVBvaW50ID4gMHg3Rikge1xuICAgICAgICAgICAgICBjb2RlUG9pbnQgPSB0ZW1wQ29kZVBvaW50XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrXG4gICAgICAgIGNhc2UgMzpcbiAgICAgICAgICBzZWNvbmRCeXRlID0gYnVmW2kgKyAxXVxuICAgICAgICAgIHRoaXJkQnl0ZSA9IGJ1ZltpICsgMl1cbiAgICAgICAgICBpZiAoKHNlY29uZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCAmJiAodGhpcmRCeXRlICYgMHhDMCkgPT09IDB4ODApIHtcbiAgICAgICAgICAgIHRlbXBDb2RlUG9pbnQgPSAoZmlyc3RCeXRlICYgMHhGKSA8PCAweEMgfCAoc2Vjb25kQnl0ZSAmIDB4M0YpIDw8IDB4NiB8ICh0aGlyZEJ5dGUgJiAweDNGKVxuICAgICAgICAgICAgaWYgKHRlbXBDb2RlUG9pbnQgPiAweDdGRiAmJiAodGVtcENvZGVQb2ludCA8IDB4RDgwMCB8fCB0ZW1wQ29kZVBvaW50ID4gMHhERkZGKSkge1xuICAgICAgICAgICAgICBjb2RlUG9pbnQgPSB0ZW1wQ29kZVBvaW50XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrXG4gICAgICAgIGNhc2UgNDpcbiAgICAgICAgICBzZWNvbmRCeXRlID0gYnVmW2kgKyAxXVxuICAgICAgICAgIHRoaXJkQnl0ZSA9IGJ1ZltpICsgMl1cbiAgICAgICAgICBmb3VydGhCeXRlID0gYnVmW2kgKyAzXVxuICAgICAgICAgIGlmICgoc2Vjb25kQnl0ZSAmIDB4QzApID09PSAweDgwICYmICh0aGlyZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCAmJiAoZm91cnRoQnl0ZSAmIDB4QzApID09PSAweDgwKSB7XG4gICAgICAgICAgICB0ZW1wQ29kZVBvaW50ID0gKGZpcnN0Qnl0ZSAmIDB4RikgPDwgMHgxMiB8IChzZWNvbmRCeXRlICYgMHgzRikgPDwgMHhDIHwgKHRoaXJkQnl0ZSAmIDB4M0YpIDw8IDB4NiB8IChmb3VydGhCeXRlICYgMHgzRilcbiAgICAgICAgICAgIGlmICh0ZW1wQ29kZVBvaW50ID4gMHhGRkZGICYmIHRlbXBDb2RlUG9pbnQgPCAweDExMDAwMCkge1xuICAgICAgICAgICAgICBjb2RlUG9pbnQgPSB0ZW1wQ29kZVBvaW50XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChjb2RlUG9pbnQgPT09IG51bGwpIHtcbiAgICAgIC8vIHdlIGRpZCBub3QgZ2VuZXJhdGUgYSB2YWxpZCBjb2RlUG9pbnQgc28gaW5zZXJ0IGFcbiAgICAgIC8vIHJlcGxhY2VtZW50IGNoYXIgKFUrRkZGRCkgYW5kIGFkdmFuY2Ugb25seSAxIGJ5dGVcbiAgICAgIGNvZGVQb2ludCA9IDB4RkZGRFxuICAgICAgYnl0ZXNQZXJTZXF1ZW5jZSA9IDFcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA+IDB4RkZGRikge1xuICAgICAgLy8gZW5jb2RlIHRvIHV0ZjE2IChzdXJyb2dhdGUgcGFpciBkYW5jZSlcbiAgICAgIGNvZGVQb2ludCAtPSAweDEwMDAwXG4gICAgICByZXMucHVzaChjb2RlUG9pbnQgPj4+IDEwICYgMHgzRkYgfCAweEQ4MDApXG4gICAgICBjb2RlUG9pbnQgPSAweERDMDAgfCBjb2RlUG9pbnQgJiAweDNGRlxuICAgIH1cblxuICAgIHJlcy5wdXNoKGNvZGVQb2ludClcbiAgICBpICs9IGJ5dGVzUGVyU2VxdWVuY2VcbiAgfVxuXG4gIHJldHVybiBkZWNvZGVDb2RlUG9pbnRzQXJyYXkocmVzKVxufVxuXG4vLyBCYXNlZCBvbiBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8yMjc0NzI3Mi82ODA3NDIsIHRoZSBicm93c2VyIHdpdGhcbi8vIHRoZSBsb3dlc3QgbGltaXQgaXMgQ2hyb21lLCB3aXRoIDB4MTAwMDAgYXJncy5cbi8vIFdlIGdvIDEgbWFnbml0dWRlIGxlc3MsIGZvciBzYWZldHlcbnZhciBNQVhfQVJHVU1FTlRTX0xFTkdUSCA9IDB4MTAwMFxuXG5mdW5jdGlvbiBkZWNvZGVDb2RlUG9pbnRzQXJyYXkgKGNvZGVQb2ludHMpIHtcbiAgdmFyIGxlbiA9IGNvZGVQb2ludHMubGVuZ3RoXG4gIGlmIChsZW4gPD0gTUFYX0FSR1VNRU5UU19MRU5HVEgpIHtcbiAgICByZXR1cm4gU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShTdHJpbmcsIGNvZGVQb2ludHMpIC8vIGF2b2lkIGV4dHJhIHNsaWNlKClcbiAgfVxuXG4gIC8vIERlY29kZSBpbiBjaHVua3MgdG8gYXZvaWQgXCJjYWxsIHN0YWNrIHNpemUgZXhjZWVkZWRcIi5cbiAgdmFyIHJlcyA9ICcnXG4gIHZhciBpID0gMFxuICB3aGlsZSAoaSA8IGxlbikge1xuICAgIHJlcyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KFxuICAgICAgU3RyaW5nLFxuICAgICAgY29kZVBvaW50cy5zbGljZShpLCBpICs9IE1BWF9BUkdVTUVOVFNfTEVOR1RIKVxuICAgIClcbiAgfVxuICByZXR1cm4gcmVzXG59XG5cbmZ1bmN0aW9uIGFzY2lpU2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgcmV0ID0gJydcbiAgZW5kID0gTWF0aC5taW4oYnVmLmxlbmd0aCwgZW5kKVxuXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgcmV0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYnVmW2ldICYgMHg3RilcbiAgfVxuICByZXR1cm4gcmV0XG59XG5cbmZ1bmN0aW9uIGJpbmFyeVNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIHJldCA9ICcnXG4gIGVuZCA9IE1hdGgubWluKGJ1Zi5sZW5ndGgsIGVuZClcblxuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgIHJldCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJ1ZltpXSlcbiAgfVxuICByZXR1cm4gcmV0XG59XG5cbmZ1bmN0aW9uIGhleFNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGxlbiA9IGJ1Zi5sZW5ndGhcblxuICBpZiAoIXN0YXJ0IHx8IHN0YXJ0IDwgMCkgc3RhcnQgPSAwXG4gIGlmICghZW5kIHx8IGVuZCA8IDAgfHwgZW5kID4gbGVuKSBlbmQgPSBsZW5cblxuICB2YXIgb3V0ID0gJydcbiAgZm9yICh2YXIgaSA9IHN0YXJ0OyBpIDwgZW5kOyBpKyspIHtcbiAgICBvdXQgKz0gdG9IZXgoYnVmW2ldKVxuICB9XG4gIHJldHVybiBvdXRcbn1cblxuZnVuY3Rpb24gdXRmMTZsZVNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGJ5dGVzID0gYnVmLnNsaWNlKHN0YXJ0LCBlbmQpXG4gIHZhciByZXMgPSAnJ1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGJ5dGVzLmxlbmd0aDsgaSArPSAyKSB7XG4gICAgcmVzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYnl0ZXNbaV0gKyBieXRlc1tpICsgMV0gKiAyNTYpXG4gIH1cbiAgcmV0dXJuIHJlc1xufVxuXG5CdWZmZXIucHJvdG90eXBlLnNsaWNlID0gZnVuY3Rpb24gc2xpY2UgKHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGxlbiA9IHRoaXMubGVuZ3RoXG4gIHN0YXJ0ID0gfn5zdGFydFxuICBlbmQgPSBlbmQgPT09IHVuZGVmaW5lZCA/IGxlbiA6IH5+ZW5kXG5cbiAgaWYgKHN0YXJ0IDwgMCkge1xuICAgIHN0YXJ0ICs9IGxlblxuICAgIGlmIChzdGFydCA8IDApIHN0YXJ0ID0gMFxuICB9IGVsc2UgaWYgKHN0YXJ0ID4gbGVuKSB7XG4gICAgc3RhcnQgPSBsZW5cbiAgfVxuXG4gIGlmIChlbmQgPCAwKSB7XG4gICAgZW5kICs9IGxlblxuICAgIGlmIChlbmQgPCAwKSBlbmQgPSAwXG4gIH0gZWxzZSBpZiAoZW5kID4gbGVuKSB7XG4gICAgZW5kID0gbGVuXG4gIH1cblxuICBpZiAoZW5kIDwgc3RhcnQpIGVuZCA9IHN0YXJ0XG5cbiAgdmFyIG5ld0J1ZlxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICBuZXdCdWYgPSBCdWZmZXIuX2F1Z21lbnQodGhpcy5zdWJhcnJheShzdGFydCwgZW5kKSlcbiAgfSBlbHNlIHtcbiAgICB2YXIgc2xpY2VMZW4gPSBlbmQgLSBzdGFydFxuICAgIG5ld0J1ZiA9IG5ldyBCdWZmZXIoc2xpY2VMZW4sIHVuZGVmaW5lZClcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNsaWNlTGVuOyBpKyspIHtcbiAgICAgIG5ld0J1ZltpXSA9IHRoaXNbaSArIHN0YXJ0XVxuICAgIH1cbiAgfVxuXG4gIGlmIChuZXdCdWYubGVuZ3RoKSBuZXdCdWYucGFyZW50ID0gdGhpcy5wYXJlbnQgfHwgdGhpc1xuXG4gIHJldHVybiBuZXdCdWZcbn1cblxuLypcbiAqIE5lZWQgdG8gbWFrZSBzdXJlIHRoYXQgYnVmZmVyIGlzbid0IHRyeWluZyB0byB3cml0ZSBvdXQgb2YgYm91bmRzLlxuICovXG5mdW5jdGlvbiBjaGVja09mZnNldCAob2Zmc2V0LCBleHQsIGxlbmd0aCkge1xuICBpZiAoKG9mZnNldCAlIDEpICE9PSAwIHx8IG9mZnNldCA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdvZmZzZXQgaXMgbm90IHVpbnQnKVxuICBpZiAob2Zmc2V0ICsgZXh0ID4gbGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignVHJ5aW5nIHRvIGFjY2VzcyBiZXlvbmQgYnVmZmVyIGxlbmd0aCcpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnRMRSA9IGZ1bmN0aW9uIHJlYWRVSW50TEUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcblxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXRdXG4gIHZhciBtdWwgPSAxXG4gIHZhciBpID0gMFxuICB3aGlsZSAoKytpIDwgYnl0ZUxlbmd0aCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIGldICogbXVsXG4gIH1cblxuICByZXR1cm4gdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnRCRSA9IGZ1bmN0aW9uIHJlYWRVSW50QkUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrT2Zmc2V0KG9mZnNldCwgYnl0ZUxlbmd0aCwgdGhpcy5sZW5ndGgpXG4gIH1cblxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXQgKyAtLWJ5dGVMZW5ndGhdXG4gIHZhciBtdWwgPSAxXG4gIHdoaWxlIChieXRlTGVuZ3RoID4gMCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIC0tYnl0ZUxlbmd0aF0gKiBtdWxcbiAgfVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDggPSBmdW5jdGlvbiByZWFkVUludDggKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAxLCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIHRoaXNbb2Zmc2V0XVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MTZMRSA9IGZ1bmN0aW9uIHJlYWRVSW50MTZMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gdGhpc1tvZmZzZXRdIHwgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDE2QkUgPSBmdW5jdGlvbiByZWFkVUludDE2QkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuICh0aGlzW29mZnNldF0gPDwgOCkgfCB0aGlzW29mZnNldCArIDFdXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQzMkxFID0gZnVuY3Rpb24gcmVhZFVJbnQzMkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICgodGhpc1tvZmZzZXRdKSB8XG4gICAgICAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KSB8XG4gICAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCAxNikpICtcbiAgICAgICh0aGlzW29mZnNldCArIDNdICogMHgxMDAwMDAwKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MzJCRSA9IGZ1bmN0aW9uIHJlYWRVSW50MzJCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuXG4gIHJldHVybiAodGhpc1tvZmZzZXRdICogMHgxMDAwMDAwKSArXG4gICAgKCh0aGlzW29mZnNldCArIDFdIDw8IDE2KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgOCkgfFxuICAgIHRoaXNbb2Zmc2V0ICsgM10pXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludExFID0gZnVuY3Rpb24gcmVhZEludExFIChvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgYnl0ZUxlbmd0aCwgdGhpcy5sZW5ndGgpXG5cbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0XVxuICB2YXIgbXVsID0gMVxuICB2YXIgaSA9IDBcbiAgd2hpbGUgKCsraSA8IGJ5dGVMZW5ndGggJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyBpXSAqIG11bFxuICB9XG4gIG11bCAqPSAweDgwXG5cbiAgaWYgKHZhbCA+PSBtdWwpIHZhbCAtPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aClcblxuICByZXR1cm4gdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludEJFID0gZnVuY3Rpb24gcmVhZEludEJFIChvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgYnl0ZUxlbmd0aCwgdGhpcy5sZW5ndGgpXG5cbiAgdmFyIGkgPSBieXRlTGVuZ3RoXG4gIHZhciBtdWwgPSAxXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldCArIC0taV1cbiAgd2hpbGUgKGkgPiAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgLS1pXSAqIG11bFxuICB9XG4gIG11bCAqPSAweDgwXG5cbiAgaWYgKHZhbCA+PSBtdWwpIHZhbCAtPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aClcblxuICByZXR1cm4gdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDggPSBmdW5jdGlvbiByZWFkSW50OCAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDEsIHRoaXMubGVuZ3RoKVxuICBpZiAoISh0aGlzW29mZnNldF0gJiAweDgwKSkgcmV0dXJuICh0aGlzW29mZnNldF0pXG4gIHJldHVybiAoKDB4ZmYgLSB0aGlzW29mZnNldF0gKyAxKSAqIC0xKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQxNkxFID0gZnVuY3Rpb24gcmVhZEludDE2TEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0XSB8ICh0aGlzW29mZnNldCArIDFdIDw8IDgpXG4gIHJldHVybiAodmFsICYgMHg4MDAwKSA/IHZhbCB8IDB4RkZGRjAwMDAgOiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MTZCRSA9IGZ1bmN0aW9uIHJlYWRJbnQxNkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldCArIDFdIHwgKHRoaXNbb2Zmc2V0XSA8PCA4KVxuICByZXR1cm4gKHZhbCAmIDB4ODAwMCkgPyB2YWwgfCAweEZGRkYwMDAwIDogdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDMyTEUgPSBmdW5jdGlvbiByZWFkSW50MzJMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuXG4gIHJldHVybiAodGhpc1tvZmZzZXRdKSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOCkgfFxuICAgICh0aGlzW29mZnNldCArIDJdIDw8IDE2KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgM10gPDwgMjQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDMyQkUgPSBmdW5jdGlvbiByZWFkSW50MzJCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuXG4gIHJldHVybiAodGhpc1tvZmZzZXRdIDw8IDI0KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgMTYpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCA4KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgM10pXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEZsb2F0TEUgPSBmdW5jdGlvbiByZWFkRmxvYXRMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgdHJ1ZSwgMjMsIDQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEZsb2F0QkUgPSBmdW5jdGlvbiByZWFkRmxvYXRCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgZmFsc2UsIDIzLCA0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWREb3VibGVMRSA9IGZ1bmN0aW9uIHJlYWREb3VibGVMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDgsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgdHJ1ZSwgNTIsIDgpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZERvdWJsZUJFID0gZnVuY3Rpb24gcmVhZERvdWJsZUJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgOCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCBmYWxzZSwgNTIsIDgpXG59XG5cbmZ1bmN0aW9uIGNoZWNrSW50IChidWYsIHZhbHVlLCBvZmZzZXQsIGV4dCwgbWF4LCBtaW4pIHtcbiAgaWYgKCFCdWZmZXIuaXNCdWZmZXIoYnVmKSkgdGhyb3cgbmV3IFR5cGVFcnJvcignYnVmZmVyIG11c3QgYmUgYSBCdWZmZXIgaW5zdGFuY2UnKVxuICBpZiAodmFsdWUgPiBtYXggfHwgdmFsdWUgPCBtaW4pIHRocm93IG5ldyBSYW5nZUVycm9yKCd2YWx1ZSBpcyBvdXQgb2YgYm91bmRzJylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGJ1Zi5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdpbmRleCBvdXQgb2YgcmFuZ2UnKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludExFID0gZnVuY3Rpb24gd3JpdGVVSW50TEUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKSwgMClcblxuICB2YXIgbXVsID0gMVxuICB2YXIgaSA9IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICh2YWx1ZSAvIG11bCkgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludEJFID0gZnVuY3Rpb24gd3JpdGVVSW50QkUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKSwgMClcblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHRoaXNbb2Zmc2V0ICsgaV0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKC0taSA+PSAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICh2YWx1ZSAvIG11bCkgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDggPSBmdW5jdGlvbiB3cml0ZVVJbnQ4ICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDEsIDB4ZmYsIDApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHZhbHVlID0gTWF0aC5mbG9vcih2YWx1ZSlcbiAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgcmV0dXJuIG9mZnNldCArIDFcbn1cblxuZnVuY3Rpb24gb2JqZWN0V3JpdGVVSW50MTYgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuKSB7XG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmICsgdmFsdWUgKyAxXG4gIGZvciAodmFyIGkgPSAwLCBqID0gTWF0aC5taW4oYnVmLmxlbmd0aCAtIG9mZnNldCwgMik7IGkgPCBqOyBpKyspIHtcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSAodmFsdWUgJiAoMHhmZiA8PCAoOCAqIChsaXR0bGVFbmRpYW4gPyBpIDogMSAtIGkpKSkpID4+PlxuICAgICAgKGxpdHRsZUVuZGlhbiA/IGkgOiAxIC0gaSkgKiA4XG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQxNkxFID0gZnVuY3Rpb24gd3JpdGVVSW50MTZMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweGZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MTZCRSA9IGZ1bmN0aW9uIHdyaXRlVUludDE2QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHhmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuZnVuY3Rpb24gb2JqZWN0V3JpdGVVSW50MzIgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuKSB7XG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmZmZmZiArIHZhbHVlICsgMVxuICBmb3IgKHZhciBpID0gMCwgaiA9IE1hdGgubWluKGJ1Zi5sZW5ndGggLSBvZmZzZXQsIDQpOyBpIDwgajsgaSsrKSB7XG4gICAgYnVmW29mZnNldCArIGldID0gKHZhbHVlID4+PiAobGl0dGxlRW5kaWFuID8gaSA6IDMgLSBpKSAqIDgpICYgMHhmZlxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MzJMRSA9IGZ1bmN0aW9uIHdyaXRlVUludDMyTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHhmZmZmZmZmZiwgMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQzMkJFID0gZnVuY3Rpb24gd3JpdGVVSW50MzJCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweGZmZmZmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDI0KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDE2KVxuICAgIHRoaXNbb2Zmc2V0ICsgMl0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludExFID0gZnVuY3Rpb24gd3JpdGVJbnRMRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IDBcbiAgdmFyIG11bCA9IDFcbiAgdmFyIHN1YiA9IHZhbHVlIDwgMCA/IDEgOiAwXG4gIHRoaXNbb2Zmc2V0XSA9IHZhbHVlICYgMHhGRlxuICB3aGlsZSAoKytpIDwgYnl0ZUxlbmd0aCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHRoaXNbb2Zmc2V0ICsgaV0gPSAoKHZhbHVlIC8gbXVsKSA+PiAwKSAtIHN1YiAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnRCRSA9IGZ1bmN0aW9uIHdyaXRlSW50QkUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIHZhciBsaW1pdCA9IE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoIC0gMSlcblxuICAgIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIGxpbWl0IC0gMSwgLWxpbWl0KVxuICB9XG5cbiAgdmFyIGkgPSBieXRlTGVuZ3RoIC0gMVxuICB2YXIgbXVsID0gMVxuICB2YXIgc3ViID0gdmFsdWUgPCAwID8gMSA6IDBcbiAgdGhpc1tvZmZzZXQgKyBpXSA9IHZhbHVlICYgMHhGRlxuICB3aGlsZSAoLS1pID49IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB0aGlzW29mZnNldCArIGldID0gKCh2YWx1ZSAvIG11bCkgPj4gMCkgLSBzdWIgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50OCA9IGZ1bmN0aW9uIHdyaXRlSW50OCAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAxLCAweDdmLCAtMHg4MClcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkgdmFsdWUgPSBNYXRoLmZsb29yKHZhbHVlKVxuICBpZiAodmFsdWUgPCAwKSB2YWx1ZSA9IDB4ZmYgKyB2YWx1ZSArIDFcbiAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgcmV0dXJuIG9mZnNldCArIDFcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDE2TEUgPSBmdW5jdGlvbiB3cml0ZUludDE2TEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHg3ZmZmLCAtMHg4MDAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDgpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgMlxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MTZCRSA9IGZ1bmN0aW9uIHdyaXRlSW50MTZCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweDdmZmYsIC0weDgwMDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgMlxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MzJMRSA9IGZ1bmN0aW9uIHdyaXRlSW50MzJMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweDdmZmZmZmZmLCAtMHg4MDAwMDAwMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0ICsgMl0gPSAodmFsdWUgPj4+IDE2KVxuICAgIHRoaXNbb2Zmc2V0ICsgM10gPSAodmFsdWUgPj4+IDI0KVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDMyQkUgPSBmdW5jdGlvbiB3cml0ZUludDMyQkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHg3ZmZmZmZmZiwgLTB4ODAwMDAwMDApXG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmZmZmZiArIHZhbHVlICsgMVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDI0KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDE2KVxuICAgIHRoaXNbb2Zmc2V0ICsgMl0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuZnVuY3Rpb24gY2hlY2tJRUVFNzU0IChidWYsIHZhbHVlLCBvZmZzZXQsIGV4dCwgbWF4LCBtaW4pIHtcbiAgaWYgKHZhbHVlID4gbWF4IHx8IHZhbHVlIDwgbWluKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcigndmFsdWUgaXMgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChvZmZzZXQgKyBleHQgPiBidWYubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignaW5kZXggb3V0IG9mIHJhbmdlJylcbiAgaWYgKG9mZnNldCA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdpbmRleCBvdXQgb2YgcmFuZ2UnKVxufVxuXG5mdW5jdGlvbiB3cml0ZUZsb2F0IChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrSUVFRTc1NChidWYsIHZhbHVlLCBvZmZzZXQsIDQsIDMuNDAyODIzNDY2Mzg1Mjg4NmUrMzgsIC0zLjQwMjgyMzQ2NjM4NTI4ODZlKzM4KVxuICB9XG4gIGllZWU3NTQud3JpdGUoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4sIDIzLCA0KVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlRmxvYXRMRSA9IGZ1bmN0aW9uIHdyaXRlRmxvYXRMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRmxvYXQodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSwgbm9Bc3NlcnQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVGbG9hdEJFID0gZnVuY3Rpb24gd3JpdGVGbG9hdEJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVGbG9hdCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSwgbm9Bc3NlcnQpXG59XG5cbmZ1bmN0aW9uIHdyaXRlRG91YmxlIChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrSUVFRTc1NChidWYsIHZhbHVlLCBvZmZzZXQsIDgsIDEuNzk3NjkzMTM0ODYyMzE1N0UrMzA4LCAtMS43OTc2OTMxMzQ4NjIzMTU3RSszMDgpXG4gIH1cbiAgaWVlZTc1NC53cml0ZShidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgNTIsIDgpXG4gIHJldHVybiBvZmZzZXQgKyA4XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVEb3VibGVMRSA9IGZ1bmN0aW9uIHdyaXRlRG91YmxlTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZURvdWJsZSh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlLCBub0Fzc2VydClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZURvdWJsZUJFID0gZnVuY3Rpb24gd3JpdGVEb3VibGVCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRG91YmxlKHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlLCBub0Fzc2VydClcbn1cblxuLy8gY29weSh0YXJnZXRCdWZmZXIsIHRhcmdldFN0YXJ0PTAsIHNvdXJjZVN0YXJ0PTAsIHNvdXJjZUVuZD1idWZmZXIubGVuZ3RoKVxuQnVmZmVyLnByb3RvdHlwZS5jb3B5ID0gZnVuY3Rpb24gY29weSAodGFyZ2V0LCB0YXJnZXRTdGFydCwgc3RhcnQsIGVuZCkge1xuICBpZiAoIXN0YXJ0KSBzdGFydCA9IDBcbiAgaWYgKCFlbmQgJiYgZW5kICE9PSAwKSBlbmQgPSB0aGlzLmxlbmd0aFxuICBpZiAodGFyZ2V0U3RhcnQgPj0gdGFyZ2V0Lmxlbmd0aCkgdGFyZ2V0U3RhcnQgPSB0YXJnZXQubGVuZ3RoXG4gIGlmICghdGFyZ2V0U3RhcnQpIHRhcmdldFN0YXJ0ID0gMFxuICBpZiAoZW5kID4gMCAmJiBlbmQgPCBzdGFydCkgZW5kID0gc3RhcnRcblxuICAvLyBDb3B5IDAgYnl0ZXM7IHdlJ3JlIGRvbmVcbiAgaWYgKGVuZCA9PT0gc3RhcnQpIHJldHVybiAwXG4gIGlmICh0YXJnZXQubGVuZ3RoID09PSAwIHx8IHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm4gMFxuXG4gIC8vIEZhdGFsIGVycm9yIGNvbmRpdGlvbnNcbiAgaWYgKHRhcmdldFN0YXJ0IDwgMCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCd0YXJnZXRTdGFydCBvdXQgb2YgYm91bmRzJylcbiAgfVxuICBpZiAoc3RhcnQgPCAwIHx8IHN0YXJ0ID49IHRoaXMubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc291cmNlU3RhcnQgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChlbmQgPCAwKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc291cmNlRW5kIG91dCBvZiBib3VuZHMnKVxuXG4gIC8vIEFyZSB3ZSBvb2I/XG4gIGlmIChlbmQgPiB0aGlzLmxlbmd0aCkgZW5kID0gdGhpcy5sZW5ndGhcbiAgaWYgKHRhcmdldC5sZW5ndGggLSB0YXJnZXRTdGFydCA8IGVuZCAtIHN0YXJ0KSB7XG4gICAgZW5kID0gdGFyZ2V0Lmxlbmd0aCAtIHRhcmdldFN0YXJ0ICsgc3RhcnRcbiAgfVxuXG4gIHZhciBsZW4gPSBlbmQgLSBzdGFydFxuICB2YXIgaVxuXG4gIGlmICh0aGlzID09PSB0YXJnZXQgJiYgc3RhcnQgPCB0YXJnZXRTdGFydCAmJiB0YXJnZXRTdGFydCA8IGVuZCkge1xuICAgIC8vIGRlc2NlbmRpbmcgY29weSBmcm9tIGVuZFxuICAgIGZvciAoaSA9IGxlbiAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICB0YXJnZXRbaSArIHRhcmdldFN0YXJ0XSA9IHRoaXNbaSArIHN0YXJ0XVxuICAgIH1cbiAgfSBlbHNlIGlmIChsZW4gPCAxMDAwIHx8ICFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIC8vIGFzY2VuZGluZyBjb3B5IGZyb20gc3RhcnRcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgIHRhcmdldFtpICsgdGFyZ2V0U3RhcnRdID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHRhcmdldC5fc2V0KHRoaXMuc3ViYXJyYXkoc3RhcnQsIHN0YXJ0ICsgbGVuKSwgdGFyZ2V0U3RhcnQpXG4gIH1cblxuICByZXR1cm4gbGVuXG59XG5cbi8vIGZpbGwodmFsdWUsIHN0YXJ0PTAsIGVuZD1idWZmZXIubGVuZ3RoKVxuQnVmZmVyLnByb3RvdHlwZS5maWxsID0gZnVuY3Rpb24gZmlsbCAodmFsdWUsIHN0YXJ0LCBlbmQpIHtcbiAgaWYgKCF2YWx1ZSkgdmFsdWUgPSAwXG4gIGlmICghc3RhcnQpIHN0YXJ0ID0gMFxuICBpZiAoIWVuZCkgZW5kID0gdGhpcy5sZW5ndGhcblxuICBpZiAoZW5kIDwgc3RhcnQpIHRocm93IG5ldyBSYW5nZUVycm9yKCdlbmQgPCBzdGFydCcpXG5cbiAgLy8gRmlsbCAwIGJ5dGVzOyB3ZSdyZSBkb25lXG4gIGlmIChlbmQgPT09IHN0YXJ0KSByZXR1cm5cbiAgaWYgKHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm5cblxuICBpZiAoc3RhcnQgPCAwIHx8IHN0YXJ0ID49IHRoaXMubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc3RhcnQgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChlbmQgPCAwIHx8IGVuZCA+IHRoaXMubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignZW5kIG91dCBvZiBib3VuZHMnKVxuXG4gIHZhciBpXG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInKSB7XG4gICAgZm9yIChpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgICAgdGhpc1tpXSA9IHZhbHVlXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHZhciBieXRlcyA9IHV0ZjhUb0J5dGVzKHZhbHVlLnRvU3RyaW5nKCkpXG4gICAgdmFyIGxlbiA9IGJ5dGVzLmxlbmd0aFxuICAgIGZvciAoaSA9IHN0YXJ0OyBpIDwgZW5kOyBpKyspIHtcbiAgICAgIHRoaXNbaV0gPSBieXRlc1tpICUgbGVuXVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0aGlzXG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIG5ldyBgQXJyYXlCdWZmZXJgIHdpdGggdGhlICpjb3BpZWQqIG1lbW9yeSBvZiB0aGUgYnVmZmVyIGluc3RhbmNlLlxuICogQWRkZWQgaW4gTm9kZSAwLjEyLiBPbmx5IGF2YWlsYWJsZSBpbiBicm93c2VycyB0aGF0IHN1cHBvcnQgQXJyYXlCdWZmZXIuXG4gKi9cbkJ1ZmZlci5wcm90b3R5cGUudG9BcnJheUJ1ZmZlciA9IGZ1bmN0aW9uIHRvQXJyYXlCdWZmZXIgKCkge1xuICBpZiAodHlwZW9mIFVpbnQ4QXJyYXkgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgICByZXR1cm4gKG5ldyBCdWZmZXIodGhpcykpLmJ1ZmZlclxuICAgIH0gZWxzZSB7XG4gICAgICB2YXIgYnVmID0gbmV3IFVpbnQ4QXJyYXkodGhpcy5sZW5ndGgpXG4gICAgICBmb3IgKHZhciBpID0gMCwgbGVuID0gYnVmLmxlbmd0aDsgaSA8IGxlbjsgaSArPSAxKSB7XG4gICAgICAgIGJ1ZltpXSA9IHRoaXNbaV1cbiAgICAgIH1cbiAgICAgIHJldHVybiBidWYuYnVmZmVyXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0J1ZmZlci50b0FycmF5QnVmZmVyIG5vdCBzdXBwb3J0ZWQgaW4gdGhpcyBicm93c2VyJylcbiAgfVxufVxuXG4vLyBIRUxQRVIgRlVOQ1RJT05TXG4vLyA9PT09PT09PT09PT09PT09XG5cbnZhciBCUCA9IEJ1ZmZlci5wcm90b3R5cGVcblxuLyoqXG4gKiBBdWdtZW50IGEgVWludDhBcnJheSAqaW5zdGFuY2UqIChub3QgdGhlIFVpbnQ4QXJyYXkgY2xhc3MhKSB3aXRoIEJ1ZmZlciBtZXRob2RzXG4gKi9cbkJ1ZmZlci5fYXVnbWVudCA9IGZ1bmN0aW9uIF9hdWdtZW50IChhcnIpIHtcbiAgYXJyLmNvbnN0cnVjdG9yID0gQnVmZmVyXG4gIGFyci5faXNCdWZmZXIgPSB0cnVlXG5cbiAgLy8gc2F2ZSByZWZlcmVuY2UgdG8gb3JpZ2luYWwgVWludDhBcnJheSBzZXQgbWV0aG9kIGJlZm9yZSBvdmVyd3JpdGluZ1xuICBhcnIuX3NldCA9IGFyci5zZXRcblxuICAvLyBkZXByZWNhdGVkXG4gIGFyci5nZXQgPSBCUC5nZXRcbiAgYXJyLnNldCA9IEJQLnNldFxuXG4gIGFyci53cml0ZSA9IEJQLndyaXRlXG4gIGFyci50b1N0cmluZyA9IEJQLnRvU3RyaW5nXG4gIGFyci50b0xvY2FsZVN0cmluZyA9IEJQLnRvU3RyaW5nXG4gIGFyci50b0pTT04gPSBCUC50b0pTT05cbiAgYXJyLmVxdWFscyA9IEJQLmVxdWFsc1xuICBhcnIuY29tcGFyZSA9IEJQLmNvbXBhcmVcbiAgYXJyLmluZGV4T2YgPSBCUC5pbmRleE9mXG4gIGFyci5jb3B5ID0gQlAuY29weVxuICBhcnIuc2xpY2UgPSBCUC5zbGljZVxuICBhcnIucmVhZFVJbnRMRSA9IEJQLnJlYWRVSW50TEVcbiAgYXJyLnJlYWRVSW50QkUgPSBCUC5yZWFkVUludEJFXG4gIGFyci5yZWFkVUludDggPSBCUC5yZWFkVUludDhcbiAgYXJyLnJlYWRVSW50MTZMRSA9IEJQLnJlYWRVSW50MTZMRVxuICBhcnIucmVhZFVJbnQxNkJFID0gQlAucmVhZFVJbnQxNkJFXG4gIGFyci5yZWFkVUludDMyTEUgPSBCUC5yZWFkVUludDMyTEVcbiAgYXJyLnJlYWRVSW50MzJCRSA9IEJQLnJlYWRVSW50MzJCRVxuICBhcnIucmVhZEludExFID0gQlAucmVhZEludExFXG4gIGFyci5yZWFkSW50QkUgPSBCUC5yZWFkSW50QkVcbiAgYXJyLnJlYWRJbnQ4ID0gQlAucmVhZEludDhcbiAgYXJyLnJlYWRJbnQxNkxFID0gQlAucmVhZEludDE2TEVcbiAgYXJyLnJlYWRJbnQxNkJFID0gQlAucmVhZEludDE2QkVcbiAgYXJyLnJlYWRJbnQzMkxFID0gQlAucmVhZEludDMyTEVcbiAgYXJyLnJlYWRJbnQzMkJFID0gQlAucmVhZEludDMyQkVcbiAgYXJyLnJlYWRGbG9hdExFID0gQlAucmVhZEZsb2F0TEVcbiAgYXJyLnJlYWRGbG9hdEJFID0gQlAucmVhZEZsb2F0QkVcbiAgYXJyLnJlYWREb3VibGVMRSA9IEJQLnJlYWREb3VibGVMRVxuICBhcnIucmVhZERvdWJsZUJFID0gQlAucmVhZERvdWJsZUJFXG4gIGFyci53cml0ZVVJbnQ4ID0gQlAud3JpdGVVSW50OFxuICBhcnIud3JpdGVVSW50TEUgPSBCUC53cml0ZVVJbnRMRVxuICBhcnIud3JpdGVVSW50QkUgPSBCUC53cml0ZVVJbnRCRVxuICBhcnIud3JpdGVVSW50MTZMRSA9IEJQLndyaXRlVUludDE2TEVcbiAgYXJyLndyaXRlVUludDE2QkUgPSBCUC53cml0ZVVJbnQxNkJFXG4gIGFyci53cml0ZVVJbnQzMkxFID0gQlAud3JpdGVVSW50MzJMRVxuICBhcnIud3JpdGVVSW50MzJCRSA9IEJQLndyaXRlVUludDMyQkVcbiAgYXJyLndyaXRlSW50TEUgPSBCUC53cml0ZUludExFXG4gIGFyci53cml0ZUludEJFID0gQlAud3JpdGVJbnRCRVxuICBhcnIud3JpdGVJbnQ4ID0gQlAud3JpdGVJbnQ4XG4gIGFyci53cml0ZUludDE2TEUgPSBCUC53cml0ZUludDE2TEVcbiAgYXJyLndyaXRlSW50MTZCRSA9IEJQLndyaXRlSW50MTZCRVxuICBhcnIud3JpdGVJbnQzMkxFID0gQlAud3JpdGVJbnQzMkxFXG4gIGFyci53cml0ZUludDMyQkUgPSBCUC53cml0ZUludDMyQkVcbiAgYXJyLndyaXRlRmxvYXRMRSA9IEJQLndyaXRlRmxvYXRMRVxuICBhcnIud3JpdGVGbG9hdEJFID0gQlAud3JpdGVGbG9hdEJFXG4gIGFyci53cml0ZURvdWJsZUxFID0gQlAud3JpdGVEb3VibGVMRVxuICBhcnIud3JpdGVEb3VibGVCRSA9IEJQLndyaXRlRG91YmxlQkVcbiAgYXJyLmZpbGwgPSBCUC5maWxsXG4gIGFyci5pbnNwZWN0ID0gQlAuaW5zcGVjdFxuICBhcnIudG9BcnJheUJ1ZmZlciA9IEJQLnRvQXJyYXlCdWZmZXJcblxuICByZXR1cm4gYXJyXG59XG5cbnZhciBJTlZBTElEX0JBU0U2NF9SRSA9IC9bXitcXC8wLTlBLVphLXotX10vZ1xuXG5mdW5jdGlvbiBiYXNlNjRjbGVhbiAoc3RyKSB7XG4gIC8vIE5vZGUgc3RyaXBzIG91dCBpbnZhbGlkIGNoYXJhY3RlcnMgbGlrZSBcXG4gYW5kIFxcdCBmcm9tIHRoZSBzdHJpbmcsIGJhc2U2NC1qcyBkb2VzIG5vdFxuICBzdHIgPSBzdHJpbmd0cmltKHN0cikucmVwbGFjZShJTlZBTElEX0JBU0U2NF9SRSwgJycpXG4gIC8vIE5vZGUgY29udmVydHMgc3RyaW5ncyB3aXRoIGxlbmd0aCA8IDIgdG8gJydcbiAgaWYgKHN0ci5sZW5ndGggPCAyKSByZXR1cm4gJydcbiAgLy8gTm9kZSBhbGxvd3MgZm9yIG5vbi1wYWRkZWQgYmFzZTY0IHN0cmluZ3MgKG1pc3NpbmcgdHJhaWxpbmcgPT09KSwgYmFzZTY0LWpzIGRvZXMgbm90XG4gIHdoaWxlIChzdHIubGVuZ3RoICUgNCAhPT0gMCkge1xuICAgIHN0ciA9IHN0ciArICc9J1xuICB9XG4gIHJldHVybiBzdHJcbn1cblxuZnVuY3Rpb24gc3RyaW5ndHJpbSAoc3RyKSB7XG4gIGlmIChzdHIudHJpbSkgcmV0dXJuIHN0ci50cmltKClcbiAgcmV0dXJuIHN0ci5yZXBsYWNlKC9eXFxzK3xcXHMrJC9nLCAnJylcbn1cblxuZnVuY3Rpb24gdG9IZXggKG4pIHtcbiAgaWYgKG4gPCAxNikgcmV0dXJuICcwJyArIG4udG9TdHJpbmcoMTYpXG4gIHJldHVybiBuLnRvU3RyaW5nKDE2KVxufVxuXG5mdW5jdGlvbiB1dGY4VG9CeXRlcyAoc3RyaW5nLCB1bml0cykge1xuICB1bml0cyA9IHVuaXRzIHx8IEluZmluaXR5XG4gIHZhciBjb2RlUG9pbnRcbiAgdmFyIGxlbmd0aCA9IHN0cmluZy5sZW5ndGhcbiAgdmFyIGxlYWRTdXJyb2dhdGUgPSBudWxsXG4gIHZhciBieXRlcyA9IFtdXG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgIGNvZGVQb2ludCA9IHN0cmluZy5jaGFyQ29kZUF0KGkpXG5cbiAgICAvLyBpcyBzdXJyb2dhdGUgY29tcG9uZW50XG4gICAgaWYgKGNvZGVQb2ludCA+IDB4RDdGRiAmJiBjb2RlUG9pbnQgPCAweEUwMDApIHtcbiAgICAgIC8vIGxhc3QgY2hhciB3YXMgYSBsZWFkXG4gICAgICBpZiAoIWxlYWRTdXJyb2dhdGUpIHtcbiAgICAgICAgLy8gbm8gbGVhZCB5ZXRcbiAgICAgICAgaWYgKGNvZGVQb2ludCA+IDB4REJGRikge1xuICAgICAgICAgIC8vIHVuZXhwZWN0ZWQgdHJhaWxcbiAgICAgICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICAgICAgICBjb250aW51ZVxuICAgICAgICB9IGVsc2UgaWYgKGkgKyAxID09PSBsZW5ndGgpIHtcbiAgICAgICAgICAvLyB1bnBhaXJlZCBsZWFkXG4gICAgICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgICAgICAgY29udGludWVcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHZhbGlkIGxlYWRcbiAgICAgICAgbGVhZFN1cnJvZ2F0ZSA9IGNvZGVQb2ludFxuXG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIC8vIDIgbGVhZHMgaW4gYSByb3dcbiAgICAgIGlmIChjb2RlUG9pbnQgPCAweERDMDApIHtcbiAgICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgICAgIGxlYWRTdXJyb2dhdGUgPSBjb2RlUG9pbnRcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgLy8gdmFsaWQgc3Vycm9nYXRlIHBhaXJcbiAgICAgIGNvZGVQb2ludCA9IChsZWFkU3Vycm9nYXRlIC0gMHhEODAwIDw8IDEwIHwgY29kZVBvaW50IC0gMHhEQzAwKSArIDB4MTAwMDBcbiAgICB9IGVsc2UgaWYgKGxlYWRTdXJyb2dhdGUpIHtcbiAgICAgIC8vIHZhbGlkIGJtcCBjaGFyLCBidXQgbGFzdCBjaGFyIHdhcyBhIGxlYWRcbiAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgIH1cblxuICAgIGxlYWRTdXJyb2dhdGUgPSBudWxsXG5cbiAgICAvLyBlbmNvZGUgdXRmOFxuICAgIGlmIChjb2RlUG9pbnQgPCAweDgwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDEpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goY29kZVBvaW50KVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50IDwgMHg4MDApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gMikgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChcbiAgICAgICAgY29kZVBvaW50ID4+IDB4NiB8IDB4QzAsXG4gICAgICAgIGNvZGVQb2ludCAmIDB4M0YgfCAweDgwXG4gICAgICApXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPCAweDEwMDAwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDMpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goXG4gICAgICAgIGNvZGVQb2ludCA+PiAweEMgfCAweEUwLFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHg2ICYgMHgzRiB8IDB4ODAsXG4gICAgICAgIGNvZGVQb2ludCAmIDB4M0YgfCAweDgwXG4gICAgICApXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPCAweDExMDAwMCkge1xuICAgICAgaWYgKCh1bml0cyAtPSA0KSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHgxMiB8IDB4RjAsXG4gICAgICAgIGNvZGVQb2ludCA+PiAweEMgJiAweDNGIHwgMHg4MCxcbiAgICAgICAgY29kZVBvaW50ID4+IDB4NiAmIDB4M0YgfCAweDgwLFxuICAgICAgICBjb2RlUG9pbnQgJiAweDNGIHwgMHg4MFxuICAgICAgKVxuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgY29kZSBwb2ludCcpXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGJ5dGVzXG59XG5cbmZ1bmN0aW9uIGFzY2lpVG9CeXRlcyAoc3RyKSB7XG4gIHZhciBieXRlQXJyYXkgPSBbXVxuICBmb3IgKHZhciBpID0gMDsgaSA8IHN0ci5sZW5ndGg7IGkrKykge1xuICAgIC8vIE5vZGUncyBjb2RlIHNlZW1zIHRvIGJlIGRvaW5nIHRoaXMgYW5kIG5vdCAmIDB4N0YuLlxuICAgIGJ5dGVBcnJheS5wdXNoKHN0ci5jaGFyQ29kZUF0KGkpICYgMHhGRilcbiAgfVxuICByZXR1cm4gYnl0ZUFycmF5XG59XG5cbmZ1bmN0aW9uIHV0ZjE2bGVUb0J5dGVzIChzdHIsIHVuaXRzKSB7XG4gIHZhciBjLCBoaSwgbG9cbiAgdmFyIGJ5dGVBcnJheSA9IFtdXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKCh1bml0cyAtPSAyKSA8IDApIGJyZWFrXG5cbiAgICBjID0gc3RyLmNoYXJDb2RlQXQoaSlcbiAgICBoaSA9IGMgPj4gOFxuICAgIGxvID0gYyAlIDI1NlxuICAgIGJ5dGVBcnJheS5wdXNoKGxvKVxuICAgIGJ5dGVBcnJheS5wdXNoKGhpKVxuICB9XG5cbiAgcmV0dXJuIGJ5dGVBcnJheVxufVxuXG5mdW5jdGlvbiBiYXNlNjRUb0J5dGVzIChzdHIpIHtcbiAgcmV0dXJuIGJhc2U2NC50b0J5dGVBcnJheShiYXNlNjRjbGVhbihzdHIpKVxufVxuXG5mdW5jdGlvbiBibGl0QnVmZmVyIChzcmMsIGRzdCwgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgIGlmICgoaSArIG9mZnNldCA+PSBkc3QubGVuZ3RoKSB8fCAoaSA+PSBzcmMubGVuZ3RoKSkgYnJlYWtcbiAgICBkc3RbaSArIG9mZnNldF0gPSBzcmNbaV1cbiAgfVxuICByZXR1cm4gaVxufVxuIiwidmFyIGxvb2t1cCA9ICdBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsvJztcblxuOyhmdW5jdGlvbiAoZXhwb3J0cykge1xuXHQndXNlIHN0cmljdCc7XG5cbiAgdmFyIEFyciA9ICh0eXBlb2YgVWludDhBcnJheSAhPT0gJ3VuZGVmaW5lZCcpXG4gICAgPyBVaW50OEFycmF5XG4gICAgOiBBcnJheVxuXG5cdHZhciBQTFVTICAgPSAnKycuY2hhckNvZGVBdCgwKVxuXHR2YXIgU0xBU0ggID0gJy8nLmNoYXJDb2RlQXQoMClcblx0dmFyIE5VTUJFUiA9ICcwJy5jaGFyQ29kZUF0KDApXG5cdHZhciBMT1dFUiAgPSAnYScuY2hhckNvZGVBdCgwKVxuXHR2YXIgVVBQRVIgID0gJ0EnLmNoYXJDb2RlQXQoMClcblx0dmFyIFBMVVNfVVJMX1NBRkUgPSAnLScuY2hhckNvZGVBdCgwKVxuXHR2YXIgU0xBU0hfVVJMX1NBRkUgPSAnXycuY2hhckNvZGVBdCgwKVxuXG5cdGZ1bmN0aW9uIGRlY29kZSAoZWx0KSB7XG5cdFx0dmFyIGNvZGUgPSBlbHQuY2hhckNvZGVBdCgwKVxuXHRcdGlmIChjb2RlID09PSBQTFVTIHx8XG5cdFx0ICAgIGNvZGUgPT09IFBMVVNfVVJMX1NBRkUpXG5cdFx0XHRyZXR1cm4gNjIgLy8gJysnXG5cdFx0aWYgKGNvZGUgPT09IFNMQVNIIHx8XG5cdFx0ICAgIGNvZGUgPT09IFNMQVNIX1VSTF9TQUZFKVxuXHRcdFx0cmV0dXJuIDYzIC8vICcvJ1xuXHRcdGlmIChjb2RlIDwgTlVNQkVSKVxuXHRcdFx0cmV0dXJuIC0xIC8vbm8gbWF0Y2hcblx0XHRpZiAoY29kZSA8IE5VTUJFUiArIDEwKVxuXHRcdFx0cmV0dXJuIGNvZGUgLSBOVU1CRVIgKyAyNiArIDI2XG5cdFx0aWYgKGNvZGUgPCBVUFBFUiArIDI2KVxuXHRcdFx0cmV0dXJuIGNvZGUgLSBVUFBFUlxuXHRcdGlmIChjb2RlIDwgTE9XRVIgKyAyNilcblx0XHRcdHJldHVybiBjb2RlIC0gTE9XRVIgKyAyNlxuXHR9XG5cblx0ZnVuY3Rpb24gYjY0VG9CeXRlQXJyYXkgKGI2NCkge1xuXHRcdHZhciBpLCBqLCBsLCB0bXAsIHBsYWNlSG9sZGVycywgYXJyXG5cblx0XHRpZiAoYjY0Lmxlbmd0aCAlIDQgPiAwKSB7XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgc3RyaW5nLiBMZW5ndGggbXVzdCBiZSBhIG11bHRpcGxlIG9mIDQnKVxuXHRcdH1cblxuXHRcdC8vIHRoZSBudW1iZXIgb2YgZXF1YWwgc2lnbnMgKHBsYWNlIGhvbGRlcnMpXG5cdFx0Ly8gaWYgdGhlcmUgYXJlIHR3byBwbGFjZWhvbGRlcnMsIHRoYW4gdGhlIHR3byBjaGFyYWN0ZXJzIGJlZm9yZSBpdFxuXHRcdC8vIHJlcHJlc2VudCBvbmUgYnl0ZVxuXHRcdC8vIGlmIHRoZXJlIGlzIG9ubHkgb25lLCB0aGVuIHRoZSB0aHJlZSBjaGFyYWN0ZXJzIGJlZm9yZSBpdCByZXByZXNlbnQgMiBieXRlc1xuXHRcdC8vIHRoaXMgaXMganVzdCBhIGNoZWFwIGhhY2sgdG8gbm90IGRvIGluZGV4T2YgdHdpY2Vcblx0XHR2YXIgbGVuID0gYjY0Lmxlbmd0aFxuXHRcdHBsYWNlSG9sZGVycyA9ICc9JyA9PT0gYjY0LmNoYXJBdChsZW4gLSAyKSA/IDIgOiAnPScgPT09IGI2NC5jaGFyQXQobGVuIC0gMSkgPyAxIDogMFxuXG5cdFx0Ly8gYmFzZTY0IGlzIDQvMyArIHVwIHRvIHR3byBjaGFyYWN0ZXJzIG9mIHRoZSBvcmlnaW5hbCBkYXRhXG5cdFx0YXJyID0gbmV3IEFycihiNjQubGVuZ3RoICogMyAvIDQgLSBwbGFjZUhvbGRlcnMpXG5cblx0XHQvLyBpZiB0aGVyZSBhcmUgcGxhY2Vob2xkZXJzLCBvbmx5IGdldCB1cCB0byB0aGUgbGFzdCBjb21wbGV0ZSA0IGNoYXJzXG5cdFx0bCA9IHBsYWNlSG9sZGVycyA+IDAgPyBiNjQubGVuZ3RoIC0gNCA6IGI2NC5sZW5ndGhcblxuXHRcdHZhciBMID0gMFxuXG5cdFx0ZnVuY3Rpb24gcHVzaCAodikge1xuXHRcdFx0YXJyW0wrK10gPSB2XG5cdFx0fVxuXG5cdFx0Zm9yIChpID0gMCwgaiA9IDA7IGkgPCBsOyBpICs9IDQsIGogKz0gMykge1xuXHRcdFx0dG1wID0gKGRlY29kZShiNjQuY2hhckF0KGkpKSA8PCAxOCkgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDEpKSA8PCAxMikgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDIpKSA8PCA2KSB8IGRlY29kZShiNjQuY2hhckF0KGkgKyAzKSlcblx0XHRcdHB1c2goKHRtcCAmIDB4RkYwMDAwKSA+PiAxNilcblx0XHRcdHB1c2goKHRtcCAmIDB4RkYwMCkgPj4gOClcblx0XHRcdHB1c2godG1wICYgMHhGRilcblx0XHR9XG5cblx0XHRpZiAocGxhY2VIb2xkZXJzID09PSAyKSB7XG5cdFx0XHR0bXAgPSAoZGVjb2RlKGI2NC5jaGFyQXQoaSkpIDw8IDIpIHwgKGRlY29kZShiNjQuY2hhckF0KGkgKyAxKSkgPj4gNClcblx0XHRcdHB1c2godG1wICYgMHhGRilcblx0XHR9IGVsc2UgaWYgKHBsYWNlSG9sZGVycyA9PT0gMSkge1xuXHRcdFx0dG1wID0gKGRlY29kZShiNjQuY2hhckF0KGkpKSA8PCAxMCkgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDEpKSA8PCA0KSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMikpID4+IDIpXG5cdFx0XHRwdXNoKCh0bXAgPj4gOCkgJiAweEZGKVxuXHRcdFx0cHVzaCh0bXAgJiAweEZGKVxuXHRcdH1cblxuXHRcdHJldHVybiBhcnJcblx0fVxuXG5cdGZ1bmN0aW9uIHVpbnQ4VG9CYXNlNjQgKHVpbnQ4KSB7XG5cdFx0dmFyIGksXG5cdFx0XHRleHRyYUJ5dGVzID0gdWludDgubGVuZ3RoICUgMywgLy8gaWYgd2UgaGF2ZSAxIGJ5dGUgbGVmdCwgcGFkIDIgYnl0ZXNcblx0XHRcdG91dHB1dCA9IFwiXCIsXG5cdFx0XHR0ZW1wLCBsZW5ndGhcblxuXHRcdGZ1bmN0aW9uIGVuY29kZSAobnVtKSB7XG5cdFx0XHRyZXR1cm4gbG9va3VwLmNoYXJBdChudW0pXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gdHJpcGxldFRvQmFzZTY0IChudW0pIHtcblx0XHRcdHJldHVybiBlbmNvZGUobnVtID4+IDE4ICYgMHgzRikgKyBlbmNvZGUobnVtID4+IDEyICYgMHgzRikgKyBlbmNvZGUobnVtID4+IDYgJiAweDNGKSArIGVuY29kZShudW0gJiAweDNGKVxuXHRcdH1cblxuXHRcdC8vIGdvIHRocm91Z2ggdGhlIGFycmF5IGV2ZXJ5IHRocmVlIGJ5dGVzLCB3ZSdsbCBkZWFsIHdpdGggdHJhaWxpbmcgc3R1ZmYgbGF0ZXJcblx0XHRmb3IgKGkgPSAwLCBsZW5ndGggPSB1aW50OC5sZW5ndGggLSBleHRyYUJ5dGVzOyBpIDwgbGVuZ3RoOyBpICs9IDMpIHtcblx0XHRcdHRlbXAgPSAodWludDhbaV0gPDwgMTYpICsgKHVpbnQ4W2kgKyAxXSA8PCA4KSArICh1aW50OFtpICsgMl0pXG5cdFx0XHRvdXRwdXQgKz0gdHJpcGxldFRvQmFzZTY0KHRlbXApXG5cdFx0fVxuXG5cdFx0Ly8gcGFkIHRoZSBlbmQgd2l0aCB6ZXJvcywgYnV0IG1ha2Ugc3VyZSB0byBub3QgZm9yZ2V0IHRoZSBleHRyYSBieXRlc1xuXHRcdHN3aXRjaCAoZXh0cmFCeXRlcykge1xuXHRcdFx0Y2FzZSAxOlxuXHRcdFx0XHR0ZW1wID0gdWludDhbdWludDgubGVuZ3RoIC0gMV1cblx0XHRcdFx0b3V0cHV0ICs9IGVuY29kZSh0ZW1wID4+IDIpXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUoKHRlbXAgPDwgNCkgJiAweDNGKVxuXHRcdFx0XHRvdXRwdXQgKz0gJz09J1xuXHRcdFx0XHRicmVha1xuXHRcdFx0Y2FzZSAyOlxuXHRcdFx0XHR0ZW1wID0gKHVpbnQ4W3VpbnQ4Lmxlbmd0aCAtIDJdIDw8IDgpICsgKHVpbnQ4W3VpbnQ4Lmxlbmd0aCAtIDFdKVxuXHRcdFx0XHRvdXRwdXQgKz0gZW5jb2RlKHRlbXAgPj4gMTApXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUoKHRlbXAgPj4gNCkgJiAweDNGKVxuXHRcdFx0XHRvdXRwdXQgKz0gZW5jb2RlKCh0ZW1wIDw8IDIpICYgMHgzRilcblx0XHRcdFx0b3V0cHV0ICs9ICc9J1xuXHRcdFx0XHRicmVha1xuXHRcdH1cblxuXHRcdHJldHVybiBvdXRwdXRcblx0fVxuXG5cdGV4cG9ydHMudG9CeXRlQXJyYXkgPSBiNjRUb0J5dGVBcnJheVxuXHRleHBvcnRzLmZyb21CeXRlQXJyYXkgPSB1aW50OFRvQmFzZTY0XG59KHR5cGVvZiBleHBvcnRzID09PSAndW5kZWZpbmVkJyA/ICh0aGlzLmJhc2U2NGpzID0ge30pIDogZXhwb3J0cykpXG4iLCJleHBvcnRzLnJlYWQgPSBmdW5jdGlvbiAoYnVmZmVyLCBvZmZzZXQsIGlzTEUsIG1MZW4sIG5CeXRlcykge1xuICB2YXIgZSwgbVxuICB2YXIgZUxlbiA9IG5CeXRlcyAqIDggLSBtTGVuIC0gMVxuICB2YXIgZU1heCA9ICgxIDw8IGVMZW4pIC0gMVxuICB2YXIgZUJpYXMgPSBlTWF4ID4+IDFcbiAgdmFyIG5CaXRzID0gLTdcbiAgdmFyIGkgPSBpc0xFID8gKG5CeXRlcyAtIDEpIDogMFxuICB2YXIgZCA9IGlzTEUgPyAtMSA6IDFcbiAgdmFyIHMgPSBidWZmZXJbb2Zmc2V0ICsgaV1cblxuICBpICs9IGRcblxuICBlID0gcyAmICgoMSA8PCAoLW5CaXRzKSkgLSAxKVxuICBzID4+PSAoLW5CaXRzKVxuICBuQml0cyArPSBlTGVuXG4gIGZvciAoOyBuQml0cyA+IDA7IGUgPSBlICogMjU2ICsgYnVmZmVyW29mZnNldCArIGldLCBpICs9IGQsIG5CaXRzIC09IDgpIHt9XG5cbiAgbSA9IGUgJiAoKDEgPDwgKC1uQml0cykpIC0gMSlcbiAgZSA+Pj0gKC1uQml0cylcbiAgbkJpdHMgKz0gbUxlblxuICBmb3IgKDsgbkJpdHMgPiAwOyBtID0gbSAqIDI1NiArIGJ1ZmZlcltvZmZzZXQgKyBpXSwgaSArPSBkLCBuQml0cyAtPSA4KSB7fVxuXG4gIGlmIChlID09PSAwKSB7XG4gICAgZSA9IDEgLSBlQmlhc1xuICB9IGVsc2UgaWYgKGUgPT09IGVNYXgpIHtcbiAgICByZXR1cm4gbSA/IE5hTiA6ICgocyA/IC0xIDogMSkgKiBJbmZpbml0eSlcbiAgfSBlbHNlIHtcbiAgICBtID0gbSArIE1hdGgucG93KDIsIG1MZW4pXG4gICAgZSA9IGUgLSBlQmlhc1xuICB9XG4gIHJldHVybiAocyA/IC0xIDogMSkgKiBtICogTWF0aC5wb3coMiwgZSAtIG1MZW4pXG59XG5cbmV4cG9ydHMud3JpdGUgPSBmdW5jdGlvbiAoYnVmZmVyLCB2YWx1ZSwgb2Zmc2V0LCBpc0xFLCBtTGVuLCBuQnl0ZXMpIHtcbiAgdmFyIGUsIG0sIGNcbiAgdmFyIGVMZW4gPSBuQnl0ZXMgKiA4IC0gbUxlbiAtIDFcbiAgdmFyIGVNYXggPSAoMSA8PCBlTGVuKSAtIDFcbiAgdmFyIGVCaWFzID0gZU1heCA+PiAxXG4gIHZhciBydCA9IChtTGVuID09PSAyMyA/IE1hdGgucG93KDIsIC0yNCkgLSBNYXRoLnBvdygyLCAtNzcpIDogMClcbiAgdmFyIGkgPSBpc0xFID8gMCA6IChuQnl0ZXMgLSAxKVxuICB2YXIgZCA9IGlzTEUgPyAxIDogLTFcbiAgdmFyIHMgPSB2YWx1ZSA8IDAgfHwgKHZhbHVlID09PSAwICYmIDEgLyB2YWx1ZSA8IDApID8gMSA6IDBcblxuICB2YWx1ZSA9IE1hdGguYWJzKHZhbHVlKVxuXG4gIGlmIChpc05hTih2YWx1ZSkgfHwgdmFsdWUgPT09IEluZmluaXR5KSB7XG4gICAgbSA9IGlzTmFOKHZhbHVlKSA/IDEgOiAwXG4gICAgZSA9IGVNYXhcbiAgfSBlbHNlIHtcbiAgICBlID0gTWF0aC5mbG9vcihNYXRoLmxvZyh2YWx1ZSkgLyBNYXRoLkxOMilcbiAgICBpZiAodmFsdWUgKiAoYyA9IE1hdGgucG93KDIsIC1lKSkgPCAxKSB7XG4gICAgICBlLS1cbiAgICAgIGMgKj0gMlxuICAgIH1cbiAgICBpZiAoZSArIGVCaWFzID49IDEpIHtcbiAgICAgIHZhbHVlICs9IHJ0IC8gY1xuICAgIH0gZWxzZSB7XG4gICAgICB2YWx1ZSArPSBydCAqIE1hdGgucG93KDIsIDEgLSBlQmlhcylcbiAgICB9XG4gICAgaWYgKHZhbHVlICogYyA+PSAyKSB7XG4gICAgICBlKytcbiAgICAgIGMgLz0gMlxuICAgIH1cblxuICAgIGlmIChlICsgZUJpYXMgPj0gZU1heCkge1xuICAgICAgbSA9IDBcbiAgICAgIGUgPSBlTWF4XG4gICAgfSBlbHNlIGlmIChlICsgZUJpYXMgPj0gMSkge1xuICAgICAgbSA9ICh2YWx1ZSAqIGMgLSAxKSAqIE1hdGgucG93KDIsIG1MZW4pXG4gICAgICBlID0gZSArIGVCaWFzXG4gICAgfSBlbHNlIHtcbiAgICAgIG0gPSB2YWx1ZSAqIE1hdGgucG93KDIsIGVCaWFzIC0gMSkgKiBNYXRoLnBvdygyLCBtTGVuKVxuICAgICAgZSA9IDBcbiAgICB9XG4gIH1cblxuICBmb3IgKDsgbUxlbiA+PSA4OyBidWZmZXJbb2Zmc2V0ICsgaV0gPSBtICYgMHhmZiwgaSArPSBkLCBtIC89IDI1NiwgbUxlbiAtPSA4KSB7fVxuXG4gIGUgPSAoZSA8PCBtTGVuKSB8IG1cbiAgZUxlbiArPSBtTGVuXG4gIGZvciAoOyBlTGVuID4gMDsgYnVmZmVyW29mZnNldCArIGldID0gZSAmIDB4ZmYsIGkgKz0gZCwgZSAvPSAyNTYsIGVMZW4gLT0gOCkge31cblxuICBidWZmZXJbb2Zmc2V0ICsgaSAtIGRdIHw9IHMgKiAxMjhcbn1cbiIsIlxuLyoqXG4gKiBpc0FycmF5XG4gKi9cblxudmFyIGlzQXJyYXkgPSBBcnJheS5pc0FycmF5O1xuXG4vKipcbiAqIHRvU3RyaW5nXG4gKi9cblxudmFyIHN0ciA9IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmc7XG5cbi8qKlxuICogV2hldGhlciBvciBub3QgdGhlIGdpdmVuIGB2YWxgXG4gKiBpcyBhbiBhcnJheS5cbiAqXG4gKiBleGFtcGxlOlxuICpcbiAqICAgICAgICBpc0FycmF5KFtdKTtcbiAqICAgICAgICAvLyA+IHRydWVcbiAqICAgICAgICBpc0FycmF5KGFyZ3VtZW50cyk7XG4gKiAgICAgICAgLy8gPiBmYWxzZVxuICogICAgICAgIGlzQXJyYXkoJycpO1xuICogICAgICAgIC8vID4gZmFsc2VcbiAqXG4gKiBAcGFyYW0ge21peGVkfSB2YWxcbiAqIEByZXR1cm4ge2Jvb2x9XG4gKi9cblxubW9kdWxlLmV4cG9ydHMgPSBpc0FycmF5IHx8IGZ1bmN0aW9uICh2YWwpIHtcbiAgcmV0dXJuICEhIHZhbCAmJiAnW29iamVjdCBBcnJheV0nID09IHN0ci5jYWxsKHZhbCk7XG59O1xuIiwibW9kdWxlLmV4cG9ydHM9e1xuICAgIFwidmVyc2lvblwiOiBcIlwiXG59XG4iLCIvKipcbiAqIEVwaWNlbnRlciBKYXZhc2NyaXB0IGxpYnJhcmllc1xuICogdjwlPSB2ZXJzaW9uICU+XG4gKiBodHRwczovL2dpdGh1Yi5jb20vZm9yaW8vZXBpY2VudGVyLWpzLWxpYnNcbiAqL1xuXG52YXIgRiA9IHtcbiAgICB1dGlsOiB7fSxcbiAgICBmYWN0b3J5OiB7fSxcbiAgICB0cmFuc3BvcnQ6IHt9LFxuICAgIHN0b3JlOiB7fSxcbiAgICBzZXJ2aWNlOiB7fSxcbiAgICBtYW5hZ2VyOiB7XG4gICAgICAgIHN0cmF0ZWd5OiB7fVxuICAgIH0sXG5cbn07XG5cbkYudXRpbC5xdWVyeSA9IHJlcXVpcmUoJy4vdXRpbC9xdWVyeS11dGlsJyk7XG5GLnV0aWwubWFrZVNlcXVlbmNlID0gcmVxdWlyZSgnLi91dGlsL21ha2Utc2VxdWVuY2UnKTtcbkYudXRpbC5ydW4gPSByZXF1aXJlKCcuL3V0aWwvcnVuLXV0aWwnKTtcbkYudXRpbC5jbGFzc0Zyb20gPSByZXF1aXJlKCcuL3V0aWwvaW5oZXJpdCcpO1xuXG5GLmZhY3RvcnkuVHJhbnNwb3J0ID0gcmVxdWlyZSgnLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xuRi50cmFuc3BvcnQuQWpheCA9IHJlcXVpcmUoJy4vdHJhbnNwb3J0L2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcblxuRi5zZXJ2aWNlLlVSTCA9IHJlcXVpcmUoJy4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcbkYuc2VydmljZS5Db25maWcgPSByZXF1aXJlKCcuL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuUnVuID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkZpbGUgPSByZXF1aXJlKCcuL3NlcnZpY2UvYWRtaW4tZmlsZS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuVmFyaWFibGVzID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3ZhcmlhYmxlcy1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkRhdGEgPSByZXF1aXJlKCcuL3NlcnZpY2UvZGF0YS1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkF1dGggPSByZXF1aXJlKCcuL3NlcnZpY2UvYXV0aC1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLldvcmxkID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG5GLnNlcnZpY2UuU3RhdGUgPSByZXF1aXJlKCcuL3NlcnZpY2Uvc3RhdGUtYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5Vc2VyID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3VzZXItYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5NZW1iZXIgPSByZXF1aXJlKCcuL3NlcnZpY2UvbWVtYmVyLWFwaS1hZGFwdGVyJyk7XG5GLnNlcnZpY2UuQXNzZXQgPSByZXF1aXJlKCcuL3NlcnZpY2UvYXNzZXQtYXBpLWFkYXB0ZXInKTtcblxuRi5zdG9yZS5Db29raWUgPSByZXF1aXJlKCcuL3N0b3JlL2Nvb2tpZS1zdG9yZScpO1xuRi5mYWN0b3J5LlN0b3JlID0gcmVxdWlyZSgnLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG5cbkYubWFuYWdlci5TY2VuYXJpb01hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL3NjZW5hcmlvLW1hbmFnZXInKTtcbkYubWFuYWdlci5SdW5NYW5hZ2VyID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tbWFuYWdlcicpO1xuRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9hdXRoLW1hbmFnZXInKTtcbkYubWFuYWdlci5Xb3JsZE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL3dvcmxkLW1hbmFnZXInKTtcblxuRi5tYW5hZ2VyLnN0cmF0ZWd5WydhbHdheXMtbmV3J10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2Fsd2F5cy1uZXctc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnY29uZGl0aW9uYWwtY3JlYXRpb24nXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvY29uZGl0aW9uYWwtY3JlYXRpb24tc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneS5pZGVudGl0eSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvaWRlbnRpdHktc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLW1pc3NpbmcnXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvbmV3LWlmLW1pc3Npbmctc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLW1pc3NpbmcnXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvbmV3LWlmLW1pc3Npbmctc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLXBlcnNpc3RlZCddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5Jyk7XG5GLm1hbmFnZXIuc3RyYXRlZ3lbJ25ldy1pZi1pbml0aWFsaXplZCddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtaW5pdGlhbGl6ZWQtc3RyYXRlZ3knKTtcblxuRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyJyk7XG5GLnNlcnZpY2UuQ2hhbm5lbCA9IHJlcXVpcmUoJy4vc2VydmljZS9jaGFubmVsLXNlcnZpY2UnKTtcblxuRi52ZXJzaW9uID0gJzwlPSB2ZXJzaW9uICU+JztcbkYuYXBpID0gcmVxdWlyZSgnLi9hcGktdmVyc2lvbi5qc29uJyk7XG5cbmdsb2JhbC5GID0gRjtcbm1vZHVsZS5leHBvcnRzID0gRjtcbiIsIi8qKlxuKiAjIyBBdXRob3JpemF0aW9uIE1hbmFnZXJcbipcbiogVGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBwcm92aWRlcyBhbiBlYXN5IHdheSB0byBtYW5hZ2UgdXNlciBhdXRoZW50aWNhdGlvbiAobG9nZ2luZyBpbiBhbmQgb3V0KSBhbmQgYXV0aG9yaXphdGlvbiAoa2VlcGluZyB0cmFjayBvZiB0b2tlbnMsIHNlc3Npb25zLCBhbmQgZ3JvdXBzKSBmb3IgcHJvamVjdHMuXG4qXG4qIFRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIgaXMgbW9zdCB1c2VmdWwgZm9yIFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9nbG9zc2FyeS8jdGVhbSkgd2l0aCBhbiBhY2Nlc3MgbGV2ZWwgb2YgW0F1dGhlbnRpY2F0ZWRdKC4uLy4uLy4uL2dsb3NzYXJ5LyNhY2Nlc3MpLiBUaGVzZSBwcm9qZWN0cyBhcmUgYWNjZXNzZWQgYnkgW2VuZCB1c2Vyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSB3aG8gYXJlIG1lbWJlcnMgb2Ygb25lIG9yIG1vcmUgW2dyb3Vwc10oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcykuXG4qXG4qICMjIyNVc2luZyB0aGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyXG4qXG4qIFRvIHVzZSB0aGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyLCBpbnN0YW50aWF0ZSBpdC4gVGhlbiwgbWFrZSBjYWxscyB0byBhbnkgb2YgdGhlIG1ldGhvZHMgeW91IG5lZWQ6XG4qXG4qICAgICAgIHZhciBhdXRoTWdyID0gbmV3IEYubWFuYWdlci5BdXRoTWFuYWdlcih7XG4qICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgICB1c2VyTmFtZTogJ2VuZHVzZXIxJyxcbiogICAgICAgICAgIHBhc3N3b3JkOiAncGFzc3cwcmQnXG4qICAgICAgIH0pO1xuKiAgICAgICBhdXRoTWdyLmxvZ2luKCkudGhlbihmdW5jdGlvbiAoKSB7XG4qICAgICAgICAgICBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiogICAgICAgfSk7XG4qXG4qXG4qIFRoZSBgb3B0aW9uc2Agb2JqZWN0IHBhc3NlZCB0byB0aGUgYEYubWFuYWdlci5BdXRoTWFuYWdlcigpYCBjYWxsIGNhbiBpbmNsdWRlOlxuKlxuKiAgICogYGFjY291bnRgOiBUaGUgYWNjb3VudCBpZCBmb3IgdGhpcyBgdXNlck5hbWVgLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yIHRoZSAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS5cbiogICAqIGB1c2VyTmFtZWA6IEVtYWlsIG9yIHVzZXJuYW1lIHRvIHVzZSBmb3IgbG9nZ2luZyBpbi5cbiogICAqIGBwYXNzd29yZGA6IFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGUgcHJvamVjdCB0byBsb2cgdGhpcyB1c2VyIGludG8uIE9wdGlvbmFsLlxuKiAgICogYGdyb3VwSWRgOiBJZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggYHVzZXJOYW1lYCBiZWxvbmdzLiBSZXF1aXJlZCBmb3IgZW5kIHVzZXJzIGlmIHRoZSBgcHJvamVjdGAgaXMgc3BlY2lmaWVkLlxuKlxuKiBJZiB5b3UgcHJlZmVyIHN0YXJ0aW5nIGZyb20gYSB0ZW1wbGF0ZSwgdGhlIEVwaWNlbnRlciBKUyBMaWJzIFtMb2dpbiBDb21wb25lbnRdKC4uLy4uLyNjb21wb25lbnRzKSB1c2VzIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIgYXMgd2VsbC4gVGhpcyBzYW1wbGUgSFRNTCBwYWdlIChhbmQgYXNzb2NpYXRlZCBDU1MgYW5kIEpTIGZpbGVzKSBwcm92aWRlcyBhIGxvZ2luIGZvcm0gZm9yIHRlYW0gbWVtYmVycyBhbmQgZW5kIHVzZXJzIG9mIHlvdXIgcHJvamVjdC4gSXQgYWxzbyBpbmNsdWRlcyBhIGdyb3VwIHNlbGVjdG9yIGZvciBlbmQgdXNlcnMgdGhhdCBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBncm91cHMuXG4qL1xuXG4ndXNlIHN0cmljdCc7XG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgQXV0aEFkYXB0ZXIgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL2F1dGgtYXBpLXNlcnZpY2UnKTtcbnZhciBNZW1iZXJBZGFwdGVyID0gcmVxdWlyZSgnLi4vc2VydmljZS9tZW1iZXItYXBpLWFkYXB0ZXInKTtcbnZhciBTdG9yYWdlRmFjdG9yeSA9IHJlcXVpcmUoJy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbnZhciBCdWZmZXIgPSByZXF1aXJlKCdidWZmZXInKS5CdWZmZXI7XG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuL2tleS1uYW1lcycpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgLyoqXG4gICAgICogV2hlcmUgdG8gc3RvcmUgdXNlciBhY2Nlc3MgdG9rZW5zIGZvciB0ZW1wb3JhcnkgYWNjZXNzLiBEZWZhdWx0cyB0byBzdG9yaW5nIGluIGEgY29va2llIGluIHRoZSBicm93c2VyLlxuICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICovXG4gICAgc3RvcmU6IHsgc3luY2hyb25vdXM6IHRydWUgfVxufTtcblxudmFyIEVQSV9DT09LSUVfS0VZID0ga2V5TmFtZXMuRVBJX0NPT0tJRV9LRVk7XG52YXIgRVBJX1NFU1NJT05fS0VZID0ga2V5TmFtZXMuRVBJX1NFU1NJT05fS0VZO1xudmFyIHRva2VuO1xudmFyIHNlc3Npb247XG5cbmZ1bmN0aW9uIHNhdmVTZXNzaW9uKHVzZXJJbmZvLCBzdG9yZSkge1xuICAgIHZhciBzZXJpYWxpemVkID0gSlNPTi5zdHJpbmdpZnkodXNlckluZm8pO1xuICAgIHN0b3JlLnNldChFUElfU0VTU0lPTl9LRVksIHNlcmlhbGl6ZWQpO1xuXG4gICAgLy9qc2hpbnQgY2FtZWxjYXNlOiBmYWxzZVxuICAgIC8vanNjczpkaXNhYmxlXG4gICAgc3RvcmUuc2V0KEVQSV9DT09LSUVfS0VZLCB1c2VySW5mby5hdXRoX3Rva2VuKTtcbn1cblxuZnVuY3Rpb24gZ2V0U2Vzc2lvbihzdG9yZSkge1xuICAgIHZhciBzZXNzaW9uID0gc3RvcmUuZ2V0KEVQSV9TRVNTSU9OX0tFWSkgfHwgJ3t9JztcbiAgICByZXR1cm4gSlNPTi5wYXJzZShzZXNzaW9uKTtcbn1cblxuZnVuY3Rpb24gQXV0aE1hbmFnZXIob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgb3B0aW9ucyk7XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2UodGhpcy5vcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIHRoaXMuaXNMb2NhbCA9IHVybENvbmZpZy5pc0xvY2FsaG9zdCgpO1xuXG4gICAgaWYgKCF0aGlzLm9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB0aGlzLm9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICAvLyBudWxsIG1pZ2h0IHNwZWNpZmllZCB0byBkaXNhYmxlIHByb2plY3QgZmlsdGVyaW5nXG4gICAgaWYgKHRoaXMub3B0aW9ucy5wcm9qZWN0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhpcy5vcHRpb25zLnByb2plY3QgPSB1cmxDb25maWcucHJvamVjdFBhdGg7XG4gICAgfVxuXG4gICAgdGhpcy5zdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh0aGlzLm9wdGlvbnMuc3RvcmUpO1xuICAgIHNlc3Npb24gPSBnZXRTZXNzaW9uKHRoaXMuc3RvcmUpO1xuICAgIHRva2VuID0gdGhpcy5zdG9yZS5nZXQoRVBJX0NPT0tJRV9LRVkpIHx8ICcnO1xuICAgIC8vanNoaW50IGNhbWVsY2FzZTogZmFsc2VcbiAgICAvL2pzY3M6ZGlzYWJsZVxuICAgIHRoaXMuYXV0aEFkYXB0ZXIgPSBuZXcgQXV0aEFkYXB0ZXIodGhpcy5vcHRpb25zLCB7IHRva2VuOiBzZXNzaW9uLmF1dGhfdG9rZW4gfSk7XG59XG5cbnZhciBfZmluZFVzZXJJbkdyb3VwID0gZnVuY3Rpb24gKG1lbWJlcnMsIGlkKSB7XG4gICAgZm9yICh2YXIgaiA9IDA7IGo8bWVtYmVycy5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAobWVtYmVyc1tqXS51c2VySWQgPT09IGlkKSB7XG4gICAgICAgICAgICByZXR1cm4gbWVtYmVyc1tqXTtcbiAgICAgICAgfVxuICAgIH1cblxuXG4gICAgcmV0dXJuIG51bGw7XG59O1xuXG5BdXRoTWFuYWdlci5wcm90b3R5cGUgPSAkLmV4dGVuZChBdXRoTWFuYWdlci5wcm90b3R5cGUsIHtcblxuICAgIC8qKlxuICAgICogTG9ncyB1c2VyIGluLlxuICAgICpcbiAgICAqICoqRXhhbXBsZSoqXG4gICAgKlxuICAgICogICAgICAgYXV0aE1nci5sb2dpbih7XG4gICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgKiAgICAgICAgICAgdXNlck5hbWU6ICdlbmR1c2VyMScsXG4gICAgKiAgICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCdcbiAgICAqICAgICAgIH0pXG4gICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oc3RhdHVzT2JqKSB7XG4gICAgKiAgICAgICAgICAgICAgIC8vIGlmIGVuZHVzZXIxIGJlbG9uZ3MgdG8gZXhhY3RseSBvbmUgZ3JvdXBcbiAgICAqICAgICAgICAgICAgICAgLy8gKG9yIGlmIHRoZSBsb2dpbigpIGNhbGwgaXMgbW9kaWZpZWQgdG8gaW5jbHVkZSB0aGUgZ3JvdXAgaWQpXG4gICAgKiAgICAgICAgICAgICAgIC8vIGNvbnRpbnVlIGhlcmVcbiAgICAqICAgICAgICAgICB9KVxuICAgICogICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uKHN0YXR1c09iaikge1xuICAgICogICAgICAgICAgICAgICAvLyBpZiBlbmR1c2VyMSBiZWxvbmdzIHRvIG11bHRpcGxlIGdyb3VwcyxcbiAgICAqICAgICAgICAgICAgICAgLy8gdGhlIGxvZ2luKCkgY2FsbCBmYWlsc1xuICAgICogICAgICAgICAgICAgICAvLyBhbmQgcmV0dXJucyBhbGwgZ3JvdXBzIG9mIHdoaWNoIHRoZSB1c2VyIGlzIGEgbWVtYmVyXG4gICAgKiAgICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IHN0YXR1c09iai51c2VyR3JvdXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgKiAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzdGF0dXNPYmoudXNlckdyb3Vwc1tpXS5uYW1lLCBzdGF0dXNPYmoudXNlckdyb3Vwc1tpXS5ncm91cElkKTtcbiAgICAqICAgICAgICAgICAgICAgfVxuICAgICogICAgICAgICAgIH0pO1xuICAgICpcbiAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgKlxuICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLiBJZiBub3QgcGFzc2VkIGluIHdoZW4gY3JlYXRpbmcgYW4gaW5zdGFuY2Ugb2YgdGhlIG1hbmFnZXIgKGBGLm1hbmFnZXIuQXV0aE1hbmFnZXIoKWApLCB0aGVzZSBvcHRpb25zIHNob3VsZCBpbmNsdWRlOlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLmFjY291bnRgIFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLnVzZXJOYW1lYCBFbWFpbCBvciB1c2VybmFtZSB0byB1c2UgZm9yIGxvZ2dpbmcgaW4uXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gYG9wdGlvbnMucGFzc3dvcmRgIFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5wcm9qZWN0YCAoT3B0aW9uYWwpIFRoZSAqKlByb2plY3QgSUQqKiBmb3IgdGhlIHByb2plY3QgdG8gbG9nIHRoaXMgdXNlciBpbnRvLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLmdyb3VwSWRgIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggYHVzZXJOYW1lYCBiZWxvbmdzLiBSZXF1aXJlZCBmb3IgW2VuZCB1c2Vyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSBpZiB0aGUgYHByb2plY3RgIGlzIHNwZWNpZmllZCBhbmQgaWYgdGhlIGVuZCB1c2VycyBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSwgb3RoZXJ3aXNlIG9wdGlvbmFsLlxuICAgICovXG4gICAgbG9naW46IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIGFkYXB0ZXJPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgeyBzdWNjZXNzOiAkLm5vb3AsIGVycm9yOiAkLm5vb3AgfSwgdGhpcy5vcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyIG91dFN1Y2Nlc3MgPSBhZGFwdGVyT3B0aW9ucy5zdWNjZXNzO1xuICAgICAgICB2YXIgb3V0RXJyb3IgPSBhZGFwdGVyT3B0aW9ucy5lcnJvcjtcbiAgICAgICAgdmFyIGdyb3VwSWQgPSBhZGFwdGVyT3B0aW9ucy5ncm91cElkO1xuXG4gICAgICAgIHZhciBhY2NvdW50TmFtZSA9IChvcHRpb25zICYmIG9wdGlvbnMuYWNjb3VudCkgPyBvcHRpb25zLmFjY291bnQgOiB0aGlzLm9wdGlvbnMuYWNjb3VudDtcbiAgICAgICAgdmFyIHByb2plY3ROYW1lID0gKG9wdGlvbnMgJiYgb3B0aW9ucy5wcm9qZWN0KSA/IG9wdGlvbnMucHJvamVjdCA6IHRoaXMub3B0aW9ucy5wcm9qZWN0O1xuXG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMuc3RvcmUucm9vdCA9PT0gdW5kZWZpbmVkICYmIGFjY291bnROYW1lICYmIHByb2plY3ROYW1lKSB7XG4gICAgICAgICAgICB0aGlzLnN0b3JlLnNlcnZpY2VPcHRpb25zLnJvb3QgPSB0aGlzLmlzTG9jYWwgPyAnLycgOiAnL2FwcC8nICsgYWNjb3VudE5hbWUgKyAnLycgKyBwcm9qZWN0TmFtZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBkZWNvZGVUb2tlbiA9IGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICAgICAgdmFyIGVuY29kZWQgPSB0b2tlbi5zcGxpdCgnLicpWzFdO1xuICAgICAgICAgICAgd2hpbGUgKGVuY29kZWQubGVuZ3RoICUgNCAhPT0gMCkge1xuICAgICAgICAgICAgICAgIGVuY29kZWQgKz0gJz0nO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZGVjb2RlID0gd2luZG93LmF0b2IgPyB3aW5kb3cuYXRvYiA6IGZ1bmN0aW9uIChlbmNvZGVkKSB7IHJldHVybiBuZXcgQnVmZmVyKGVuY29kZWQsICdiYXNlNjQnKS50b1N0cmluZygnYXNjaWknKTsgfTtcblxuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoZGVjb2RlKGVuY29kZWQpKTtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgaGFuZGxlR3JvdXBFcnJvciA9IGZ1bmN0aW9uIChtZXNzYWdlLCBzdGF0dXNDb2RlLCBkYXRhKSB7XG4gICAgICAgICAgICAvLyBsb2dvdXQgdGhlIHVzZXIgc2luY2UgaXQncyBpbiBhbiBpbnZhbGlkIHN0YXRlIHdpdGggbm8gZ3JvdXAgc2VsZWN0ZWRcbiAgICAgICAgICAgIF90aGlzLmxvZ291dCgpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBlcnJvciA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkYXRhLCB7IHN0YXR1c1RleHQ6IG1lc3NhZ2UsIHN0YXR1czogc3RhdHVzQ29kZSB9KTtcbiAgICAgICAgICAgICAgICAkZC5yZWplY3QoZXJyb3IpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIGhhbmRsZVN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgIC8vanNoaW50IGNhbWVsY2FzZTogZmFsc2VcbiAgICAgICAgICAgIC8vanNjczpkaXNhYmxlXG4gICAgICAgICAgICB0b2tlbiA9IHJlc3BvbnNlLmFjY2Vzc190b2tlbjtcbiAgICAgICAgICAgIHZhciB1c2VySW5mbyA9IGRlY29kZVRva2VuKHRva2VuKTtcbiAgICAgICAgICAgIHZhciB1c2VyR3JvdXBPcHRzID0gJC5leHRlbmQodHJ1ZSwge30sIGFkYXB0ZXJPcHRpb25zLCB7IHN1Y2Nlc3M6ICQubm9vcCwgdG9rZW46IHRva2VuIH0pO1xuICAgICAgICAgICAgX3RoaXMuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogdXNlckluZm8udXNlcl9pZCwgdG9rZW46IHRva2VuIH0sIHVzZXJHcm91cE9wdHMpLmRvbmUoIGZ1bmN0aW9uIChtZW1iZXJJbmZvKSB7XG4gICAgICAgICAgICAgICAgdmFyIGRhdGEgPSB7YXV0aDogcmVzcG9uc2UsIHVzZXI6IHVzZXJJbmZvLCB1c2VyR3JvdXBzOiBtZW1iZXJJbmZvLCBncm91cFNlbGVjdGlvbjoge30gfTtcblxuICAgICAgICAgICAgICAgIHZhciBzZXNzaW9uSW5mbyA9IHtcbiAgICAgICAgICAgICAgICAgICAgJ2F1dGhfdG9rZW4nOiB0b2tlbixcbiAgICAgICAgICAgICAgICAgICAgJ2FjY291bnQnOiBhZGFwdGVyT3B0aW9ucy5hY2NvdW50LFxuICAgICAgICAgICAgICAgICAgICAncHJvamVjdCc6IGFkYXB0ZXJPcHRpb25zLnByb2plY3QsXG4gICAgICAgICAgICAgICAgICAgICd1c2VySWQnOiB1c2VySW5mby51c2VyX2lkXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAvLyBUaGUgZ3JvdXAgaXMgbm90IHJlcXVpcmVkIGlmIHRoZSB1c2VyIGlzIG5vdCBsb2dnaW5nIGludG8gYSBwcm9qZWN0XG4gICAgICAgICAgICAgICAgaWYgKCFhZGFwdGVyT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHNhdmVTZXNzaW9uKHNlc3Npb25JbmZvLCBfdGhpcy5zdG9yZSk7XG4gICAgICAgICAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW2RhdGFdKTtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBncm91cCA9IG51bGw7XG4gICAgICAgICAgICAgICAgaWYgKG1lbWJlckluZm8ubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGhhbmRsZUdyb3VwRXJyb3IoJ1RoZSB1c2VyIGhhcyBubyBncm91cHMgYXNzb2NpYXRlZCBpbiB0aGlzIGFjY291bnQnLCA0MDEsIGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChtZW1iZXJJbmZvLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBTZWxlY3QgdGhlIG9ubHkgZ3JvdXBcbiAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBtZW1iZXJJbmZvWzBdO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAobWVtYmVySW5mby5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChncm91cElkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZmlsdGVyZWRHcm91cHMgPSAkLmdyZXAobWVtYmVySW5mbywgZnVuY3Rpb24gKHJlc0dyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc0dyb3VwLmdyb3VwSWQgPT09IGdyb3VwSWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gZmlsdGVyZWRHcm91cHMubGVuZ3RoID09PSAxID8gZmlsdGVyZWRHcm91cHNbMF0gOiBudWxsO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBncm91cFNlbGVjdGlvbiA9IGdyb3VwLmdyb3VwSWQ7XG4gICAgICAgICAgICAgICAgICAgIGRhdGEuZ3JvdXBTZWxlY3Rpb25bYWRhcHRlck9wdGlvbnMucHJvamVjdF0gPSBncm91cFNlbGVjdGlvbjtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHNlc3Npb25JbmZvV2l0aEdyb3VwID0gJC5leHRlbmQoe30sIHNlc3Npb25JbmZvLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICAnZ3JvdXBJZCc6IGdyb3VwLmdyb3VwSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAnZ3JvdXBOYW1lJzogZ3JvdXAubmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICdpc0ZhYyc6IF9maW5kVXNlckluR3JvdXAoZ3JvdXAubWVtYmVycywgdXNlckluZm8udXNlcl9pZCkucm9sZSA9PT0gJ2ZhY2lsaXRhdG9yJ1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgc2F2ZVNlc3Npb24oc2Vzc2lvbkluZm9XaXRoR3JvdXAsIF90aGlzLnN0b3JlKTtcbiAgICAgICAgICAgICAgICAgICAgb3V0U3VjY2Vzcy5hcHBseSh0aGlzLCBbZGF0YV0pO1xuICAgICAgICAgICAgICAgICAgICAkZC5yZXNvbHZlKGRhdGEpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGhhbmRsZUdyb3VwRXJyb3IoJ1RoaXMgdXNlciBpcyBhc3NvY2lhdGVkIHdpdGggbW9yZSB0aGFuIG9uZSBncm91cC4gUGxlYXNlIHNwZWNpZnkgYSBncm91cCBpZCB0byBsb2cgaW50byBhbmQgdHJ5IGFnYWluJywgNDAzLCBkYXRhKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KS5mYWlsKCRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgYWRhcHRlck9wdGlvbnMuc3VjY2VzcyA9IGhhbmRsZVN1Y2Nlc3M7XG4gICAgICAgIGFkYXB0ZXJPcHRpb25zLmVycm9yID0gZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICBpZiAoYWRhcHRlck9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICAgICAgICAgIC8vIFRyeSB0byBsb2dpbiBhcyBhIHN5c3RlbSB1c2VyXG4gICAgICAgICAgICAgICAgYWRhcHRlck9wdGlvbnMuYWNjb3VudCA9IG51bGw7XG4gICAgICAgICAgICAgICAgYWRhcHRlck9wdGlvbnMuZXJyb3IgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIG91dEVycm9yLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlamVjdChyZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgIF90aGlzLmF1dGhBZGFwdGVyLmxvZ2luKGFkYXB0ZXJPcHRpb25zKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG91dEVycm9yLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAkZC5yZWplY3QocmVzcG9uc2UpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMuYXV0aEFkYXB0ZXIubG9naW4oYWRhcHRlck9wdGlvbnMpO1xuICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAqIExvZ3MgdXNlciBvdXQuXG4gICAgKlxuICAgICogKipFeGFtcGxlKipcbiAgICAqXG4gICAgKiAgICAgICBhdXRoTWdyLmxvZ291dCgpO1xuICAgICpcbiAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgKlxuICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICovXG4gICAgbG9nb3V0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB2YXIgYWRhcHRlck9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7IHRva2VuOiB0b2tlbiB9LCB0aGlzLm9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciByZW1vdmVDb29raWVGbiA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgX3RoaXMuc3RvcmUucmVtb3ZlKEVQSV9DT09LSUVfS0VZLCBhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICBfdGhpcy5zdG9yZS5yZW1vdmUoRVBJX1NFU1NJT05fS0VZLCBhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICB0b2tlbiA9ICcnO1xuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiB0aGlzLmF1dGhBZGFwdGVyLmxvZ291dChhZGFwdGVyT3B0aW9ucykuZG9uZShyZW1vdmVDb29raWVGbik7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGV4aXN0aW5nIHVzZXIgYWNjZXNzIHRva2VuIGlmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluLiBPdGhlcndpc2UsIGxvZ3MgdGhlIHVzZXIgaW4sIGNyZWF0aW5nIGEgbmV3IHVzZXIgYWNjZXNzIHRva2VuLCBhbmQgcmV0dXJucyB0aGUgbmV3IHRva2VuLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBhdXRoTWdyLmdldFRva2VuKClcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgKiAgICAgICAgICAgICAgY29uc29sZS5sb2coJ015IHRva2VuIGlzICcsIHRva2VuKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldFRva2VuOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB0aGlzLm9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgaWYgKHRva2VuKSB7XG4gICAgICAgICAgICAkZC5yZXNvbHZlKHRva2VuKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMubG9naW4oaHR0cE9wdGlvbnMpLnRoZW4oJGQucmVzb2x2ZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhbiBhcnJheSBvZiBncm91cCByZWNvcmRzLCBvbmUgZm9yIGVhY2ggZ3JvdXAgb2Ygd2hpY2ggdGhlIGN1cnJlbnQgdXNlciBpcyBhIG1lbWJlci4gRWFjaCBncm91cCByZWNvcmQgaW5jbHVkZXMgdGhlIGdyb3VwIGBuYW1lYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgZ3JvdXBJZGAuXG4gICAgICpcbiAgICAgKiBJZiBzb21lIGVuZCB1c2VycyBpbiB5b3VyIHByb2plY3QgYXJlIG1lbWJlcnMgb2YgbXVsdGlwbGUgZ3JvdXBzLCB0aGlzIGlzIGEgdXNlZnVsIG1ldGhvZCB0byBjYWxsIG9uIHlvdXIgcHJvamVjdCdzIGxvZ2luIHBhZ2UuIFdoZW4gdGhlIHVzZXIgYXR0ZW1wdHMgdG8gbG9nIGluLCB5b3UgY2FuIHVzZSB0aGlzIHRvIGRpc3BsYXkgdGhlIGdyb3VwcyBvZiB3aGljaCB0aGUgdXNlciBpcyBtZW1iZXIsIGFuZCBoYXZlIHRoZSB1c2VyIHNlbGVjdCB0aGUgY29ycmVjdCBncm91cCB0byBsb2cgaW4gdG8gZm9yIHRoaXMgc2Vzc2lvbi5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIGN1cnJlbnQgdXNlclxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKiAgICAgIGF1dGhNZ3IuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogc2Vzc2lvbk9iai51c2VySWQsIHRva2VuOiBzZXNzaW9uT2JqLmF1dGhfdG9rZW4gfSlcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAoZ3JvdXBzKSB7XG4gICAgICogICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IGdyb3Vwcy5sZW5ndGg7IGkrKylcbiAgICAgKiAgICAgICAgICAgICAgICAgIHsgY29uc29sZS5sb2coZ3JvdXBzW2ldLm5hbWUpOyB9XG4gICAgICogICAgICAgICAgfSk7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIHBhcnRpY3VsYXIgdXNlclxuICAgICAqICAgICAgYXV0aE1nci5nZXRVc2VyR3JvdXBzKHt1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB0b2tlbjogc2F2ZWRQcm9qQWNjZXNzVG9rZW4gfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgcGFyYW1zYCBPYmplY3Qgd2l0aCBhIHVzZXJJZCBhbmQgdG9rZW4gcHJvcGVydGllcy5cbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gYHBhcmFtcy51c2VySWRgIFRoZSB1c2VySWQuIElmIGxvb2tpbmcgdXAgZ3JvdXBzIGZvciB0aGUgY3VycmVudGx5IGxvZ2dlZCBpbiB1c2VyLCB0aGlzIGlzIGluIHRoZSBzZXNzaW9uIGluZm9ybWF0aW9uLiBPdGhlcndpc2UsIHBhc3MgYSBzdHJpbmcuXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IGBwYXJhbXMudG9rZW5gIFRoZSBhdXRob3JpemF0aW9uIGNyZWRlbnRpYWxzIChhY2Nlc3MgdG9rZW4pIHRvIHVzZSBmb3IgY2hlY2tpbmcgdGhlIGdyb3VwcyBmb3IgdGhpcyB1c2VyLiBJZiBsb29raW5nIHVwIGdyb3VwcyBmb3IgdGhlIGN1cnJlbnRseSBsb2dnZWQgaW4gdXNlciwgdGhpcyBpcyBpbiB0aGUgc2Vzc2lvbiBpbmZvcm1hdGlvbi4gQSB0ZWFtIG1lbWJlcidzIHRva2VuIG9yIGEgcHJvamVjdCBhY2Nlc3MgdG9rZW4gY2FuIGFjY2VzcyBhbGwgdGhlIGdyb3VwcyBmb3IgYWxsIGVuZCB1c2VycyBpbiB0aGUgdGVhbSBvciBwcm9qZWN0LlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgKi9cbiAgICBnZXRVc2VyR3JvdXBzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBhZGFwdGVyT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHsgc3VjY2VzczogJC5ub29wIH0sIHRoaXMub3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIG91dFN1Y2Nlc3MgPSBhZGFwdGVyT3B0aW9ucy5zdWNjZXNzO1xuXG4gICAgICAgIGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAobWVtYmVySW5mbykge1xuICAgICAgICAgICAgLy8gVGhlIG1lbWJlciBBUEkgaXMgYXQgdGhlIGFjY291bnQgc2NvcGUsIHdlIGZpbHRlciBieSBwcm9qZWN0XG4gICAgICAgICAgICBpZiAoYWRhcHRlck9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICAgICAgICAgIG1lbWJlckluZm8gPSAkLmdyZXAobWVtYmVySW5mbywgZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBncm91cC5wcm9qZWN0ID09PSBhZGFwdGVyT3B0aW9ucy5wcm9qZWN0O1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBvdXRTdWNjZXNzLmFwcGx5KHRoaXMsIFttZW1iZXJJbmZvXSk7XG4gICAgICAgICAgICAkZC5yZXNvbHZlKG1lbWJlckluZm8pO1xuICAgICAgICB9O1xuXG4gICAgICAgIHZhciBtZW1iZXJBZGFwdGVyID0gbmV3IE1lbWJlckFkYXB0ZXIoeyB0b2tlbjogcGFyYW1zLnRva2VuIH0pO1xuICAgICAgICBtZW1iZXJBZGFwdGVyLmdldEdyb3Vwc0ZvclVzZXIocGFyYW1zLCBhZGFwdGVyT3B0aW9ucykuZmFpbCgkZC5yZWplY3QpO1xuICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHNlc3Npb24gaW5mb3JtYXRpb24gZm9yIHRoZSBjdXJyZW50IHVzZXIsIGluY2x1ZGluZyB0aGUgYHVzZXJJZGAsIGBhY2NvdW50YCwgYHByb2plY3RgLCBgZ3JvdXBJZGAsIGBncm91cE5hbWVgLCBgaXNGYWNgICh3aGV0aGVyIHRoZSBlbmQgdXNlciBpcyBhIGZhY2lsaXRhdG9yIG9mIHRoaXMgZ3JvdXApLCBhbmQgYGF1dGhfdG9rZW5gICh1c2VyIGFjY2VzcyB0b2tlbikuXG4gICAgICpcbiAgICAgKiAqSW1wb3J0YW50KjogVGhpcyBtZXRob2QgaXMgc3luY2hyb25vdXMuIFRoZSBzZXNzaW9uIGluZm9ybWF0aW9uIGlzIHJldHVybmVkIGltbWVkaWF0ZWx5IGluIGFuIG9iamVjdDsgbm8gY2FsbGJhY2tzIG9yIHByb21pc2VzIGFyZSBuZWVkZWQuXG4gICAgICpcbiAgICAgKiBCeSBkZWZhdWx0LCBzZXNzaW9uIGluZm9ybWF0aW9uIGlzIHN0b3JlZCBpbiBhIGNvb2tpZSBpbiB0aGUgYnJvd3Nlci4gWW91IGNhbiBjaGFuZ2UgdGhpcyB3aXRoIHRoZSBgc3RvcmVgIGNvbmZpZ3VyYXRpb24gb3B0aW9uLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm86IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiBnZXRTZXNzaW9uKHRoaXMuc3RvcmUsIG9wdGlvbnMpO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEF1dGhNYW5hZ2VyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ2hhbm5lbCA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlJyk7XG5cbi8qKlxuICogIyMgQ2hhbm5lbCBNYW5hZ2VyXG4gKlxuICogVGhlcmUgYXJlIHR3byBtYWluIHVzZSBjYXNlcyBmb3IgdGhlIGNoYW5uZWw6IGV2ZW50IG5vdGlmaWNhdGlvbnMgYW5kIGNoYXQgbWVzc2FnZXMuXG4gKlxuICogVGhlIENoYW5uZWwgTWFuYWdlciBpcyBhIHdyYXBwZXIgYXJvdW5kIHRoZSBkZWZhdWx0IFtjb21ldGQgSmF2YVNjcmlwdCBsaWJyYXJ5XShodHRwOi8vZG9jcy5jb21ldGQub3JnLzIvcmVmZXJlbmNlL2phdmFzY3JpcHQuaHRtbCksIGAkLmNvbWV0ZGAuIEl0IHByb3ZpZGVzIGEgZmV3IG5pY2UgZmVhdHVyZXMgdGhhdCBgJC5jb21ldGRgIGRvZXNuJ3QsIGluY2x1ZGluZzpcbiAqXG4gKiAqIEF1dG9tYXRpYyByZS1zdWJzY3JpcHRpb24gdG8gY2hhbm5lbHMgaWYgeW91IGxvc2UgeW91ciBjb25uZWN0aW9uXG4gKiAqIE9ubGluZSAvIE9mZmxpbmUgbm90aWZpY2F0aW9uc1xuICogKiAnRXZlbnRzJyBmb3IgY29tZXRkIG5vdGlmaWNhdGlvbnMgKGluc3RlYWQgb2YgaGF2aW5nIHRvIGxpc3RlbiBvbiBzcGVjaWZpYyBtZXRhIGNoYW5uZWxzKVxuICpcbiAqIFdoaWxlIHlvdSBjYW4gd29yayBkaXJlY3RseSB3aXRoIHRoZSBDaGFubmVsIE1hbmFnZXIgdGhyb3VnaCBOb2RlLmpzIChmb3IgZXhhbXBsZSwgYHJlcXVpcmUoJ21hbmFnZXIvY2hhbm5lbC1tYW5hZ2VyJylgKSAtLSBvciBldmVuIHdvcmsgZGlyZWN0bHkgd2l0aCBgJC5jb21ldGRgIGFuZCBFcGljZW50ZXIncyB1bmRlcmx5aW5nIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIC0tIG1vc3Qgb2Z0ZW4gaXQgd2lsbCBiZSBlYXNpZXN0IHRvIHdvcmsgd2l0aCB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKS4gVGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaXMgYSB3cmFwcGVyIHRoYXQgaW5zdGFudGlhdGVzIGEgQ2hhbm5lbCBNYW5hZ2VyIHdpdGggRXBpY2VudGVyLXNwZWNpZmljIGRlZmF1bHRzLlxuICpcbiAqIFlvdSdsbCBuZWVkIHRvIGluY2x1ZGUgdGhlIGBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzYCBsaWJyYXJ5IGluIGFkZGl0aW9uIHRvIHRoZSBgZXBpY2VudGVyLmpzYCBsaWJyYXJ5IGluIHlvdXIgcHJvamVjdCB0byB1c2UgdGhlIENoYW5uZWwgTWFuYWdlci4gKFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLilcbiAqXG4gKiBUbyB1c2UgdGhlIENoYW5uZWwgTWFuYWdlciBpbiBjbGllbnQtc2lkZSBKYXZhU2NyaXB0LCBpbnN0YW50aWF0ZSB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKSwgZ2V0IHRoZSBjaGFubmVsLCB0aGVuIHVzZSB0aGUgY2hhbm5lbCdzIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gc3Vic2NyaWJlIHRvIHRvcGljcyBvciBwdWJsaXNoIGRhdGEgdG8gdG9waWNzLlxuICpcbiAqICAgICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gKiAgICAgICAgdmFyIGNoYW5uZWwgPSBjbS5nZXRDaGFubmVsKCk7XG4gKlxuICogICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCd0b3BpYycsIGNhbGxiYWNrKTtcbiAqICAgICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIFRoZSBvcHRpb25zIG9iamVjdCB0byBjb25maWd1cmUgdGhlIENoYW5uZWwgTWFuYWdlci4gQmVzaWRlcyB0aGUgY29tbW9uIG9wdGlvbnMgbGlzdGVkIGhlcmUsIHNlZSBodHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0Lmh0bWwgZm9yIG90aGVyIHN1cHBvcnRlZCBvcHRpb25zLlxuICogKiBgb3B0aW9ucy51cmxgIFRoZSBDb21ldGQgZW5kcG9pbnQgVVJMLlxuICogKiBgb3B0aW9ucy53ZWJzb2NrZXRFbmFibGVkYCBXaGV0aGVyIHdlYnNvY2tldCBzdXBwb3J0IGlzIGFjdGl2ZSAoYm9vbGVhbikuXG4gKiAqIGBvcHRpb25zLmNoYW5uZWxgIE90aGVyIGRlZmF1bHRzIHRvIHBhc3Mgb24gdG8gaW5zdGFuY2VzIG9mIHRoZSB1bmRlcmx5aW5nIENoYW5uZWwgU2VydmljZS4gU2VlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pIGZvciBkZXRhaWxzLlxuICpcbiAqL1xudmFyIENoYW5uZWxNYW5hZ2VyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICBpZiAoISQuY29tZXRkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignQ29tZXRkIGxpYnJhcnkgbm90IGZvdW5kLiBQbGVhc2UgaW5jbHVkZSBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzJyk7XG4gICAgfVxuICAgIGlmICghb3B0aW9ucyB8fCAhb3B0aW9ucy51cmwpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhbiB1cmwgZm9yIHRoZSBjb21ldGQgc2VydmVyJyk7XG4gICAgfVxuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIENvbWV0ZCBlbmRwb2ludCBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1cmw6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbG9nIGxldmVsIGZvciB0aGUgY2hhbm5lbCAobG9ncyB0byBjb25zb2xlKS5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGxvZ0xldmVsOiAnaW5mbycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFdoZXRoZXIgd2Vic29ja2V0IHN1cHBvcnQgaXMgYWN0aXZlLiBEZWZhdWx0cyB0byBgZmFsc2VgOyBFcGljZW50ZXIgZG9lc24ndCBjdXJyZW50bHkgc3VwcG9ydCBjb21tdW5pY2F0aW9uIHRocm91Z2ggd2Vic29ja2V0cy5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICB3ZWJzb2NrZXRFbmFibGVkOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogSWYgZmFsc2UgZWFjaCBpbnN0YW5jZSBvZiBDaGFubmVsIHdpbGwgaGF2ZSBhIHNlcGFyYXRlIGNvbWV0ZCBjb25uZWN0aW9uIHRvIHNlcnZlciwgd2hpY2ggY291bGQgYmUgbm9pc3kuIFNldCB0byB0cnVlIHRvIHJlLXVzZSB0aGUgc2FtZSBjb25uZWN0aW9uIGFjcm9zcyBpbnN0YW5jZXMuXG4gICAgICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAgICAgKi9cbiAgICAgICAgc2hhcmVDb25uZWN0aW9uOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3RoZXIgZGVmYXVsdHMgdG8gcGFzcyBvbiB0byBpbnN0YW5jZXMgb2YgdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLyksIHdoaWNoIGFyZSBjcmVhdGVkIHRocm91Z2ggYGdldENoYW5uZWwoKWAuXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBjaGFubmVsOiB7XG5cbiAgICAgICAgfVxuICAgIH07XG4gICAgdmFyIGRlZmF1bHRDb21ldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMgPSBbXTtcbiAgICB0aGlzLm9wdGlvbnMgPSBkZWZhdWx0Q29tZXRPcHRpb25zO1xuXG4gICAgaWYgKGRlZmF1bHRDb21ldE9wdGlvbnMuc2hhcmVDb25uZWN0aW9uICYmIENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZS5fY29tZXRkKSB7XG4gICAgICAgIHRoaXMuY29tZXRkID0gQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQ7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbiAgICB2YXIgY29tZXRkID0gbmV3ICQuQ29tZXRkKCk7XG4gICAgQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQgPSBjb21ldGQ7XG5cbiAgICBjb21ldGQud2Vic29ja2V0RW5hYmxlZCA9IGRlZmF1bHRDb21ldE9wdGlvbnMud2Vic29ja2V0RW5hYmxlZDtcblxuICAgIHRoaXMuaXNDb25uZWN0ZWQgPSBmYWxzZTtcbiAgICB2YXIgY29ubmVjdGlvbkJyb2tlbiA9IGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQodGhpcykudHJpZ2dlcignZGlzY29ubmVjdCcsIG1lc3NhZ2UpO1xuICAgIH07XG4gICAgdmFyIGNvbm5lY3Rpb25TdWNjZWVkZWQgPSBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIoJ2Nvbm5lY3QnLCBtZXNzYWdlKTtcbiAgICB9O1xuICAgIHZhciBtZSA9IHRoaXM7XG5cbiAgICBjb21ldGQuY29uZmlndXJlKGRlZmF1bHRDb21ldE9wdGlvbnMpO1xuXG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9jb25uZWN0JywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgdmFyIHdhc0Nvbm5lY3RlZCA9IHRoaXMuaXNDb25uZWN0ZWQ7XG4gICAgICAgIHRoaXMuaXNDb25uZWN0ZWQgPSAobWVzc2FnZS5zdWNjZXNzZnVsID09PSB0cnVlKTtcbiAgICAgICAgaWYgKCF3YXNDb25uZWN0ZWQgJiYgdGhpcy5pc0Nvbm5lY3RlZCkgeyAvL0Nvbm5lY3RpbmcgZm9yIHRoZSBmaXJzdCB0aW1lXG4gICAgICAgICAgICBjb25uZWN0aW9uU3VjY2VlZGVkLmNhbGwodGhpcywgbWVzc2FnZSk7XG4gICAgICAgIH0gZWxzZSBpZiAod2FzQ29ubmVjdGVkICYmICF0aGlzLmlzQ29ubmVjdGVkKSB7IC8vT25seSB0aHJvdyBkaXNjb25uZWN0ZWQgbWVzc2FnZSBmcm8gdGhlIGZpcnN0IGRpc2Nvbm5lY3QsIG5vdCBvbmNlIHBlciB0cnlcbiAgICAgICAgICAgIGNvbm5lY3Rpb25Ccm9rZW4uY2FsbCh0aGlzLCBtZXNzYWdlKTtcbiAgICAgICAgfVxuICAgIH0uYmluZCh0aGlzKSk7XG5cbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL2Rpc2Nvbm5lY3QnLCBjb25uZWN0aW9uQnJva2VuKTtcblxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvaGFuZHNoYWtlJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgaWYgKG1lc3NhZ2Uuc3VjY2Vzc2Z1bCkge1xuICAgICAgICAgICAgLy9odHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0X3N1YnNjcmliZS5odG1sI2phdmFzY3JpcHRfc3Vic2NyaWJlX21ldGFfY2hhbm5lbHNcbiAgICAgICAgICAgIC8vIF4gXCJkeW5hbWljIHN1YnNjcmlwdGlvbnMgYXJlIGNsZWFyZWQgKGxpa2UgYW55IG90aGVyIHN1YnNjcmlwdGlvbikgYW5kIHRoZSBhcHBsaWNhdGlvbiBuZWVkcyB0byBmaWd1cmUgb3V0IHdoaWNoIGR5bmFtaWMgc3Vic2NyaXB0aW9uIG11c3QgYmUgcGVyZm9ybWVkIGFnYWluXCJcbiAgICAgICAgICAgIGNvbWV0ZC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgJChtZS5jdXJyZW50U3Vic2NyaXB0aW9ucykuZWFjaChmdW5jdGlvbiAoaW5kZXgsIHN1YnMpIHtcbiAgICAgICAgICAgICAgICAgICAgY29tZXRkLnJlc3Vic2NyaWJlKHN1YnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vT3RoZXIgaW50ZXJlc3RpbmcgZXZlbnRzIGZvciByZWZlcmVuY2VcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3N1YnNjcmliZScsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3N1YnNjcmliZScsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvdW5zdWJzY3JpYmUnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKG1lKS50cmlnZ2VyKCd1bnN1YnNjcmliZScsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvcHVibGlzaCcsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3B1Ymxpc2gnLCBtZXNzYWdlKTtcbiAgICB9KTtcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3Vuc3VjY2Vzc2Z1bCcsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ2Vycm9yJywgbWVzc2FnZSk7XG4gICAgfSk7XG5cbiAgICBjb21ldGQuaGFuZHNoYWtlKCk7XG5cbiAgICB0aGlzLmNvbWV0ZCA9IGNvbWV0ZDtcbn07XG5cblxuQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlID0gJC5leHRlbmQoQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLCB7XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgY2hhbm5lbCwgdGhhdCBpcywgYW4gaW5zdGFuY2Ugb2YgYSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgIHZhciBjaGFubmVsID0gY20uZ2V0Q2hhbm5lbCgpO1xuICAgICAqXG4gICAgICogICAgICBjaGFubmVsLnN1YnNjcmliZSgndG9waWMnLCBjYWxsYmFjayk7XG4gICAgICogICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBJZiBzdHJpbmcsIGFzc3VtZWQgdG8gYmUgdGhlIGJhc2UgY2hhbm5lbCB1cmwuIElmIG9iamVjdCwgYXNzdW1lZCB0byBiZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjb25zdHJ1Y3Rvci5cbiAgICAgKi9cbiAgICBnZXRDaGFubmVsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvL0lmIHlvdSBqdXN0IHdhbnQgdG8gcGFzcyBpbiBhIHN0cmluZ1xuICAgICAgICBpZiAob3B0aW9ucyAmJiAhJC5pc1BsYWluT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgICAgICAgICBvcHRpb25zID0ge1xuICAgICAgICAgICAgICAgIGJhc2U6IG9wdGlvbnNcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAgICAgdHJhbnNwb3J0OiB0aGlzLmNvbWV0ZFxuICAgICAgICB9O1xuICAgICAgICB2YXIgY2hhbm5lbCA9IG5ldyBDaGFubmVsKCQuZXh0ZW5kKHRydWUsIHt9LCB0aGlzLm9wdGlvbnMuY2hhbm5lbCwgZGVmYXVsdHMsIG9wdGlvbnMpKTtcblxuXG4gICAgICAgIC8vV3JhcCBzdWJzIGFuZCB1bnN1YnMgc28gd2UgY2FuIHVzZSBpdCB0byByZS1hdHRhY2ggaGFuZGxlcnMgYWZ0ZXIgYmVpbmcgZGlzY29ubmVjdGVkXG4gICAgICAgIHZhciBzdWJzID0gY2hhbm5lbC5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHN1YmlkID0gc3Vicy5hcHBseShjaGFubmVsLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucyAgPSB0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zLmNvbmNhdChzdWJpZCk7XG4gICAgICAgICAgICByZXR1cm4gc3ViaWQ7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuXG4gICAgICAgIHZhciB1bnN1YnMgPSBjaGFubmVsLnVuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnVuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJlbW92ZWQgPSB1bnN1YnMuYXBwbHkoY2hhbm5lbCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zW2ldLmlkID09PSByZW1vdmVkLmlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMuc3BsaWNlKGksIDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZW1vdmVkO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0YXJ0IGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqXG4gICAgICogU3VwcG9ydGVkIGV2ZW50cyBhcmU6IGBjb25uZWN0YCwgYGRpc2Nvbm5lY3RgLCBgc3Vic2NyaWJlYCwgYHVuc3Vic2NyaWJlYCwgYHB1Ymxpc2hgLCBgZXJyb3JgLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29uLy5cbiAgICAgKi9cbiAgICBvbjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub24uYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RvcCBsaXN0ZW5pbmcgZm9yIGV2ZW50cyBvbiB0aGlzIGluc3RhbmNlLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKi9cbiAgICBvZmY6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLm9mZi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUcmlnZ2VyIGV2ZW50cyBhbmQgZXhlY3V0ZSBoYW5kbGVycy4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKi9cbiAgICB0cmlnZ2VyOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuICogIyMgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlclxuICpcbiAqIFRoZSBFcGljZW50ZXIgcGxhdGZvcm0gcHJvdmlkZXMgYSBwdXNoIGNoYW5uZWwsIHdoaWNoIGFsbG93cyB5b3UgdG8gcHVibGlzaCBhbmQgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzIHdpdGhpbiBhIFtwcm9qZWN0XSguLi8uLi8uLi9nbG9zc2FyeS8jcHJvamVjdHMpLCBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvciBbbXVsdGlwbGF5ZXIgd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuIFRoZXJlIGFyZSB0d28gbWFpbiB1c2UgY2FzZXMgZm9yIHRoZSBjaGFubmVsOiBldmVudCBub3RpZmljYXRpb25zIGFuZCBjaGF0IG1lc3NhZ2VzLlxuICpcbiAqIFRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIGEgd3JhcHBlciBhcm91bmQgdGhlIChtb3JlIGdlbmVyaWMpIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pLCB0byBpbnN0YW50aWF0ZSBpdCB3aXRoIEVwaWNlbnRlci1zcGVjaWZpYyBkZWZhdWx0cy4gSWYgeW91IGFyZSBpbnRlcmVzdGVkIGluIGluY2x1ZGluZyBhIG5vdGlmaWNhdGlvbiBvciBjaGF0IGZlYXR1cmUgaW4geW91ciBwcm9qZWN0LCB1c2luZyBhbiBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIHByb2JhYmx5IHRoZSBlYXNpZXN0IHdheSB0byBnZXQgc3RhcnRlZC5cbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyLiBTZWUgW0luY2x1ZGluZyBFcGljZW50ZXIuanNdKC4uLy4uLyNpbmNsdWRlKS5cbiAqXG4gKiBUbyB1c2UgdGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXI6IGluc3RhbnRpYXRlIGl0LCBnZXQgdGhlIGNoYW5uZWwgb2YgdGhlIHNjb3BlIHlvdSB3YW50IChbdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgW3dvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLCBvciBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpKSwgdGhlbiB1c2UgdGhlIGNoYW5uZWwncyBgc3Vic2NyaWJlKClgIGFuZCBgcHVibGlzaCgpYCBtZXRob2RzIHRvIHN1YnNjcmliZSB0byB0b3BpY3Mgb3IgcHVibGlzaCBkYXRhIHRvIHRvcGljcy5cbiAqXG4gKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICogICAgIHZhciBnYyA9IGNtLmdldEdyb3VwQ2hhbm5lbCgpO1xuICogICAgIGdjLnN1YnNjcmliZSgnYnJvYWRjYXN0cycsIGNhbGxiYWNrKTtcbiAqXG4gKiBGb3IgYWRkaXRpb25hbCBiYWNrZ3JvdW5kIG9uIEVwaWNlbnRlcidzIHB1c2ggY2hhbm5lbCwgc2VlIHRoZSBpbnRyb2R1Y3Rvcnkgbm90ZXMgb24gdGhlIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIHBhZ2UuXG4gKlxuICogVGhlIHBhcmFtZXRlcnMgZm9yIGluc3RhbnRpYXRpbmcgYW4gRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYHNlcnZlcmAgT2JqZWN0IHdpdGggZGV0YWlscyBhYm91dCB0aGUgRXBpY2VudGVyIHByb2plY3QgZm9yIHRoaXMgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpbnN0YW5jZS5cbiAqICogYHNlcnZlci5hY2NvdW50YCBUaGUgRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICogKiBgc2VydmVyLnByb2plY3RgIEVwaWNlbnRlciBwcm9qZWN0IGlkLlxuICovXG5cbnZhciBDaGFubmVsTWFuYWdlciA9IHJlcXVpcmUoJy4vY2hhbm5lbC1tYW5hZ2VyJyk7XG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgdXJsU2VydmljZSA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlJyk7XG5cbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBzZXNzaW9uID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG52YXIgZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvciA9IGZ1bmN0aW9uICh2YWx1ZSwgc2Vzc2lvbktleU5hbWUsIHNldHRpbmdzKSB7XG4gICAgaWYgKCF2YWx1ZSkge1xuICAgICAgICB2YXIgdXNlckluZm8gPSBzZXNzaW9uLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgaWYgKHNldHRpbmdzICYmIHNldHRpbmdzW3Nlc3Npb25LZXlOYW1lXSkge1xuICAgICAgICAgICAgdmFsdWUgPSBzZXR0aW5nc1tzZXNzaW9uS2V5TmFtZV07XG4gICAgICAgIH0gZWxzZSBpZiAodXNlckluZm9bc2Vzc2lvbktleU5hbWVdKSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHVzZXJJbmZvW3Nlc3Npb25LZXlOYW1lXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihzZXNzaW9uS2V5TmFtZSArICcgbm90IGZvdW5kLiBQbGVhc2UgbG9nLWluIGFnYWluLCBvciBzcGVjaWZ5ICcgKyBzZXNzaW9uS2V5TmFtZSArICcgZXhwbGljaXRseScpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZTtcbn07XG52YXIgX19zdXBlciA9IENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZTtcbnZhciBFcGljZW50ZXJDaGFubmVsTWFuYWdlciA9IGNsYXNzRnJvbShDaGFubmVsTWFuYWdlciwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgdXNlckluZm8gPSBzZXNzaW9uLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcblxuICAgICAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgICAgICBhY2NvdW50OiB1c2VySW5mby5hY2NvdW50LFxuICAgICAgICAgICAgcHJvamVjdDogdXNlckluZm8ucHJvamVjdCxcbiAgICAgICAgfTtcbiAgICAgICAgdmFyIGRlZmF1bHRDb21ldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIHVzZXJJbmZvLCBvcHRpb25zKTtcblxuICAgICAgICB2YXIgdXJsT3B0cyA9IHVybFNlcnZpY2UoZGVmYXVsdENvbWV0T3B0aW9ucy5zZXJ2ZXIpO1xuICAgICAgICBpZiAoIWRlZmF1bHRDb21ldE9wdGlvbnMudXJsKSB7XG4gICAgICAgICAgICAvL0RlZmF1bHQgZXBpY2VudGVyIGNvbWV0ZCBlbmRwb2ludFxuICAgICAgICAgICAgZGVmYXVsdENvbWV0T3B0aW9ucy51cmwgPSB1cmxPcHRzLnByb3RvY29sICsgJzovLycgKyB1cmxPcHRzLmhvc3QgKyAnL2NoYW5uZWwvc3Vic2NyaWJlJztcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMub3B0aW9ucyA9IGRlZmF1bHRDb21ldE9wdGlvbnM7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgZGVmYXVsdENvbWV0T3B0aW9ucyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhbmQgcmV0dXJuIGEgcHVibGlzaC9zdWJzY3JpYmUgY2hhbm5lbCAoZnJvbSB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSkgZm9yIHRoZSBnaXZlbiBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLiBUaGUgZ3JvdXAgbXVzdCBleGlzdCBpbiB0aGUgYWNjb3VudCAodGVhbSkgYW5kIHByb2plY3QgcHJvdmlkZWQuXG4gICAgICpcbiAgICAgKiBUaGVyZSBhcmUgbm8gbm90aWZpY2F0aW9ucyBmcm9tIEVwaWNlbnRlciBvbiB0aGlzIGNoYW5uZWw7IGFsbCBtZXNzYWdlcyBhcmUgdXNlci1vcmlnaW5hdGVkLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciBnYyA9IGNtLmdldEdyb3VwQ2hhbm5lbCgpO1xuICAgICAqICAgICBnYy5zdWJzY3JpYmUoJ2Jyb2FkY2FzdHMnLCBjYWxsYmFjayk7XG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBHcm91cCB0byBicm9hZGNhc3QgdG8uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldEdyb3VwQ2hhbm5lbDogZnVuY3Rpb24gKGdyb3VwTmFtZSkge1xuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScpO1xuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2dyb3VwJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lXS5qb2luKCcvJyk7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIFt3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS5cbiAgICAgKlxuICAgICAqIFRoaXMgaXMgdHlwaWNhbGx5IHVzZWQgdG9nZXRoZXIgd2l0aCB0aGUgW1dvcmxkIE1hbmFnZXJdKC4uL3dvcmxkLW1hbmFnZXIpLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciB3b3JsZE1hbmFnZXIgPSBuZXcgRi5tYW5hZ2VyLldvcmxkTWFuYWdlcih7XG4gICAgICogICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICogICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAqICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gICAgICogICAgICAgICBydW46IHsgbW9kZWw6ICdtb2RlbC5lcW4nIH1cbiAgICAgKiAgICAgfSk7XG4gICAgICogICAgIHdvcmxkTWFuYWdlci5nZXRDdXJyZW50V29ybGQoKS50aGVuKGZ1bmN0aW9uICh3b3JsZE9iamVjdCwgd29ybGRBZGFwdGVyKSB7XG4gICAgICogICAgICAgICB2YXIgd29ybGRDaGFubmVsID0gY20uZ2V0V29ybGRDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHdvcmxkQ2hhbm5lbC5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICogICAgICAgICAgICAgY29uc29sZS5sb2coZGF0YSk7XG4gICAgICogICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSBgd29ybGRgIFRoZSB3b3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFdvcmxkQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCBncm91cE5hbWUpIHtcbiAgICAgICAgdmFyIHdvcmxkaWQgPSAoJC5pc1BsYWluT2JqZWN0KHdvcmxkKSAmJiB3b3JsZC5pZCkgPyB3b3JsZC5pZCA6IHdvcmxkO1xuICAgICAgICBpZiAoIXdvcmxkaWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHNwZWNpZnkgYSB3b3JsZCBpZCcpO1xuICAgICAgICB9XG4gICAgICAgIGdyb3VwTmFtZSA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJyk7XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvd29ybGQnLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWUsIHdvcmxkaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgY3VycmVudCBbZW5kIHVzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycykgaW4gdGhhdCB1c2VyJ3MgY3VycmVudCBbd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuXG4gICAgICpcbiAgICAgKiBUaGlzIGlzIHR5cGljYWxseSB1c2VkIHRvZ2V0aGVyIHdpdGggdGhlIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyKS4gTm90ZSB0aGF0IHRoaXMgY2hhbm5lbCBvbmx5IGdldHMgbm90aWZpY2F0aW9ucyBmb3Igd29ybGRzIGN1cnJlbnRseSBpbiBtZW1vcnkuIChTZWUgbW9yZSBiYWNrZ3JvdW5kIG9uIFtwZXJzaXN0ZW5jZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlKS4pXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIHdvcmxkTWFuYWdlciA9IG5ldyBGLm1hbmFnZXIuV29ybGRNYW5hZ2VyKHtcbiAgICAgKiAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgKiAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICogICAgICAgICBncm91cDogJ3RlYW0xJyxcbiAgICAgKiAgICAgICAgIHJ1bjogeyBtb2RlbDogJ21vZGVsLmVxbicgfVxuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgKiAgICAgICAgIHZhciB1c2VyQ2hhbm5lbCA9IGNtLmdldFVzZXJDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHVzZXJDaGFubmVsLnN1YnNjcmliZSgnJywgZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgKiAgICAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKiAgICAgICAgIH0pO1xuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHdvcmxkYCBXb3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHVzZXJgIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFVzZXJDaGFubmVsOiBmdW5jdGlvbiAod29ybGQsIHVzZXIsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVzZXJpZCA9ICgkLmlzUGxhaW5PYmplY3QodXNlcikgJiYgdXNlci5pZCkgPyB1c2VyLmlkIDogdXNlcjtcbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnKTtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcihncm91cE5hbWUsICdncm91cE5hbWUnKTtcblxuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3VzZXJzJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkLCB1c2VyaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIHRoYXQgYXV0b21hdGljYWxseSB0cmFja3MgdGhlIHByZXNlbmNlIG9mIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgdGhhdCBpcywgd2hldGhlciB0aGUgZW5kIHVzZXIgaXMgY3VycmVudGx5IG9ubGluZSBpbiB0aGlzIGdyb3VwIGFuZCB3b3JsZC4gTm90aWZpY2F0aW9ucyBhcmUgYXV0b21hdGljYWxseSBzZW50IHdoZW4gdGhlIGVuZCB1c2VyIGNvbWVzIG9ubGluZSwgYW5kIHdoZW4gdGhlIGVuZCB1c2VyIGdvZXMgb2ZmbGluZSAobm90IHByZXNlbnQgZm9yIG1vcmUgdGhhbiAyIG1pbnV0ZXMpLiBVc2VmdWwgaW4gbXVsdGlwbGF5ZXIgZ2FtZXMgZm9yIGxldHRpbmcgZWFjaCBlbmQgdXNlciBrbm93IHdoZXRoZXIgb3RoZXIgdXNlcnMgaW4gdGhlaXIgc2hhcmVkIHdvcmxkIGFyZSBhbHNvIG9ubGluZS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgd29ybGRNYW5hZ2VyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuICAgICAqICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAqICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgKiAgICAgICAgIG1vZGVsOiAnbW9kZWwuZXFuJ1xuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZFNlcnZpY2UpIHtcbiAgICAgKiAgICAgICAgIHZhciBwcmVzZW5jZUNoYW5uZWwgPSBjbS5nZXRQcmVzZW5jZUNoYW5uZWwod29ybGRPYmplY3QpO1xuICAgICAqICAgICAgICAgcHJlc2VuY2VDaGFubmVsLm9uKCdwcmVzZW5jZScsIGZ1bmN0aW9uIChldnQsIG5vdGlmaWNhdGlvbikge1xuICAgICAqICAgICAgICAgICAgICBjb25zb2xlLmxvZyhub3RpZmljYXRpb24ub25saW5lLCBub3RpZmljYXRpb24udXNlcklkKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB3b3JsZGAgV29ybGQgb2JqZWN0IG9yIGlkLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB1c2VyaWRgIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFByZXNlbmNlQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCB1c2VyaWQsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnKTtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcihncm91cE5hbWUsICdncm91cE5hbWUnKTtcblxuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3VzZXJzJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG5cbiAgICAgICAgdmFyIGxhc3RQaW5nVGltZSA9IHsgfTtcblxuICAgICAgICB2YXIgUElOR19JTlRFUlZBTCA9IDYwMDA7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCdpbnRlcm5hbC1waW5nLWNoYW5uZWwnLCBmdW5jdGlvbiAobm90aWZpY2F0aW9uKSB7XG4gICAgICAgICAgICB2YXIgaW5jb21pbmdVc2VySWQgPSBub3RpZmljYXRpb24uZGF0YS51c2VyO1xuICAgICAgICAgICAgaWYgKCFsYXN0UGluZ1RpbWVbaW5jb21pbmdVc2VySWRdICYmIGluY29taW5nVXNlcklkICE9PSB1c2VyaWQpIHtcbiAgICAgICAgICAgICAgICBjaGFubmVsLnRyaWdnZXIuY2FsbChjaGFubmVsLCAncHJlc2VuY2UnLCB7IHVzZXJJZDogaW5jb21pbmdVc2VySWQsIG9ubGluZTogdHJ1ZSB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxhc3RQaW5nVGltZVtpbmNvbWluZ1VzZXJJZF0gPSAobmV3IERhdGUoKSkudmFsdWVPZigpO1xuICAgICAgICB9KTtcblxuICAgICAgICBzZXRJbnRlcnZhbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBjaGFubmVsLnB1Ymxpc2goJ2ludGVybmFsLXBpbmctY2hhbm5lbCcsIHsgdXNlcjogdXNlcmlkIH0pO1xuXG4gICAgICAgICAgICAkLmVhY2gobGFzdFBpbmdUaW1lLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHZhciBub3cgPSAobmV3IERhdGUoKSkudmFsdWVPZigpO1xuICAgICAgICAgICAgICAgIGlmICh2YWx1ZSAmJiB2YWx1ZSArIChQSU5HX0lOVEVSVkFMICogMikgPCBub3cpIHtcbiAgICAgICAgICAgICAgICAgICAgbGFzdFBpbmdUaW1lW2tleV0gPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICBjaGFubmVsLnRyaWdnZXIuY2FsbChjaGFubmVsLCAncHJlc2VuY2UnLCB7IHVzZXJJZDoga2V5LCBvbmxpbmU6IGZhbHNlIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LCBQSU5HX0lOVEVSVkFMKTtcblxuICAgICAgICByZXR1cm4gY2hhbm5lbDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIGNvbGxlY3Rpb24uIChUaGUgY29sbGVjdGlvbiBuYW1lIGlzIHNwZWNpZmllZCBpbiB0aGUgYHJvb3RgIGFyZ3VtZW50IHdoZW4gdGhlIFtEYXRhIFNlcnZpY2VdKC4uL2RhdGEtYXBpLXNlcnZpY2UvKSBpcyBpbnN0YW50aWF0ZWQuKSBNdXN0IGJlIG9uZSBvZiB0aGUgY29sbGVjdGlvbnMgaW4gdGhpcyBhY2NvdW50ICh0ZWFtKSBhbmQgcHJvamVjdC5cbiAgICAgKlxuICAgICAqIFRoZXJlIGFyZSBhdXRvbWF0aWMgbm90aWZpY2F0aW9ucyBmcm9tIEVwaWNlbnRlciBvbiB0aGlzIGNoYW5uZWwgd2hlbiBkYXRhIGlzIGNyZWF0ZWQsIHVwZGF0ZWQsIG9yIGRlbGV0ZWQgaW4gdGhpcyBjb2xsZWN0aW9uLiBTZWUgbW9yZSBvbiBbYXV0b21hdGljIG1lc3NhZ2VzIHRvIHRoZSBkYXRhIGNoYW5uZWxdKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLyNkYXRhLW1lc3NhZ2VzKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgZ2MgPSBjbS5nZXREYXRhQ2hhbm5lbCgnc3VydmV5LXJlc3BvbnNlcycpO1xuICAgICAqICAgICBnYy5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uKGRhdGEsIG1ldGEpIHtcbiAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKlxuICAgICAqICAgICAgICAgIC8vIG1ldGEuZGF0ZSBpcyB0aW1lIG9mIGNoYW5nZSxcbiAgICAgKiAgICAgICAgICAvLyBtZXRhLnN1YlR5cGUgaXMgdGhlIGtpbmQgb2YgY2hhbmdlOiBuZXcsIHVwZGF0ZSwgb3IgZGVsZXRlXG4gICAgICogICAgICAgICAgLy8gbWV0YS5wYXRoIGlzIHRoZSBmdWxsIHBhdGggdG8gdGhlIGNoYW5nZWQgZGF0YVxuICAgICAqICAgICAgICAgIGNvbnNvbGUubG9nKG1ldGEpO1xuICAgICAqICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgY29sbGVjdGlvbmAgTmFtZSBvZiBjb2xsZWN0aW9uIHdob3NlIGF1dG9tYXRpYyBub3RpZmljYXRpb25zIHlvdSB3YW50IHRvIHJlY2VpdmUuXG4gICAgICovXG4gICAgZ2V0RGF0YUNoYW5uZWw6IGZ1bmN0aW9uIChjb2xsZWN0aW9uKSB7XG4gICAgICAgIGlmICghY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIGNvbGxlY3Rpb24gdG8gbGlzdGVuIG9uLicpO1xuICAgICAgICB9XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2RhdGEnLCBhY2NvdW50LCBwcm9qZWN0LCBjb2xsZWN0aW9uXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG5cbiAgICAgICAgLy9UT0RPOiBGaXggYWZ0ZXIgRXBpY2VudGVyIGJ1ZyBpcyByZXNvbHZlZFxuICAgICAgICB2YXIgb2xkc3VicyA9IGNoYW5uZWwuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnN1YnNjcmliZSA9IGZ1bmN0aW9uICh0b3BpYywgY2FsbGJhY2ssIGNvbnRleHQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBjYWxsYmFja1dpdGhDbGVhbkRhdGEgPSBmdW5jdGlvbiAocGF5bG9hZCkge1xuICAgICAgICAgICAgICAgIHZhciBtZXRhID0ge1xuICAgICAgICAgICAgICAgICAgICBwYXRoOiBwYXlsb2FkLmNoYW5uZWwsXG4gICAgICAgICAgICAgICAgICAgIHN1YlR5cGU6IHBheWxvYWQuZGF0YS5zdWJUeXBlLFxuICAgICAgICAgICAgICAgICAgICBkYXRlOiBwYXlsb2FkLmRhdGEuZGF0ZVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdmFyIGFjdHVhbERhdGEgPSBwYXlsb2FkLmRhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICBpZiAoYWN0dWFsRGF0YS5kYXRhKSB7IC8vRGVsZXRlIG5vdGlmaWNhdGlvbnMgYXJlIG9uZSBkYXRhLWxldmVsIGJlaGluZCBvZiBjb3Vyc2VcbiAgICAgICAgICAgICAgICAgICAgYWN0dWFsRGF0YSA9IGFjdHVhbERhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBjYWxsYmFjay5jYWxsKGNvbnRleHQsIGFjdHVhbERhdGEsIG1ldGEpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiBvbGRzdWJzLmNhbGwoY2hhbm5lbCwgdG9waWMsIGNhbGxiYWNrV2l0aENsZWFuRGF0YSwgY29udGV4dCwgb3B0aW9ucyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gRXBpY2VudGVyQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIEVQSV9DT09LSUVfS0VZOiAnZXBpY2VudGVyLnByb2plY3QudG9rZW4nLFxuICAgIEVQSV9TRVNTSU9OX0tFWTogJ2VwaWNlbnRlci51c2VyLnNlc3Npb24nLFxuICAgIFNUUkFURUdZX1NFU1NJT05fS0VZOiAnZXBpY2VudGVyLXNjZW5hcmlvJ1xufTsiLCIvKipcbiogIyMgUnVuIE1hbmFnZXJcbipcbiogVGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBhY2Nlc3MgdG8gcnVucyBmb3IgeW91ciBwcm9qZWN0LiBUaGlzIGFsbG93cyB5b3UgdG8gcmVhZCBhbmQgdXBkYXRlIHZhcmlhYmxlcywgY2FsbCBvcGVyYXRpb25zLCBldGMuIEFkZGl0aW9uYWxseSwgdGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBjb250cm9sIG92ZXIgcnVuIGNyZWF0aW9uIGRlcGVuZGluZyBvbiBydW4gc3RhdGVzLiBTcGVjaWZpY2FsbHksIHlvdSBjYW4gc2VsZWN0IFtydW4gY3JlYXRpb24gc3RyYXRlZ2llcyAocnVsZXMpXSguLi8uLi9zdHJhdGVneS8pIGZvciB3aGljaCBydW5zIGVuZCB1c2VycyBvZiB5b3VyIHByb2plY3Qgd29yayB3aXRoIHdoZW4gdGhleSBsb2cgaW4gdG8geW91ciBwcm9qZWN0LlxuKlxuKiBUaGVyZSBhcmUgbWFueSB3YXlzIHRvIGNyZWF0ZSBuZXcgcnVucywgaW5jbHVkaW5nIHRoZSBFcGljZW50ZXIuanMgW1J1biBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSwgdGhlIFJFU0ZUZnVsIFtSdW4gQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkpIGFuZCB0aGUgW01vZGVsIFJ1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9vdGhlcl9hcGlzL21vZGVsX2FwaXMvcnVuLykuIEhvd2V2ZXIsIGZvciBzb21lIHByb2plY3RzIGl0IG1ha2VzIG1vcmUgc2Vuc2UgdG8gcGljayB1cCB3aGVyZSB0aGUgdXNlciBsZWZ0IG9mZiwgdXNpbmcgYW4gZXhpc3RpbmcgcnVuLiBBbmQgaW4gc29tZSBwcm9qZWN0cywgd2hldGhlciB0byBjcmVhdGUgYSBuZXcgcnVuIG9yIHVzZSBhbiBleGlzdGluZyBvbmUgaXMgY29uZGl0aW9uYWwsIGZvciBleGFtcGxlIGJhc2VkIG9uIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgZXhpc3RpbmcgcnVuIG9yIHlvdXIgb3duIGtub3dsZWRnZSBhYm91dCB0aGUgbW9kZWwuIFRoZSBSdW4gTWFuYWdlciBwcm92aWRlcyB0aGlzIGxldmVsIG9mIGNvbnRyb2w6IHlvdXIgY2FsbCB0byBgZ2V0UnVuKClgLCByYXRoZXIgdGhhbiBhbHdheXMgcmV0dXJuaW5nIGEgbmV3IHJ1biwgcmV0dXJucyBhIHJ1biBiYXNlZCBvbiB0aGUgc3RyYXRlZ3kgeW91J3ZlIHNwZWNpZmllZC4gKE5vdGUgdGhhdCBtYW55IG9mIHRoZSBFcGljZW50ZXIgc2FtcGxlIHByb2plY3RzIHVzZSBhIFJ1biBTZXJ2aWNlIGRpcmVjdGx5LCBiZWNhdXNlIGdlbmVyYWxseSB0aGUgc2FtcGxlIHByb2plY3RzIGFyZSBwbGF5ZWQgaW4gb25lIGVuZCB1c2VyIHNlc3Npb24gYW5kIGRvbid0IGNhcmUgYWJvdXQgcnVuIHN0YXRlcyBvciBydW4gc3RyYXRlZ2llcy4pXG4qXG4qXG4qICMjIyBVc2luZyB0aGUgUnVuIE1hbmFnZXIgdG8gY3JlYXRlIGFuZCBhY2Nlc3MgcnVuc1xuKlxuKiBUbyB1c2UgdGhlIFJ1biBNYW5hZ2VyLCBpbnN0YW50aWF0ZSBpdCBieSBwYXNzaW5nIGluOlxuKlxuKiAgICogYHJ1bmA6IChyZXF1aXJlZCkgUnVuIG9iamVjdC4gTXVzdCBjb250YWluOlxuKiAgICAgICAqIGBhY2NvdW50YDogRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuKiAgICAgICAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4qICAgICAgICogYG1vZGVsYDogVGhlIG5hbWUgb2YgeW91ciBwcmltYXJ5IG1vZGVsIGZpbGUuIChTZWUgbW9yZSBvbiBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4pXG4qICAgICAgICogYHNjb3BlYDogKG9wdGlvbmFsKSBTY29wZSBvYmplY3QgZm9yIHRoZSBydW4sIGZvciBleGFtcGxlIGBzY29wZS5ncm91cGAgd2l0aCB2YWx1ZSBvZiB0aGUgbmFtZSBvZiB0aGUgZ3JvdXAuXG4qICAgICAgICogYHNlcnZlcmA6IChvcHRpb25hbCkgQW4gb2JqZWN0IHdpdGggb25lIGZpZWxkLCBgaG9zdGAuIFRoZSB2YWx1ZSBvZiBgaG9zdGAgaXMgdGhlIHN0cmluZyBgYXBpLmZvcmlvLmNvbWAsIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4qICAgICAgICogYGZpbGVzYDogKG9wdGlvbmFsKSBJZiBhbmQgb25seSBpZiB5b3UgYXJlIHVzaW5nIGEgVmVuc2ltIG1vZGVsIGFuZCB5b3UgaGF2ZSBhZGRpdGlvbmFsIGRhdGEgdG8gcGFzcyBpbiB0byB5b3VyIG1vZGVsLCB5b3UgY2FuIHBhc3MgYSBgZmlsZXNgIG9iamVjdCB3aXRoIHRoZSBuYW1lcyBvZiB0aGUgZmlsZXMsIGZvciBleGFtcGxlOiBgXCJmaWxlc1wiOiB7XCJkYXRhXCI6IFwibXlFeHRyYURhdGEueGxzXCJ9YC4gKE5vdGUgdGhhdCB5b3UnbGwgYWxzbyBuZWVkIHRvIGFkZCB0aGlzIHNhbWUgZmlsZXMgb2JqZWN0IHRvIHlvdXIgVmVuc2ltIFtjb25maWd1cmF0aW9uIGZpbGVdKC4uLy4uLy4uL21vZGVsX2NvZGUvdmVuc2ltLykuKSBTZWUgdGhlIFt1bmRlcmx5aW5nIE1vZGVsIFJ1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9vdGhlcl9hcGlzL21vZGVsX2FwaXMvcnVuLyNwb3N0LWNyZWF0aW5nLWEtbmV3LXJ1bi1mb3ItdGhpcy1wcm9qZWN0KSBmb3IgYWRkaXRpb25hbCBpbmZvcm1hdGlvbi5cbipcbiogICAqIGBzdHJhdGVneWA6IChvcHRpb25hbCkgUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgZGV0YWlscy4gRGVmYXVsdHMgdG8gYG5ldy1pZi1pbml0aWFsaXplZGAuXG4qXG4qICAgKiBgc2Vzc2lvbktleWA6IChvcHRpb25hbCkgTmFtZSBvZiBicm93c2VyIGNvb2tpZSBpbiB3aGljaCB0byBzdG9yZSBydW4gaW5mb3JtYXRpb24sIGluY2x1ZGluZyBydW4gaWQuIE1hbnkgY29uZGl0aW9uYWwgc3RyYXRlZ2llcywgaW5jbHVkaW5nIHRoZSBwcm92aWRlZCBzdHJhdGVnaWVzLCByZWx5IG9uIHRoaXMgYnJvd3NlciBjb29raWUgdG8gc3RvcmUgdGhlIHJ1biBpZCBhbmQgaGVscCBtYWtlIHRoZSBkZWNpc2lvbiBvZiB3aGV0aGVyIHRvIGNyZWF0ZSBhIG5ldyBydW4gb3IgdXNlIGFuIGV4aXN0aW5nIG9uZS4gVGhlIG5hbWUgb2YgdGhpcyBjb29raWUgZGVmYXVsdHMgdG8gYGVwaWNlbnRlci1zY2VuYXJpb2AgYW5kIGNhbiBiZSBzZXQgd2l0aCB0aGUgYHNlc3Npb25LZXlgIHBhcmFtZXRlci5cbipcbipcbiogQWZ0ZXIgaW5zdGFudGlhdGluZyBhIFJ1biBNYW5hZ2VyLCBtYWtlIGEgY2FsbCB0byBgZ2V0UnVuKClgIHdoZW5ldmVyIHlvdSBuZWVkIHRvIGFjY2VzcyBhIHJ1biBmb3IgdGhpcyBlbmQgdXNlci4gVGhlIGBSdW5NYW5hZ2VyLnJ1bmAgY29udGFpbnMgdGhlIGluc3RhbnRpYXRlZCBbUnVuIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLiBUaGUgUnVuIFNlcnZpY2UgYWxsb3dzIHlvdSB0byBhY2Nlc3MgdmFyaWFibGVzLCBjYWxsIG9wZXJhdGlvbnMsIGV0Yy5cbipcbiogKipFeGFtcGxlKipcbipcbiogICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiogICAgICAgICAgIHJ1bjoge1xuKiAgICAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5LWNoYWluLW1vZGVsLmpsJyxcbiogICAgICAgICAgICAgICBzZXJ2ZXI6IHsgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH1cbiogICAgICAgICAgIH0sXG4qICAgICAgICAgICBzdHJhdGVneTogJ2Fsd2F5cy1uZXcnLFxuKiAgICAgICAgICAgc2Vzc2lvbktleTogJ2VwaWNlbnRlci1zZXNzaW9uJ1xuKiAgICAgICB9KTtcbiogICAgICAgcm0uZ2V0UnVuKClcbiogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1bikge1xuKiAgICAgICAgICAgICAgIC8vIHRoZSByZXR1cm4gdmFsdWUgb2YgZ2V0UnVuKCkgaXMgYSBydW4gb2JqZWN0XG4qICAgICAgICAgICAgICAgdmFyIHRoaXNSdW5JZCA9IHJ1bi5pZDtcbiogICAgICAgICAgICAgICAvLyB0aGUgUnVuTWFuYWdlci5ydW4gYWxzbyBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFJ1biBTZXJ2aWNlLFxuKiAgICAgICAgICAgICAgIC8vIHNvIGFueSBSdW4gU2VydmljZSBtZXRob2QgaXMgdmFsaWQgaGVyZVxuKiAgICAgICAgICAgICAgIHJtLnJ1bi5kbygncnVuTW9kZWwnKTtcbiogICAgICAgfSlcbipcbiovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBzdHJhdGVnaWVzTWFwID0gcmVxdWlyZSgnLi9ydW4tc3RyYXRlZ2llcy9zdHJhdGVnaWVzLW1hcCcpO1xudmFyIHNwZWNpYWxPcGVyYXRpb25zID0gcmVxdWlyZSgnLi9zcGVjaWFsLW9wZXJhdGlvbnMnKTtcbnZhciBSdW5TZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9ydW4tYXBpLXNlcnZpY2UnKTtcblxuXG5mdW5jdGlvbiBwYXRjaFJ1blNlcnZpY2Uoc2VydmljZSwgbWFuYWdlcikge1xuICAgIGlmIChzZXJ2aWNlLnBhdGNoZWQpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2U7XG4gICAgfVxuXG4gICAgdmFyIG9yaWcgPSBzZXJ2aWNlLmRvO1xuICAgIHNlcnZpY2UuZG8gPSBmdW5jdGlvbiAob3BlcmF0aW9uLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHJlc2VydmVkT3BzID0gT2JqZWN0LmtleXMoc3BlY2lhbE9wZXJhdGlvbnMpO1xuICAgICAgICBpZiAocmVzZXJ2ZWRPcHMuaW5kZXhPZihvcGVyYXRpb24pID09PSAtMSkge1xuICAgICAgICAgICAgcmV0dXJuIG9yaWcuYXBwbHkoc2VydmljZSwgYXJndW1lbnRzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBzcGVjaWFsT3BlcmF0aW9uc1tvcGVyYXRpb25dLmNhbGwoc2VydmljZSwgcGFyYW1zLCBvcHRpb25zLCBtYW5hZ2VyKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBzZXJ2aWNlLnBhdGNoZWQgPSB0cnVlO1xuXG4gICAgcmV0dXJuIHNlcnZpY2U7XG59XG5cblxuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgLyoqXG4gICAgICogUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgZGV0YWlscy4gRGVmYXVsdHMgdG8gYG5ldy1pZi1pbml0aWFsaXplZGAuXG4gICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgKi9cblxuICAgIHN0cmF0ZWd5OiAnbmV3LWlmLWluaXRpYWxpemVkJ1xufTtcblxuZnVuY3Rpb24gUnVuTWFuYWdlcihvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcblxuICAgIGlmICh0aGlzLm9wdGlvbnMucnVuIGluc3RhbmNlb2YgUnVuU2VydmljZSkge1xuICAgICAgICB0aGlzLnJ1biA9IHRoaXMub3B0aW9ucy5ydW47XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5ydW4gPSBuZXcgUnVuU2VydmljZSh0aGlzLm9wdGlvbnMucnVuKTtcbiAgICB9XG5cbiAgICBwYXRjaFJ1blNlcnZpY2UodGhpcy5ydW4sIHRoaXMpO1xuXG4gICAgdmFyIFN0cmF0ZWd5Q3RvciA9IHR5cGVvZiB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kgPT09ICdmdW5jdGlvbicgPyB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kgOiBzdHJhdGVnaWVzTWFwW3RoaXMub3B0aW9ucy5zdHJhdGVneV07XG5cbiAgICBpZiAoIVN0cmF0ZWd5Q3Rvcikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NwZWNpZmllZCBydW4gY3JlYXRpb24gc3RyYXRlZ3kgd2FzIGludmFsaWQ6JywgdGhpcy5vcHRpb25zLnN0cmF0ZWd5KTtcbiAgICB9XG5cbiAgICB0aGlzLnN0cmF0ZWd5ID0gbmV3IFN0cmF0ZWd5Q3Rvcih0aGlzLnJ1biwgdGhpcy5vcHRpb25zKTtcbn1cblxuUnVuTWFuYWdlci5wcm90b3R5cGUgPSB7XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSAnZ29vZCcgcnVuLlxuICAgICAqXG4gICAgICogQSBnb29kIHJ1biBpcyBkZWZpbmVkIGJ5IHRoZSBzdHJhdGVneS4gRm9yIGV4YW1wbGUsIGlmIHRoZSBzdHJhdGVneSBpcyBgYWx3YXlzLW5ld2AsIHRoZSBjYWxsXG4gICAgICogdG8gYGdldFJ1bigpYCBhbHdheXMgcmV0dXJucyBhIG5ld2x5IGNyZWF0ZWQgcnVuOyBpZiB0aGUgc3RyYXRlZ3kgaXMgYG5ldy1pZi1wZXJzaXN0ZWRgLFxuICAgICAqIGBnZXRSdW4oKWAgY3JlYXRlcyBhIG5ldyBydW4gaWYgdGhlIHByZXZpb3VzIHJ1biBpcyBpbiBhIHBlcnNpc3RlZCBzdGF0ZSwgb3RoZXJ3aXNlXG4gICAgICogaXQgcmV0dXJucyB0aGUgcHJldmlvdXMgcnVuLiBTZWUgW1J1biBNYW5hZ2VyIFN0cmF0ZWdpZXNdKC4uLy4uL3N0cmF0ZWd5LykgZm9yIG1vcmUgb24gc3RyYXRlZ2llcy5cbiAgICAgKlxuICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBybS5nZXRSdW4oKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqIEByZXR1cm4geyRwcm9taXNlfSBQcm9taXNlIHRvIGNvbXBsZXRlIHRoZSBjYWxsLlxuICAgICAqL1xuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zdHJhdGVneVxuICAgICAgICAgICAgICAgIC5nZXRSdW4oKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSBuZXcgcnVuLCByZWdhcmRsZXNzIG9mIHN0cmF0ZWd5OiBmb3JjZSBjcmVhdGlvbiBvZiBhIG5ldyBydW4uXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgcm0ucmVzZXQoKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIChuZXcpIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBydW5TZXJ2aWNlT3B0aW9uc2AgVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGUgUnVuIFNlcnZpY2UuIFNlZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSBmb3IgbW9yZS5cbiAgICAgKi9cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0cmF0ZWd5LnJlc2V0KHJ1blNlcnZpY2VPcHRpb25zKTtcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJ1bk1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIC8vIGFsd2F5cyBjcmVhdGUgYSBuZXcgcnVuIVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIG1ha2VTZXEgPSByZXF1aXJlKCcuLi8uLi91dGlsL21ha2Utc2VxdWVuY2UnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFNlc3Npb25TdG9yZSA9IHJlcXVpcmUoJy4uLy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBVcmxTZXJ2aWNlID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4uL2F1dGgtbWFuYWdlcicpO1xuXG52YXIgc2Vzc2lvblN0b3JlID0gbmV3IFNlc3Npb25TdG9yZSh7fSk7XG52YXIgdXJsU2VydmljZSA9IG5ldyBVcmxTZXJ2aWNlKCk7XG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuLi9rZXktbmFtZXMnKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHNlc3Npb25LZXk6IGtleU5hbWVzLlNUUkFURUdZX1NFU1NJT05fS0VZLFxuICAgIHBhdGg6ICcnXG59O1xuXG5mdW5jdGlvbiBzZXRSdW5JblNlc3Npb24oc2Vzc2lvbktleSwgcnVuLCBwYXRoKSB7XG4gICAgaWYgKCFwYXRoKSB7XG4gICAgICAgIGlmICghdXJsU2VydmljZS5pc0xvY2FsaG9zdCgpKSB7XG4gICAgICAgICAgICBwYXRoID0gJy8nICsgW3VybFNlcnZpY2UuYXBwUGF0aCwgdXJsU2VydmljZS5hY2NvdW50UGF0aCwgdXJsU2VydmljZS5wcm9qZWN0UGF0aF0uam9pbignLycpO1xuICAgICAgICAgICAgLy8gbWFrZSBzdXJlIHdlIGRvbid0IGdldCBjb25zZWN1dGVpdmUgJy8nIHNvIHdlIGhhdmUgYSB2YWxpZCBwYXRoIGZvciB0aGUgc2Vzc2lvblxuICAgICAgICAgICAgcGF0aCA9IHBhdGgucmVwbGFjZSgvXFwvezIsfS9nLCcvJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwYXRoID0gJyc7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gc2V0IHRoZSBzZWVzaW9uS2V5IGZvciB0aGUgcnVuXG4gICAgc2Vzc2lvblN0b3JlLnNldChzZXNzaW9uS2V5LCBKU09OLnN0cmluZ2lmeSh7IHJ1bklkOiBydW4uaWQgfSksIHsgcm9vdDogcGF0aCB9KTtcbn1cblxuLyoqXG4qIENvbmRpdGlvbmFsIENyZWF0aW9uIFN0cmF0ZWd5XG4qIFRoaXMgc3RyYXRlZ3kgd2lsbCB0cnkgdG8gZ2V0IHRoZSBydW4gc3RvcmVkIGluIHRoZSBjb29raWUgYW5kXG4qIGV2YWx1YXRlIGlmIG5lZWRzIHRvIGNyZWF0ZSBhIG5ldyBydW4gYnkgY2FsbGluZyB0aGUgJ2NvbmRpdGlvbicgZnVuY3Rpb25cbiovXG5cbi8qIGpzaGludCBlcW51bGw6IHRydWUgKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIFN0cmF0ZWd5KHJ1blNlcnZpY2UsIGNvbmRpdGlvbiwgb3B0aW9ucykge1xuXG4gICAgICAgIGlmIChjb25kaXRpb24gPT0gbnVsbCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb25kaXRpb25hbCBzdHJhdGVneSBuZWVkcyBhIGNvbmRpdGlvbiB0byBjcmVhdGV0ZSBhIHJ1bicpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fYXV0aCA9IG5ldyBBdXRoTWFuYWdlcigpO1xuICAgICAgICB0aGlzLnJ1biA9IG1ha2VTZXEocnVuU2VydmljZSk7XG4gICAgICAgIHRoaXMuY29uZGl0aW9uID0gdHlwZW9mIGNvbmRpdGlvbiAhPT0gJ2Z1bmN0aW9uJyA/IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGNvbmRpdGlvbjsgfSA6IGNvbmRpdGlvbjtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICB9LFxuXG4gICAgcnVuT3B0aW9uc1dpdGhTY29wZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgdXNlclNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiB1c2VyU2Vzc2lvbi5ncm91cE5hbWUgfVxuICAgICAgICB9LCB0aGlzLnJ1bk9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBvcHQgPSB0aGlzLnJ1bk9wdGlvbnNXaXRoU2NvcGUoKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5ydW5cbiAgICAgICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgc2V0UnVuSW5TZXNzaW9uKF90aGlzLm9wdGlvbnMuc2Vzc2lvbktleSwgcnVuLCBfdGhpcy5vcHRpb25zLnBhdGgpO1xuICAgICAgICAgICAgICAgIHJ1bi5mcmVzaGx5Q3JlYXRlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuc3RhcnQoKTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBydW5TZXNzaW9uID0gSlNPTi5wYXJzZShzZXNzaW9uU3RvcmUuZ2V0KHRoaXMub3B0aW9ucy5zZXNzaW9uS2V5KSk7XG5cbiAgICAgICAgaWYgKHJ1blNlc3Npb24gJiYgcnVuU2Vzc2lvbi5ydW5JZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2xvYWRBbmRDaGVjayhydW5TZXNzaW9uKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJlc2V0KCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgX2xvYWRBbmRDaGVjazogZnVuY3Rpb24gKHJ1blNlc3Npb24pIHtcbiAgICAgICAgdmFyIHNob3VsZENyZWF0ZSA9IGZhbHNlO1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1blxuICAgICAgICAgICAgLmxvYWQocnVuU2Vzc2lvbi5ydW5JZCwgbnVsbCwge1xuICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZ1bmN0aW9uIChydW4sIG1zZywgaGVhZGVycykge1xuICAgICAgICAgICAgICAgICAgICBzaG91bGRDcmVhdGUgPSBfdGhpcy5jb25kaXRpb24uY2FsbChfdGhpcywgcnVuLCBoZWFkZXJzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIGlmIChzaG91bGRDcmVhdGUpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9wdCA9IF90aGlzLnJ1bk9wdGlvbnNXaXRoU2NvcGUoKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gd2UgbmVlZCB0byBkbyB0aGlzLCBvbiB0aGUgb3JpZ2luYWwgcnVuU2VydmljZSAoaWUgbm90IHNlcXVlbmNpYWxpemVkKVxuICAgICAgICAgICAgICAgICAgICAvLyBzbyB3ZSBkb24ndCBnZXQgaW4gdGhlIG1pZGRsZSBvZiB0aGUgcXVldWVcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1bi5vcmlnaW5hbC5jcmVhdGUob3B0KVxuICAgICAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRSdW5JblNlc3Npb24oX3RoaXMub3B0aW9ucy5zZXNzaW9uS2V5LCBydW4pO1xuICAgICAgICAgICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnN0YXJ0KCk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0ge307XG5cbi8vIEludGVyZmFjZSB0aGF0IGFsbCBzdHJhdGVnaWVzIG5lZWQgdG8gaW1wbGVtZW50XG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuU2VydmljZSAgPSBydW5TZXJ2aWNlO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSBuZXdseSBjcmVhdGVkIHJ1blxuICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlc29sdmUoKS5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSB1c2FibGUgcnVuXG4gICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVzb2x2ZSh0aGlzLnJ1blNlcnZpY2UpLnByb21pc2UoKTtcbiAgICB9XG59KTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xuXG52YXIgSWRlbnRpdHlTdHJhdGVneSA9IHJlcXVpcmUoJy4vaWRlbnRpdHktc3RyYXRlZ3knKTtcbnZhciBXb3JsZEFwaUFkYXB0ZXIgPSByZXF1aXJlKCcuLi8uLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuLi9hdXRoLW1hbmFnZXInKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHN0b3JlOiB7XG4gICAgICAgIHN5bmNocm9ub3VzOiB0cnVlXG4gICAgfVxufTtcblxudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKElkZW50aXR5U3RyYXRlZ3ksIHtcblxuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICB0aGlzLnJ1blNlcnZpY2UgPSBydW5TZXJ2aWNlO1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMud29ybGRBcGkgPSBuZXcgV29ybGRBcGlBZGFwdGVyKHRoaXMub3B0aW9ucy5ydW4pO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICB2YXIgY3VyVXNlcklkID0gc2Vzc2lvbi51c2VySWQ7XG4gICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaVxuICAgICAgICAgICAgLmdldEN1cnJlbnRXb3JsZEZvclVzZXIoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaS5uZXdSdW5Gb3JXb3JsZCh3b3JsZC5pZCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIGN1clVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICB2YXIgY3VyR3JvdXBOYW1lID0gc2Vzc2lvbi5ncm91cE5hbWU7XG4gICAgICAgIHZhciB3b3JsZEFwaSA9IHRoaXMud29ybGRBcGk7XG4gICAgICAgIHZhciBtb2RlbCA9IHRoaXMub3B0aW9ucy5tb2RlbDtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcblxuICAgICAgICBpZiAoIWN1clVzZXJJZCkge1xuICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDAsIGVycm9yOiAnV2UgbmVlZCBhbiBhdXRoZW50aWNhdGVkIHVzZXIgdG8gam9pbiBhIG11bHRpcGxheWVyIHdvcmxkLiAoRVJSOiBubyB1c2VySWQgaW4gc2Vzc2lvbiknIH0sIHNlc3Npb24pLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBsb2FkUnVuRnJvbVdvcmxkID0gZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICBpZiAoIXdvcmxkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDQsIGVycm9yOiAnVGhlIHVzZXIgaXMgbm90IGluIGFueSB3b3JsZC4nIH0sIHsgb3B0aW9uczogdGhpcy5vcHRpb25zLCBzZXNzaW9uOiBzZXNzaW9uIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gd29ybGRBcGkuZ2V0Q3VycmVudFJ1bklkKHsgbW9kZWw6IG1vZGVsLCBmaWx0ZXI6IHdvcmxkLmlkIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oX3RoaXMuX2xvYWRSdW4pXG4gICAgICAgICAgICAgICAgLnRoZW4oZHRkLnJlc29sdmUpXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHNlcnZlckVycm9yID0gZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAvLyBpcyB0aGlzIHBvc3NpYmxlP1xuICAgICAgICAgICAgZHRkLnJlamVjdChlcnJvciwgc2Vzc2lvbiwgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLndvcmxkQXBpXG4gICAgICAgICAgICAuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcihjdXJVc2VySWQsIGN1ckdyb3VwTmFtZSlcbiAgICAgICAgICAgIC50aGVuKGxvYWRSdW5Gcm9tV29ybGQpXG4gICAgICAgICAgICAuZmFpbChzZXJ2ZXJFcnJvcik7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIF9sb2FkUnVuOiBmdW5jdGlvbiAoaWQsIG9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5sb2FkKGlkLCBudWxsLCBvcHRpb25zKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIHJldHVybiBoZWFkZXJzLmdldFJlc3BvbnNlSGVhZGVyKCdwcmFnbWEnKSA9PT0gJ3BlcnNpc3RlbnQnIHx8IHJ1bi5pbml0aWFsaXplZDtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbi8qXG4qICBjcmVhdGUgYSBuZXcgcnVuIG9ubHkgaWYgbm90aGluZyBpcyBzdG9yZWQgaW4gdGhlIGNvb2tpZVxuKiAgdGhpcyBpcyB1c2VmdWwgZm9yIGJhc2VSdW5zLlxuKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgLy8gaWYgd2UgYXJlIGhlcmUsIGl0IG1lYW5zIHRoYXQgdGhlIHJ1biBleGlzdHMuLi4gc28gd2UgZG9uJ3QgbmVlZCBhIG5ldyBvbmVcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgcmV0dXJuIGhlYWRlcnMuZ2V0UmVzcG9uc2VIZWFkZXIoJ3ByYWdtYScpID09PSAncGVyc2lzdGVudCc7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBJZGVudGl0eVN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIFN0YXRlQXBpID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xudmFyIEF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4uL2tleS1uYW1lcycpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgc3RvcmU6IHtcbiAgICAgICAgc3luY2hyb25vdXM6IHRydWVcbiAgICB9XG59O1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oSWRlbnRpdHlTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiBTdHJhdGVneShydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICAgICAgdGhpcy5fc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkodGhpcy5vcHRpb25zLnN0b3JlKTtcbiAgICAgICAgdGhpcy5zdGF0ZUFwaSA9IG5ldyBTdGF0ZUFwaSgpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG5cbiAgICAgICAgdGhpcy5fbG9hZEFuZENoZWNrID0gdGhpcy5fbG9hZEFuZENoZWNrLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX3Jlc3RvcmVSdW4gPSB0aGlzLl9yZXN0b3JlUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2dldEFsbFJ1bnMgPSB0aGlzLl9nZXRBbGxSdW5zLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAocnVuU2VydmljZU9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiBzZXNzaW9uLmdyb3VwTmFtZSB9XG4gICAgICAgIH0sIHRoaXMucnVuT3B0aW9ucyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuXG4gICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0QWxsUnVucygpXG4gICAgICAgICAgICAudGhlbih0aGlzLl9sb2FkQW5kQ2hlY2spO1xuICAgIH0sXG5cbiAgICBfZ2V0QWxsUnVuczogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IEpTT04ucGFyc2UodGhpcy5fc3RvcmUuZ2V0KGtleU5hbWVzLkVQSV9TRVNTSU9OX0tFWSkgfHwgJ3t9Jyk7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5xdWVyeSh7XG4gICAgICAgICAgICAndXNlci5pZCc6IHNlc3Npb24udXNlcklkIHx8ICcwMDAwJyxcbiAgICAgICAgICAgICdzY29wZS5ncm91cCc6IHNlc3Npb24uZ3JvdXBOYW1lXG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICBfbG9hZEFuZENoZWNrOiBmdW5jdGlvbiAocnVucykge1xuICAgICAgICBpZiAoIXJ1bnMgfHwgIXJ1bnMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yZXNldCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGRhdGVDb21wID0gZnVuY3Rpb24gKGEsIGIpIHsgcmV0dXJuIG5ldyBEYXRlKGIuZGF0ZSkgLSBuZXcgRGF0ZShhLmRhdGUpOyB9O1xuICAgICAgICB2YXIgbGF0ZXN0UnVuID0gcnVucy5zb3J0KGRhdGVDb21wKVswXTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIHNob3VsZFJlcGxheSA9IGZhbHNlO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5sb2FkKGxhdGVzdFJ1bi5pZCwgbnVsbCwge1xuICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKHJ1biwgbXNnLCBoZWFkZXJzKSB7XG4gICAgICAgICAgICAgICAgc2hvdWxkUmVwbGF5ID0gaGVhZGVycy5nZXRSZXNwb25zZUhlYWRlcigncHJhZ21hJykgPT09ICdwZXJzaXN0ZW50JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSkudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICByZXR1cm4gc2hvdWxkUmVwbGF5ID8gX3RoaXMuX3Jlc3RvcmVSdW4ocnVuLmlkKSA6IHJ1bjtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIF9yZXN0b3JlUnVuOiBmdW5jdGlvbiAocnVuSWQpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGVBcGkucmVwbGF5KHsgcnVuSWQ6IHJ1bklkIH0pXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzcCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5fbG9hZFJ1bihyZXNwLnJ1bik7XG4gICAgICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgX2xvYWRSdW46IGZ1bmN0aW9uIChpZCwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5ydW4ubG9hZChpZCwgbnVsbCwgb3B0aW9ucyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIm1vZHVsZS5leHBvcnRzID0ge1xuICAgICduZXctaWYtaW5pdGlhbGl6ZWQnOiByZXF1aXJlKCcuL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpLFxuICAgICduZXctaWYtcGVyc2lzdGVkJzogcmVxdWlyZSgnLi9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5JyksXG4gICAgJ25ldy1pZi1taXNzaW5nJzogcmVxdWlyZSgnLi9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpLFxuICAgICdhbHdheXMtbmV3JzogcmVxdWlyZSgnLi9hbHdheXMtbmV3LXN0cmF0ZWd5JyksXG4gICAgJ211bHRpcGxheWVyJzogcmVxdWlyZSgnLi9tdWx0aXBsYXllci1zdHJhdGVneScpLFxuICAgICdwZXJzaXN0ZW50LXNpbmdsZS1wbGF5ZXInOiByZXF1aXJlKCcuL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneScpLFxuICAgICdub25lJzogcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpXG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIFJ1blNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgdmFsaWRGaWx0ZXI6IHsgc2F2ZWQ6IHRydWUgfVxufTtcblxuZnVuY3Rpb24gU2NlbmFyaW9NYW5hZ2VyKG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMucnVuU2VydmljZSA9IHRoaXMub3B0aW9ucy5ydW4gfHwgbmV3IFJ1blNlcnZpY2UodGhpcy5vcHRpb25zKTtcbn1cblxuU2NlbmFyaW9NYW5hZ2VyLnByb3RvdHlwZSA9IHtcbiAgICBnZXRSdW5zOiBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgIHRoaXMuZmlsdGVyID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMub3B0aW9ucy52YWxpZEZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5xdWVyeSh0aGlzLmZpbHRlcik7XG4gICAgfSxcblxuICAgIGxvYWRWYXJpYWJsZXM6IGZ1bmN0aW9uICh2YXJzKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1blNlcnZpY2UucXVlcnkodGhpcy5maWx0ZXIsIHsgaW5jbHVkZTogdmFycyB9KTtcbiAgICB9LFxuXG4gICAgc2F2ZTogZnVuY3Rpb24gKHJ1biwgbWV0YSkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0U2VydmljZShydW4pLnNhdmUoJC5leHRlbmQodHJ1ZSwge30sIHsgc2F2ZWQ6IHRydWUgfSwgbWV0YSkpO1xuICAgIH0sXG5cbiAgICBhcmNoaXZlOiBmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9nZXRTZXJ2aWNlKHJ1bikuc2F2ZSh7IHNhdmVkOiBmYWxzZSB9KTtcbiAgICB9LFxuXG4gICAgX2dldFNlcnZpY2U6IGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW4gfSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdvYmplY3QnICYmIHJ1biBpbnN0YW5jZW9mIFJ1blNlcnZpY2UpIHtcbiAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgIH1cblxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NhdmUgbWV0aG9kIHJlcXVpcmVzIGEgcnVuIHNlcnZpY2Ugb3IgYSBydW5JZCcpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW5JZCB9KSk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTY2VuYXJpb01hbmFnZXI7XG5cbiIsIid1c2Ugc3RyaWN0JztcblxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICByZXNldDogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucywgbWFuYWdlcikge1xuICAgICAgICByZXR1cm4gbWFuYWdlci5yZXNldChvcHRpb25zKTtcbiAgICB9XG59O1xuIiwiLyoqXG4qICMjIFdvcmxkIE1hbmFnZXJcbipcbiogQXMgZGlzY3Vzc2VkIHVuZGVyIHRoZSBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLyksIGEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsLiBGb3IgYnVpbGRpbmcgbXVsdGlwbGF5ZXIgc2ltdWxhdGlvbnMgeW91IHR5cGljYWxseSB3YW50IG11bHRpcGxlIGVuZCB1c2VycyB0byBzaGFyZSB0aGUgc2FtZSBzZXQgb2YgaW50ZXJhY3Rpb25zLCBhbmQgd29yayB3aXRoaW4gYSBjb21tb24gc3RhdGUuIEVwaWNlbnRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSBcIndvcmxkc1wiIHRvIGhhbmRsZSBzdWNoIGNhc2VzLlxuKlxuKiBUaGUgV29ybGQgTWFuYWdlciBwcm92aWRlcyBhbiBlYXN5IHdheSB0byB0cmFjayBhbmQgYWNjZXNzIHRoZSBjdXJyZW50IHdvcmxkIGFuZCBydW4gZm9yIHBhcnRpY3VsYXIgZW5kIHVzZXJzLiBJdCBpcyB0eXBpY2FsbHkgdXNlZCBpbiBwYWdlcyB0aGF0IGVuZCB1c2VycyB3aWxsIGludGVyYWN0IHdpdGguIChUaGUgcmVsYXRlZCBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLykgaGFuZGxlcyBjcmVhdGluZyBtdWx0aXBsYXllciB3b3JsZHMsIGFuZCBhZGRpbmcgYW5kIHJlbW92aW5nIGVuZCB1c2VycyBhbmQgcnVucyBmcm9tIGEgd29ybGQuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4pXG4qXG4qICMjIyBVc2luZyB0aGUgV29ybGQgTWFuYWdlclxuKlxuKiBUbyB1c2UgdGhlIFdvcmxkIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LiBUaGVuLCBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbipcbiogV2hlbiB5b3UgaW5zdGFudGlhdGUgYSBXb3JsZCBNYW5hZ2VyLCB0aGUgd29ybGQncyBhY2NvdW50IGlkLCBwcm9qZWN0IGlkLCBhbmQgZ3JvdXAgYXJlIGF1dG9tYXRpY2FsbHkgdGFrZW4gZnJvbSB0aGUgc2Vzc2lvbiAodGhhbmtzIHRvIHRoZSBbQXV0aGVudGljYXRpb24gU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZSkpLlxuKlxuKiBOb3RlIHRoYXQgdGhlIFdvcmxkIE1hbmFnZXIgZG9lcyAqbm90KiBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkuIChUaGlzIGlzIGRpZmZlcmVudCB0aGFuIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyKS4pIEhvd2V2ZXIsIHlvdSBjYW4gcGFzcyBpbiBzcGVjaWZpYyBvcHRpb25zIHRvIGFueSBydW5zIGNyZWF0ZWQgYnkgdGhlIG1hbmFnZXIsIHVzaW5nIGEgYHJ1bmAgb2JqZWN0LlxuKlxuKiBUaGUgcGFyYW1ldGVycyBmb3IgY3JlYXRpbmcgYSBXb3JsZCBNYW5hZ2VyIGFyZTpcbipcbiogICAqIGBhY2NvdW50YDogVGhlICoqVGVhbSBJRCoqIGluIHRoZSBFcGljZW50ZXIgdXNlciBpbnRlcmZhY2UgZm9yIHRoaXMgcHJvamVjdC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGlzIHByb2plY3QuXG4qICAgKiBgZ3JvdXBgOiBUaGUgKipHcm91cCBOYW1lKiogZm9yIHRoaXMgd29ybGQuXG4qICAgKiBgcnVuYDogT3B0aW9ucyB0byB1c2Ugd2hlbiBjcmVhdGluZyBuZXcgcnVucyB3aXRoIHRoZSBtYW5hZ2VyLCBlLmcuIGBydW46IHsgZmlsZXM6IFsnZGF0YS54bHMnXSB9YC5cbiogICAqIGBydW4ubW9kZWxgOiBUaGUgbmFtZSBvZiB0aGUgcHJpbWFyeSBtb2RlbCBmaWxlIGZvciB0aGlzIHByb2plY3QuIFJlcXVpcmVkIGlmIHlvdSBoYXZlIG5vdCBhbHJlYWR5IHBhc3NlZCBpdCBpbiBhcyBwYXJ0IG9mIHRoZSBgb3B0aW9uc2AgcGFyYW1ldGVyIGZvciBhbiBlbmNsb3NpbmcgY2FsbC5cbipcbiogRm9yIGV4YW1wbGU6XG4qXG4qICAgICAgIHZhciB3TWdyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4qICAgICAgICAgIHJ1bjogeyBtb2RlbDogJ3N1cHBseS1jaGFpbi5weScgfSxcbiogICAgICAgICAgZ3JvdXA6ICd0ZWFtMSdcbiogICAgICAgfSk7XG4qXG4qICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bigpO1xuKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgV29ybGRBcGkgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgUnVuTWFuYWdlciA9ICByZXF1aXJlKCcuL3J1bi1tYW5hZ2VyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL2F1dGgtbWFuYWdlcicpO1xudmFyIHdvcmxkQXBpO1xuXG4vLyB2YXIgZGVmYXVsdHMgPSB7XG4vLyAgYWNjb3VudDogJycsXG4vLyAgcHJvamVjdDogJycsXG4vLyAgZ3JvdXA6ICcnLFxuLy8gIHRyYW5zcG9ydDoge1xuLy8gIH1cbi8vIH07XG5cblxuZnVuY3Rpb24gYnVpbGRTdHJhdGVneSh3b3JsZElkLCBkdGQpIHtcblxuICAgIHJldHVybiBmdW5jdGlvbiBDdG9yKHJ1blNlcnZpY2UsIG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5ydW5TZXJ2aWNlID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcblxuICAgICAgICAkLmV4dGVuZCh0aGlzLCB7XG4gICAgICAgICAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbm90IGltcGxlbWVudGQuIE5lZWQgYXBpIGNoYW5nZXMnKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgICAgICAgICAgLy9nZXQgb3IgY3JlYXRlIVxuICAgICAgICAgICAgICAgIC8vIE1vZGVsIGlzIHJlcXVpcmVkIGluIHRoZSBvcHRpb25zXG4gICAgICAgICAgICAgICAgdmFyIG1vZGVsID0gdGhpcy5vcHRpb25zLnJ1bi5tb2RlbCB8fCB0aGlzLm9wdGlvbnMubW9kZWw7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHdvcmxkQXBpLmdldEN1cnJlbnRSdW5JZCh7IG1vZGVsOiBtb2RlbCwgZmlsdGVyOiB3b3JsZElkIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1blNlcnZpY2UubG9hZChydW5JZCk7XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlLmNhbGwodGhpcywgcnVuLCBfdGhpcy5ydW5TZXJ2aWNlKTtcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH07XG59XG5cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnMgfHwgeyBydW46IHt9LCB3b3JsZDoge30gfTtcblxuICAgICQuZXh0ZW5kKHRydWUsIHRoaXMub3B0aW9ucywgdGhpcy5vcHRpb25zLnJ1bik7XG4gICAgJC5leHRlbmQodHJ1ZSwgdGhpcy5vcHRpb25zLCB0aGlzLm9wdGlvbnMud29ybGQpO1xuXG4gICAgd29ybGRBcGkgPSBuZXcgV29ybGRBcGkodGhpcy5vcHRpb25zKTtcbiAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgIHZhciBhcGkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0dXJucyB0aGUgY3VycmVudCB3b3JsZCAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtXb3JsZCBBUEkgQWRhcHRlcl0oLi4vd29ybGQtYXBpLWFkYXB0ZXIvKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB3TWdyLmdldEN1cnJlbnRXb3JsZCgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkLCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdvcmxkQWRhcHRlci5nZXRDdXJyZW50UnVuSWQoKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgdXNlcklkYCAoT3B0aW9uYWwpIFRoZSBpZCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZCBpcyBiZWluZyBhY2Nlc3NlZC4gRGVmYXVsdHMgdG8gdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgZ3JvdXAgd2hvc2Ugd29ybGQgaXMgYmVpbmcgYWNjZXNzZWQuIERlZmF1bHRzIHRvIHRoZSBncm91cCBmb3IgdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFdvcmxkOiBmdW5jdGlvbiAodXNlcklkLCBncm91cE5hbWUpIHtcbiAgICAgICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5fYXV0aC5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgICAgICBpZiAoIXVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFncm91cE5hbWUpIHtcbiAgICAgICAgICAgICAgICBncm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB3b3JsZEFwaS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKHVzZXJJZCwgZ3JvdXBOYW1lKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHJ1biAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bih7bW9kZWw6ICdteU1vZGVsLnB5J30pXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1biwgcnVuU2VydmljZSkge1xuICAgICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2cocnVuLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHJ1blNlcnZpY2UuZG8oJ3N0YXJ0R2FtZScpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBtb2RlbGAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgbW9kZWwgZmlsZS4gUmVxdWlyZWQgaWYgbm90IGFscmVhZHkgcGFzc2VkIGluIGFzIGBydW4ubW9kZWxgIHdoZW4gdGhlIFdvcmxkIE1hbmFnZXIgaXMgY3JlYXRlZC5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFJ1bjogZnVuY3Rpb24gKG1vZGVsKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgICAgIHZhciBjdXJVc2VySWQgPSBzZXNzaW9uLnVzZXJJZDtcbiAgICAgICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICAgICAgZnVuY3Rpb24gZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bih3b3JsZCkge1xuICAgICAgICAgICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBlcnJvcjogJ1RoZSB1c2VyIGlzIG5vdCBwYXJ0IG9mIGFueSB3b3JsZCEnIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBjdXJyZW50V29ybGRJZCA9IHdvcmxkLmlkO1xuICAgICAgICAgICAgICAgIHZhciBydW5PcHRzID0gJC5leHRlbmQodHJ1ZSwgX3RoaXMub3B0aW9ucywgeyBtb2RlbDogbW9kZWwgfSk7XG4gICAgICAgICAgICAgICAgdmFyIHN0cmF0ZWd5ID0gYnVpbGRTdHJhdGVneShjdXJyZW50V29ybGRJZCwgZHRkKTtcbiAgICAgICAgICAgICAgICB2YXIgb3B0ID0gJC5leHRlbmQodHJ1ZSwge30sIHtcbiAgICAgICAgICAgICAgICAgICAgc3RyYXRlZ3k6IHN0cmF0ZWd5LFxuICAgICAgICAgICAgICAgICAgICBydW46IHJ1bk9wdHNcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB2YXIgcm0gPSBuZXcgUnVuTWFuYWdlcihvcHQpO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJtLmdldFJ1bigpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHJ1biwgcm0ucnVuU2VydmljZSwgcm0pO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5nZXRDdXJyZW50V29ybGQoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAgICAgLnRoZW4oZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bik7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIGFwaSk7XG59O1xuIiwiLyoqXG4gKiAjI0ZpbGUgQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGlzIGlzIHVzZWQgdG8gdXBsb2FkL2Rvd25sb2FkIGZpbGVzIGRpcmVjdGx5IG9udG8gRXBpY2VudGVyLCBhbmFsb2dvdXMgdG8gdXNpbmcgdGhlIEZpbGUgTWFuYWdlciBVSSBpbiBFcGljZW50ZXIgZGlyZWN0bHkgb3IgU0ZUUGluZyBmaWxlcyBpbi4gVGhlIEFzc2V0IEFQSSBpcyB0eXBpY2FsbHkgdXNlZCBmb3IgYWxsIHByb2plY3QgdXNlLWNhc2VzLCBhbmQgaXQncyB1bmxpa2VseSB0aGlzIEZpbGUgU2VydmljZSB3aWxsIGJlIHVzZWQgZGlyZWN0bHkgZXhjZXB0IGJ5IEFkbWluIHRvb2xzIChlLmcuIEZsb3cgSW5zcGVjdG9yKS5cbiAqXG4gKiBQYXJ0aWFsbHkgaW1wbGVtZW50ZWQuXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIC8vIGNvbmZpZyB8fCAoY29uZmlnID0gY29uZmlnU2VydmljZS5nZXQoKSk7XG4gICAgdmFyIHN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHsgc3luY2hyb25vdXM6IHRydWUgfSk7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICAgdG9rZW46IHN0b3JlLmdldCgnZXBpY2VudGVyLnByb2plY3QudG9rZW4nKSB8fCBzdG9yZS5nZXQoJ2VwaWNlbnRlci50b2tlbicpIHx8ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiAnJyxcblxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgnZmlsZScpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQXN5bmNBUEkgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgYSBkaXJlY3RvcnkgbGlzdGluZywgb3IgY29udGVudHMgb2YgYSBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGZpbGVQYXRoYCAgIFBhdGggdG8gdGhlIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBgZm9sZGVyVHlwZWAgT25lIG9mIE1vZGVsfFN0YXRpY3xOb2RlXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBnZXRDb250ZW50czogZnVuY3Rpb24gKGZpbGVQYXRoLCBmb2xkZXJUeXBlLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IGZvbGRlclR5cGUgKyAnLycgKyBmaWxlUGF0aDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2ZpbGUnKSArIHBhdGhcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQXN5bmNBUEkpO1xufTtcbiIsIi8qKlxuICogIyNBc3NldCBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBBc3NldCBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHN0b3JlIGFzc2V0cyAtLSByZXNvdXJjZXMgb3IgZmlsZXMgb2YgYW55IGtpbmQgLS0gdXNlZCBieSBhIHByb2plY3Qgd2l0aCBhIHNjb3BlIHRoYXQgaXMgc3BlY2lmaWMgdG8gcHJvamVjdCwgZ3JvdXAsIG9yIGVuZCB1c2VyLlxuICpcbiAqIEFzc2V0cyBhcmUgdXNlZCB3aXRoIFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9wcm9qZWN0X2FkbWluLyN0ZWFtKS4gT25lIGNvbW1vbiB1c2UgY2FzZSBpcyBoYXZpbmcgZW5kIHVzZXJzIGluIGEgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSBvciBpbiBhIFttdWx0aXBsYXllciB3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKSB1cGxvYWQgZGF0YSAtLSB2aWRlb3MgY3JlYXRlZCBkdXJpbmcgZ2FtZSBwbGF5LCBwcm9maWxlIHBpY3R1cmVzIGZvciBjdXN0b21pemluZyB0aGVpciBleHBlcmllbmNlLCBldGMuIC0tIGFzIHBhcnQgb2YgcGxheWluZyB0aHJvdWdoIHRoZSBwcm9qZWN0LlxuICpcbiAqIFJlc291cmNlcyBjcmVhdGVkIHVzaW5nIHRoZSBBc3NldCBBZGFwdGVyIGFyZSBzY29wZWQ6XG4gKlxuICogICogUHJvamVjdCBhc3NldHMgYXJlIHdyaXRhYmxlIG9ubHkgYnkgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pLCB0aGF0IGlzLCBFcGljZW50ZXIgYXV0aG9ycy5cbiAqICAqIEdyb3VwIGFzc2V0cyBhcmUgd3JpdGFibGUgYnkgYW55b25lIHdpdGggYWNjZXNzIHRvIHRoZSBwcm9qZWN0IHRoYXQgaXMgcGFydCBvZiB0aGF0IHBhcnRpY3VsYXIgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS4gVGhpcyBpbmNsdWRlcyBhbGwgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIChFcGljZW50ZXIgYXV0aG9ycykgYW5kIGFueSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiB0aGUgZ3JvdXAgLS0gYm90aCBmYWNpbGl0YXRvcnMgYW5kIHN0YW5kYXJkIGVuZCB1c2Vycy5cbiAqICAqIFVzZXIgYXNzZXRzIGFyZSB3cml0YWJsZSBieSB0aGUgc3BlY2lmaWMgZW5kIHVzZXIsIGFuZCBieSB0aGUgZmFjaWxpdGF0b3Igb2YgdGhlIGdyb3VwLlxuICogICogQWxsIGFzc2V0cyBhcmUgcmVhZGFibGUgYnkgYW55b25lIHdpdGggdGhlIGV4YWN0IFVSSS5cbiAqXG4gKiBUbyB1c2UgdGhlIEFzc2V0IEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSkgYW5kIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKS4gVGhlIGdyb3VwIG5hbWUgaXMgcmVxdWlyZWQgZm9yIGFzc2V0cyB3aXRoIGEgZ3JvdXAgc2NvcGUsIGFuZCB0aGUgZ3JvdXAgbmFtZSBhbmQgdXNlcklkIGFyZSByZXF1aXJlZCBmb3IgYXNzZXRzIHdpdGggYSB1c2VyIHNjb3BlLiBJZiBub3QgaW5jbHVkZWQsIHRoZXkgYXJlIHRha2VuIGZyb20gdGhlIGxvZ2dlZCBpbiB1c2VyJ3Mgc2Vzc2lvbiBpbmZvcm1hdGlvbiBpZiBuZWVkZWQuXG4gKlxuICogV2hlbiBjcmVhdGluZyBhbiBhc3NldCwgeW91IGNhbiBwYXNzIGluIHRleHQgKGVuY29kZWQgZGF0YSkgdG8gdGhlIGBjcmVhdGUoKWAgY2FsbC4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBtYWtlIHRoZSBgY3JlYXRlKClgIGNhbGwgYXMgcGFydCBvZiBhbiBIVE1MIGZvcm0gYW5kIHBhc3MgaW4gYSBmaWxlIHVwbG9hZGVkIHZpYSB0aGUgZm9ybS5cbiAqXG4gKiAgICAgICAvLyBpbnN0YW50aWF0ZSB0aGUgQXNzZXQgQWRhcHRlclxuICogICAgICAgdmFyIGFhID0gbmV3IEYuc2VydmljZS5Bc3NldCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gKiAgICAgICAgICB1c2VySWQ6ICcxMjM0NSdcbiAqICAgICAgIH0pO1xuICpcbiAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAqICAgICAgIGFhLmNyZWF0ZSgndGVzdC50eHQnLCB7XG4gKiAgICAgICAgICAgZW5jb2Rpbmc6ICdCQVNFXzY0JyxcbiAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICogICAgICAgfSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICpcbiAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAqICAgICAgIC8vIHRoaXMgc2FtcGxlIGNvZGUgZ29lcyB3aXRoIGFuIGh0bWwgZm9ybSB0aGF0IGxvb2tzIGxpa2UgdGhpczpcbiAqICAgICAgIC8vXG4gKiAgICAgICAvLyA8Zm9ybSBpZD1cInVwbG9hZC1maWxlXCI+XG4gKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlVwbG9hZCBteUZpbGU8L2J1dHRvbj5cbiAqICAgICAgIC8vIDwvZm9ybT5cbiAqICAgICAgIC8vXG4gKiAgICAgICAkKCcjdXBsb2FkLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAqICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAqXG4gKiAgICAgICAgICBhYS5jcmVhdGUoZmlsZW5hbWUsIGRhdGEsIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAqICAgICAgIH0pO1xuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBTdG9yYWdlRmFjdG9yeSA9IHJlcXVpcmUoJy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbi8vIHZhciBxdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIGtleU5hbWVzID0gcmVxdWlyZSgnLi4vbWFuYWdlcnMva2V5LW5hbWVzJyk7XG5cbnZhciBhcGlFbmRwb2ludCA9ICdhc3NldCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBzdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh7IHN5bmNocm9ub3VzOiB0cnVlIH0pO1xuICAgIHZhciBzZXNzaW9uID0gSlNPTi5wYXJzZShzdG9yZS5nZXQoa2V5TmFtZXMuRVBJX1NFU1NJT05fS0VZKSB8fCAne30nKTtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KGtleU5hbWVzLkVQSV9DT09LSUVfS0VZKSB8fCAnJyxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgZ3JvdXAgbmFtZS4gRGVmYXVsdHMgdG8gc2Vzc2lvbidzIGBncm91cE5hbWVgLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZ3JvdXA6IHNlc3Npb24uZ3JvdXBOYW1lLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHVzZXIgaWQuIERlZmF1bHRzIHRvIHNlc3Npb24ncyBgdXNlcklkYC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogc2Vzc2lvbi51c2VySWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgc2NvcGUgZm9yIHRoZSBhc3NldC4gVmFsaWQgdmFsdWVzIGFyZTogYHVzZXJgLCBgZ3JvdXBgLCBhbmQgYHByb2plY3RgLiBTZWUgYWJvdmUgZm9yIHRoZSByZXF1aXJlZCBwZXJtaXNzaW9ucyB0byB3cml0ZSB0byBlYWNoIHNjb3BlLiBEZWZhdWx0cyB0byBgdXNlcmAsIG1lYW5pbmcgdGhlIGN1cnJlbnQgZW5kIHVzZXIgb3IgYSBmYWNpbGl0YXRvciBpbiB0aGUgZW5kIHVzZXIncyBncm91cCBjYW4gZWRpdCB0aGUgYXNzZXQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBzY29wZTogJ3VzZXInLFxuICAgICAgICAvKipcbiAgICAgICAgICogRGV0ZXJtaW5lcyBpZiBhIHJlcXVlc3QgdG8gbGlzdCB0aGUgYXNzZXRzIGluIGEgc2NvcGUgaW5jbHVkZXMgdGhlIGNvbXBsZXRlIFVSTCBmb3IgZWFjaCBhc3NldCAoYHRydWVgKSwgb3Igb25seSB0aGUgZmlsZSBuYW1lcyBvZiB0aGUgYXNzZXRzIChgZmFsc2VgKS4gRGVmYXVsdHMgdG8gYHRydWVgLlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn1cbiAgICAgICAgICovXG4gICAgICAgIGZ1bGxVcmw6IHRydWUsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgdHJhbnNwb3J0IG9iamVjdCBjb250YWlucyB0aGUgb3B0aW9ucyBwYXNzZWQgdG8gdGhlIFhIUiByZXF1ZXN0LlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7XG4gICAgICAgICAgICBwcm9jZXNzRGF0YTogZmFsc2VcbiAgICAgICAgfVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIGlmICghc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50ID0gdXJsQ29uZmlnLmFjY291bnRQYXRoO1xuICAgIH1cblxuICAgIGlmICghc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0ID0gdXJsQ29uZmlnLnByb2plY3RQYXRoO1xuICAgIH1cblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuXG4gICAgdmFyIGFzc2V0QXBpUGFyYW1zID0gWydlbmNvZGluZycsICdkYXRhJywgJ2NvbnRlbnRUeXBlJ107XG4gICAgdmFyIHNjb3BlQ29uZmlnID0ge1xuICAgICAgICB1c2VyOiBbJ3Njb3BlJywgJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCcsICd1c2VySWQnXSxcbiAgICAgICAgZ3JvdXA6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10sXG4gICAgICAgIHByb2plY3Q6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0J10sXG4gICAgfTtcblxuICAgIHZhciB2YWxpZGF0ZUZpbGVuYW1lID0gZnVuY3Rpb24gKGZpbGVuYW1lKSB7XG4gICAgICAgIGlmICghZmlsZW5hbWUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZmlsZW5hbWUgaXMgbmVlZGVkLicpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciB2YWxpZGF0ZVVybFBhcmFtcyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBwYXJ0S2V5cyA9IHNjb3BlQ29uZmlnW29wdGlvbnMuc2NvcGVdO1xuICAgICAgICBpZiAoIXBhcnRLZXlzKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3Njb3BlIHBhcmFtZXRlciBpcyBuZWVkZWQuJyk7XG4gICAgICAgIH1cblxuICAgICAgICAkLmVhY2gocGFydEtleXMsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmICghb3B0aW9uc1t0aGlzXSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcih0aGlzICsgJyBwYXJhbWV0ZXIgaXMgbmVlZGVkLicpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgdmFyIGJ1aWxkVXJsID0gZnVuY3Rpb24gKGZpbGVuYW1lLCBvcHRpb25zKSB7XG4gICAgICAgIHZhbGlkYXRlVXJsUGFyYW1zKG9wdGlvbnMpO1xuICAgICAgICB2YXIgcGFydEtleXMgPSBzY29wZUNvbmZpZ1tvcHRpb25zLnNjb3BlXTtcbiAgICAgICAgdmFyIHBhcnRzID0gJC5tYXAocGFydEtleXMsIGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgIHJldHVybiBvcHRpb25zW2tleV07XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoZmlsZW5hbWUpIHtcbiAgICAgICAgICAgIC8vIFRoaXMgcHJldmVudHMgYWRkaW5nIGEgdHJhaWxpbmcgLyBpbiB0aGUgVVJMIGFzIHRoZSBBc3NldCBBUElcbiAgICAgICAgICAgIC8vIGRvZXMgbm90IHdvcmsgY29ycmVjdGx5IHdpdGggaXRcbiAgICAgICAgICAgIGZpbGVuYW1lID0gJy8nICsgZmlsZW5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHBhcnRzLmpvaW4oJy8nKSArIGZpbGVuYW1lO1xuICAgIH07XG5cbiAgICAvLyBQcml2YXRlIGZ1bmN0aW9uLCBhbGwgcmVxdWVzdHMgZm9sbG93IGEgbW9yZSBvciBsZXNzIHNhbWUgYXBwcm9hY2ggdG9cbiAgICAvLyB1c2UgdGhlIEFzc2V0IEFQSSBhbmQgdGhlIGRpZmZlcmVuY2UgaXMgdGhlIEhUVFAgdmVyYlxuICAgIC8vXG4gICAgLy8gQHBhcmFtIHtzdHJpbmd9IGBtZXRob2RgIChSZXF1aXJlZCkgSFRUUCB2ZXJiXG4gICAgLy8gQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIGRlbGV0ZS9yZXBsYWNlL2NyZWF0ZVxuICAgIC8vIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCAoT3B0aW9uYWwpIEJvZHkgcGFyYW1ldGVycyB0byBzZW5kIHRvIHRoZSBBc3NldCBBUElcbiAgICAvLyBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgdmFyIHVwbG9hZCA9IGZ1bmN0aW9uIChtZXRob2QsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFsaWRhdGVGaWxlbmFtZShmaWxlbmFtZSk7XG4gICAgICAgIC8vIG1ha2Ugc3VyZSB0aGUgcGFyYW1ldGVyIGlzIGNsZWFuXG4gICAgICAgIG1ldGhvZCA9IG1ldGhvZC50b0xvd2VyQ2FzZSgpO1xuICAgICAgICB2YXIgY29udGVudFR5cGUgPSBwYXJhbXMgaW5zdGFuY2VvZiBGb3JtRGF0YSA9PT0gdHJ1ZSA/IGZhbHNlIDogJ2FwcGxpY2F0aW9uL2pzb24nO1xuICAgICAgICBpZiAoY29udGVudFR5cGUgPT09ICdhcHBsaWNhdGlvbi9qc29uJykge1xuICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIGFzc2V0QXBpUGFyYW1zKTtcbiAgICAgICAgfSBlbHNlIHsgLy8gZWxzZSB3ZSdyZSBzZW5kaW5nIGZvcm0gZGF0YSB3aGljaCBnb2VzIGRpcmVjdGx5IGluIHJlcXVlc3QgYm9keVxuICAgICAgICAgICAgLy8gRm9yIG11bHRpcGFydC9mb3JtLWRhdGEgdXBsb2FkcyB0aGUgZmlsZW5hbWUgaXMgbm90IHNldCBpbiB0aGUgVVJMLFxuICAgICAgICAgICAgLy8gaXQncyBnZXR0aW5nIHBpY2tlZCBieSB0aGUgRm9ybURhdGEgZmllbGQgZmlsZW5hbWUuXG4gICAgICAgICAgICBmaWxlbmFtZSA9IG1ldGhvZCA9PT0gJ3Bvc3QnIHx8IG1ldGhvZCA9PT0gJ3B1dCcgPyAnJyA6IGZpbGVuYW1lO1xuICAgICAgICB9XG4gICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyIHVybCA9IGJ1aWxkVXJsKGZpbGVuYW1lLCB1cmxPcHRpb25zKTtcbiAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdXJsT3B0aW9ucywgeyB1cmw6IHVybCwgY29udGVudFR5cGU6IGNvbnRlbnRUeXBlIH0pO1xuXG4gICAgICAgIHJldHVybiBodHRwW21ldGhvZF0ocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIGZpbGUgaW4gdGhlIEFzc2V0IEFQSS4gVGhlIHNlcnZlciByZXR1cm5zIGFuIGVycm9yIChzdGF0dXMgY29kZSBgNDA5YCwgY29uZmxpY3QpIGlmIHRoZSBmaWxlIGFscmVhZHkgZXhpc3RzLCBzb1xuICAgICAgICAqIGNoZWNrIGZpcnN0IHdpdGggYSBgbGlzdCgpYCBvciBhIGBnZXQoKWAuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBhYSA9IG5ldyBGLnNlcnZpY2UuQXNzZXQoe1xuICAgICAgICAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgIGdyb3VwOiAndGVhbTEnLFxuICAgICAgICAqICAgICAgICAgIHVzZXJJZDogJydcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAgICAgICAgKiAgICAgICBhYS5jcmVhdGUoJ3Rlc3QudHh0Jywge1xuICAgICAgICAqICAgICAgICAgICBlbmNvZGluZzogJ0JBU0VfNjQnLFxuICAgICAgICAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gICAgICAgICogICAgICAgICAgIGNvbnRlbnRUeXBlOiAndGV4dC9wbGFpbidcbiAgICAgICAgKiAgICAgICB9LCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAvLyBhbHRlcm5hdGl2ZWx5LCBjcmVhdGUgYSBuZXcgYXNzZXQgdXNpbmcgYSBmaWxlIHVwbG9hZGVkIHRocm91Z2ggYSBmb3JtXG4gICAgICAgICogICAgICAgLy8gdGhpcyBzYW1wbGUgY29kZSBnb2VzIHdpdGggYW4gaHRtbCBmb3JtIHRoYXQgbG9va3MgbGlrZSB0aGlzOlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgLy8gPGZvcm0gaWQ9XCJ1cGxvYWQtZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwiZmlsZVwiIHR5cGU9XCJmaWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gICAgICAgICogICAgICAgLy8gICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIj5VcGxvYWQgbXlGaWxlPC9idXR0b24+XG4gICAgICAgICogICAgICAgLy8gPC9mb3JtPlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgJCgnI3VwbG9hZC1maWxlJykub24oJ3N1Ym1pdCcsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICogICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBkYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGlucHV0Q29udHJvbCA9ICQoJyNmaWxlJylbMF07XG4gICAgICAgICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgIGFhLmNyZWF0ZShmaWxlbmFtZSwgZGF0YSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gY3JlYXRlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCAoT3B0aW9uYWwpIEJvZHkgcGFyYW1ldGVycyB0byBzZW5kIHRvIHRoZSBBc3NldCBBUEkuIFJlcXVpcmVkIGlmIHRoZSBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYCwgb3RoZXJ3aXNlIGlnbm9yZWQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZW5jb2RpbmdgIEVpdGhlciBgSEVYYCBvciBgQkFTRV82NGAuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmRhdGFgIFRoZSBlbmNvZGVkIGRhdGEgZm9yIHRoZSBmaWxlLiBSZXF1aXJlZCBpZiBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5jb250ZW50VHlwZWAgVGhlIG1pbWUgdHlwZSBvZiB0aGUgZmlsZS4gT3B0aW9uYWwuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ3Bvc3QnLCBmaWxlbmFtZSwgcGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGEgZmlsZSBmcm9tIHRoZSBBc3NldCBBUEksIGZldGNoaW5nIHRoZSBhc3NldCBjb250ZW50LiAoVG8gZ2V0IGEgbGlzdFxuICAgICAgICAqIG9mIHRoZSBhc3NldHMgaW4gYSBzY29wZSwgdXNlIGBsaXN0KClgLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSB0byByZXRyaWV2ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBnZXRTZXJ2aWNlT3B0aW9ucyA9IF9waWNrKHNlcnZpY2VPcHRpb25zLCBbJ3Njb3BlJywgJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCcsICd1c2VySWQnXSk7XG4gICAgICAgICAgICB2YXIgdXJsT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBnZXRTZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgdXJsID0gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdXJsT3B0aW9ucywgeyB1cmw6IHVybCB9KTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIHRoZSBsaXN0IG9mIHRoZSBhc3NldHMgaW4gYSBzY29wZS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBhYS5saXN0KHsgZnVsbFVybDogdHJ1ZSB9KS50aGVuKGZ1bmN0aW9uKGZpbGVMaXN0KXtcbiAgICAgICAgKiAgICAgICAgICAgY29uc29sZS5sb2coJ2FycmF5IG9mIGZpbGVzID0gJywgZmlsZUxpc3QpO1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5zY29wZWAgKE9wdGlvbmFsKSBUaGUgc2NvcGUgKGB1c2VyYCwgYGdyb3VwYCwgYHByb2plY3RgKS5cbiAgICAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IGBvcHRpb25zLmZ1bGxVcmxgIChPcHRpb25hbCkgRGV0ZXJtaW5lcyBpZiB0aGUgbGlzdCBvZiBhc3NldHMgaW4gYSBzY29wZSBpbmNsdWRlcyB0aGUgY29tcGxldGUgVVJMIGZvciBlYWNoIGFzc2V0IChgdHJ1ZWApLCBvciBvbmx5IHRoZSBmaWxlIG5hbWVzIG9mIHRoZSBhc3NldHMgKGBmYWxzZWApLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGxpc3Q6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciB1cmwgPSBidWlsZFVybCgnJywgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsIH0pO1xuICAgICAgICAgICAgdmFyIGZ1bGxVcmwgPSBnZXRPcHRpb25zLmZ1bGxVcmw7XG5cbiAgICAgICAgICAgIGlmICghZnVsbFVybCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldCh7fSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKVxuICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChmaWxlcykge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZnVsbFBhdGhGaWxlcyA9ICQubWFwKGZpbGVzLCBmdW5jdGlvbiAoZmlsZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGJ1aWxkVXJsKGZpbGUsIHVybE9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUoZnVsbFBhdGhGaWxlcywgbWUpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJlcGxhY2VzIGFuIGV4aXN0aW5nIGZpbGUgaW4gdGhlIEFzc2V0IEFQSS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAvLyByZXBsYWNlIGFuIGFzc2V0IHVzaW5nIGVuY29kZWQgdGV4dFxuICAgICAgICAqICAgICAgIGFhLnJlcGxhY2UoJ3Rlc3QudHh0Jywge1xuICAgICAgICAqICAgICAgICAgICBlbmNvZGluZzogJ0JBU0VfNjQnLFxuICAgICAgICAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhObFkyOXVaQ0IwWlhOMElHWnBiR1V1JyxcbiAgICAgICAgKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICAgICAgICAqICAgICAgIH0sIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIHJlcGxhY2UgYW4gYXNzZXQgdXNpbmcgYSBmaWxlIHVwbG9hZGVkIHRocm91Z2ggYSBmb3JtXG4gICAgICAgICogICAgICAgLy8gdGhpcyBzYW1wbGUgY29kZSBnb2VzIHdpdGggYW4gaHRtbCBmb3JtIHRoYXQgbG9va3MgbGlrZSB0aGlzOlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgLy8gPGZvcm0gaWQ9XCJyZXBsYWNlLWZpbGVcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwicmVwbGFjZS1maWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gICAgICAgICogICAgICAgLy8gICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIj5SZXBsYWNlIG15RmlsZTwvYnV0dG9uPlxuICAgICAgICAqICAgICAgIC8vIDwvZm9ybT5cbiAgICAgICAgKiAgICAgICAvL1xuICAgICAgICAqICAgICAgICQoJyNyZXBsYWNlLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgKiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGZpbGVuYW1lID0gJCgnI3JlcGxhY2UtZmlsZW5hbWUnKS52YWwoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgZGF0YSA9IG5ldyBGb3JtRGF0YSgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICAgICAgICAqICAgICAgICAgIGRhdGEuYXBwZW5kKCdmaWxlJywgaW5wdXRDb250cm9sLmZpbGVzWzBdLCBmaWxlbmFtZSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICBhYS5yZXBsYWNlKGZpbGVuYW1lLCBkYXRhLCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgYmVpbmcgcmVwbGFjZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSS4gUmVxdWlyZWQgaWYgdGhlIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLCBvdGhlcndpc2UgaWdub3JlZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5lbmNvZGluZ2AgRWl0aGVyIGBIRVhgIG9yIGBCQVNFXzY0YC4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZGF0YWAgVGhlIGVuY29kZWQgZGF0YSBmb3IgdGhlIGZpbGUuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmNvbnRlbnRUeXBlYCBUaGUgbWltZSB0eXBlIG9mIHRoZSBmaWxlLiBPcHRpb25hbC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgcmVwbGFjZTogZnVuY3Rpb24gKGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ3B1dCcsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgYSBmaWxlIGZyb20gdGhlIEFzc2V0IEFQSS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBhYS5kZWxldGUoc2FtcGxlRmlsZU5hbWUpO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIGRlbGV0ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgZGVsZXRlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ2RlbGV0ZScsIGZpbGVuYW1lLCB7fSwgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgYXNzZXRVcmw6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGJ1aWxkVXJsKGZpbGVuYW1lLCB1cmxPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjI0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhlIEF1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlIHByb3ZpZGVzIG1ldGhvZHMgZm9yIGxvZ2dpbmcgaW4gYW5kIGxvZ2dpbmcgb3V0LiBPbiBsb2dpbiwgdGhpcyBzZXJ2aWNlIGNyZWF0ZXMgYW5kIHJldHVybnMgYSB1c2VyIGFjY2VzcyB0b2tlbi5cbiAqXG4gKiBVc2VyIGFjY2VzcyB0b2tlbnMgYXJlIHJlcXVpcmVkIGZvciBlYWNoIGNhbGwgdG8gRXBpY2VudGVyLiAoU2VlIFtQcm9qZWN0IEFjY2Vzc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSBmb3IgbW9yZSBpbmZvcm1hdGlvbi4pXG4gKlxuICogSWYgeW91IG5lZWQgYWRkaXRpb25hbCBmdW5jdGlvbmFsaXR5IC0tIHN1Y2ggYXMgdHJhY2tpbmcgc2Vzc2lvbiBpbmZvcm1hdGlvbiwgZWFzaWx5IHJldHJpZXZpbmcgdGhlIHVzZXIgdG9rZW4sIG9yIGdldHRpbmcgdGhlIGdyb3VwcyB0byB3aGljaCBhbiBlbmQgdXNlciBiZWxvbmdzIC0tIGNvbnNpZGVyIHVzaW5nIHRoZSBbQXV0aG9yaXphdGlvbiBNYW5hZ2VyXSguLi9hdXRoLW1hbmFnZXIvKSBpbnN0ZWFkLlxuICpcbiAqICAgICAgdmFyIGF1dGggPSBuZXcgRi5zZXJ2aWNlLkF1dGgoKTtcbiAqICAgICAgYXV0aC5sb2dpbih7IHVzZXJOYW1lOiAnanNtaXRoQGFjbWVzaW11bGF0aW9ucy5jb20nLFxuICogICAgICAgICAgICAgICAgICBwYXNzd29yZDogJ3Bhc3N3MHJkJyB9KTtcbiAqICAgICAgYXV0aC5sb2dvdXQoKTtcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRW1haWwgb3IgdXNlcm5hbWUgdG8gdXNlIGZvciBsb2dnaW5nIGluLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1c2VyTmFtZTogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcGFzc3dvcmQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZCBmb3IgdGhpcyBgdXNlck5hbWVgLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yIHRoZSAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gUmVxdWlyZWQgaWYgdGhlIGB1c2VyTmFtZWAgaXMgZm9yIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdhdXRoZW50aWNhdGlvbicpXG4gICAgfSk7XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIExvZ3MgdXNlciBpbiwgcmV0dXJuaW5nIHRoZSB1c2VyIGFjY2VzcyB0b2tlbi5cbiAgICAgICAgICpcbiAgICAgICAgICogSWYgbm8gYHVzZXJOYW1lYCBvciBgcGFzc3dvcmRgIHdlcmUgcHJvdmlkZWQgaW4gdGhlIGluaXRpYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLCB0aGV5IGFyZSByZXF1aXJlZCBpbiB0aGUgYG9wdGlvbnNgIGhlcmUuIElmIG5vIGBhY2NvdW50YCB3YXMgcHJvdmlkZWQgaW4gdGhlIGluaXRpYWwgY29uZmlndXJhdGlvbiBvcHRpb25zIGFuZCB0aGUgYHVzZXJOYW1lYCBpcyBmb3IgYW4gW2VuZCB1c2VyXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpLCB0aGUgYGFjY291bnRgIGlzIHJlcXVpcmVkIGFzIHdlbGwuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgYXV0aC5sb2dpbih7XG4gICAgICAgICAqICAgICAgICAgIHVzZXJOYW1lOiAnanNtaXRoJyxcbiAgICAgICAgICogICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCcsXG4gICAgICAgICAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyB9KVxuICAgICAgICAgKiAgICAgIC50aGVuKGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhcInVzZXIgYWNjZXNzIHRva2VuIGlzOiBcIiwgdG9rZW4uYWNjZXNzX3Rva2VuKTtcbiAgICAgICAgICogICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9naW46IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7IHN1Y2Nlc3M6ICQubm9vcCB9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBpZiAoIWh0dHBPcHRpb25zLnVzZXJOYW1lIHx8ICFodHRwT3B0aW9ucy5wYXNzd29yZCkge1xuICAgICAgICAgICAgICAgIHZhciByZXNwID0geyBzdGF0dXM6IDQwMSwgc3RhdHVzTWVzc2FnZTogJ05vIHVzZXJuYW1lIG9yIHBhc3N3b3JkIHNwZWNpZmllZC4nIH07XG4gICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMuZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5lcnJvci5jYWxsKHRoaXMsIHJlc3ApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVqZWN0KHJlc3ApLnByb21pc2UoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHBvc3RQYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgdXNlck5hbWU6IGh0dHBPcHRpb25zLnVzZXJOYW1lLFxuICAgICAgICAgICAgICAgIHBhc3N3b3JkOiBodHRwT3B0aW9ucy5wYXNzd29yZCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBpZiAoaHR0cE9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICAgICAgICAgIC8vcGFzcyBpbiBudWxsIGZvciBhY2NvdW50IHVuZGVyIG9wdGlvbnMgaWYgeW91IGRvbid0IHdhbnQgaXQgdG8gYmUgc2VudFxuICAgICAgICAgICAgICAgIHBvc3RQYXJhbXMuYWNjb3VudCA9IGh0dHBPcHRpb25zLmFjY291bnQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocG9zdFBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2dzIHVzZXIgb3V0IGZyb20gc3BlY2lmaWVkIGFjY291bnRzLlxuICAgICAgICAgKiBFcGljZW50ZXIgbG9nb3V0IGlzIG5vdCBpbXBsZW1lbnRlZCB5ZXQsIGFkZGVkIGEgZHVtbXkgcHJvbWlzZSB0aGF0IGdldHMgYXV0b21hdGljYWxseSByZXNvbHZlZC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICBhdXRoLmxvZ291dCgpO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2dvdXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgZHRkLnJlc29sdmUoKTtcbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqICMjIENoYW5uZWwgU2VydmljZVxuICpcbiAqIFRoZSBFcGljZW50ZXIgcGxhdGZvcm0gcHJvdmlkZXMgYSBwdXNoIGNoYW5uZWwsIHdoaWNoIGFsbG93cyB5b3UgdG8gcHVibGlzaCBhbmQgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzIHdpdGhpbiBhIFtwcm9qZWN0XSguLi8uLi8uLi9nbG9zc2FyeS8jcHJvamVjdHMpLCBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvciBbbXVsdGlwbGF5ZXIgd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuIFRoZXJlIGFyZSB0d28gbWFpbiB1c2UgY2FzZXMgZm9yIHRoZSBjaGFubmVsOiBldmVudCBub3RpZmljYXRpb25zIGFuZCBjaGF0IG1lc3NhZ2VzLlxuICpcbiAqIFRoZSBDaGFubmVsIFNlcnZpY2UgaXMgYSBidWlsZGluZyBibG9jayBmb3IgdGhpcyBmdW5jdGlvbmFsaXR5LiBJdCBjcmVhdGVzIGEgcHVibGlzaC1zdWJzY3JpYmUgb2JqZWN0LCBhbGxvd2luZyB5b3UgdG8gcHVibGlzaCBtZXNzYWdlcywgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzLCBvciB1bnN1YnNjcmliZSBmcm9tIG1lc3NhZ2VzIGZvciBhIGdpdmVuICd0b3BpYycgb24gYSBgJC5jb21ldGRgIHRyYW5zcG9ydCBpbnN0YW5jZS5cbiAqXG4gKiBUeXBpY2FsbHksIHlvdSB1c2UgdGhlIFtFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLykgdG8gY3JlYXRlIG9yIHJldHJpZXZlIGNoYW5uZWxzLCB0aGVuIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gbGlzdGVuIHRvIG9yIHVwZGF0ZSBkYXRhLiAoRm9yIGFkZGl0aW9uYWwgYmFja2dyb3VuZCBvbiBFcGljZW50ZXIncyBwdXNoIGNoYW5uZWwsIHNlZSB0aGUgaW50cm9kdWN0b3J5IG5vdGVzIG9uIHRoZSBbUHVzaCBDaGFubmVsIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL2NoYW5uZWwvKSBwYWdlLilcbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBDaGFubmVsIFNlcnZpY2UuIFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLlxuICpcbiAqIFRvIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlLCBpbnN0YW50aWF0ZSBpdCwgdGhlbiBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbiAqXG4gKiAgICAgICAgdmFyIGNzID0gbmV3IEYuc2VydmljZS5DaGFubmVsKCk7XG4gKiAgICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi92YXJpYWJsZXMnLCB7IHByaWNlOiA1MCB9KTtcbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhIENoYW5uZWwgU2VydmljZSBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIFRoZSBvcHRpb25zIG9iamVjdCB0byBjb25maWd1cmUgdGhlIENoYW5uZWwgU2VydmljZS5cbiAqICogYG9wdGlvbnMuYmFzZWAgVGhlIGJhc2UgdG9waWMuIFRoaXMgaXMgYWRkZWQgYXMgYSBwcmVmaXggdG8gYWxsIGZ1cnRoZXIgdG9waWNzIHlvdSBwdWJsaXNoIG9yIHN1YnNjcmliZSB0byB3aGlsZSB3b3JraW5nIHdpdGggdGhpcyBDaGFubmVsIFNlcnZpY2UuXG4gKiAqIGBvcHRpb25zLnRvcGljUmVzb2x2ZXJgIEEgZnVuY3Rpb24gdGhhdCBwcm9jZXNzZXMgYWxsICd0b3BpY3MnIHBhc3NlZCBpbnRvIHRoZSBgcHVibGlzaGAgYW5kIGBzdWJzY3JpYmVgIG1ldGhvZHMuIFRoaXMgaXMgdXNlZnVsIGlmIHlvdSB3YW50IHRvIGltcGxlbWVudCB5b3VyIG93biBzZXJpYWxpemUgZnVuY3Rpb25zIGZvciBjb252ZXJ0aW5nIGN1c3RvbSBvYmplY3RzIHRvIHRvcGljIG5hbWVzLiBSZXR1cm5zIGEgU3RyaW5nLiBCeSBkZWZhdWx0LCBpdCBqdXN0IGVjaG9lcyB0aGUgdG9waWMuXG4gKiAqIGBvcHRpb25zLnRyYW5zcG9ydGAgVGhlIGluc3RhbmNlIG9mIGAkLmNvbWV0ZGAgdG8gaG9vayBvbnRvLiBTZWUgaHR0cDovL2RvY3MuY29tZXRkLm9yZy9yZWZlcmVuY2UvamF2YXNjcmlwdC5odG1sIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQgb24gY29tZXRkLlxuICovXG52YXIgQ2hhbm5lbCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYmFzZSB0b3BpYy4gVGhpcyBpcyBhZGRlZCBhcyBhIHByZWZpeCB0byBhbGwgZnVydGhlciB0b3BpY3MgeW91IHB1Ymxpc2ggb3Igc3Vic2NyaWJlIHRvIHdoaWxlIHdvcmtpbmcgd2l0aCB0aGlzIENoYW5uZWwgU2VydmljZS5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGJhc2U6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBBIGZ1bmN0aW9uIHRoYXQgcHJvY2Vzc2VzIGFsbCAndG9waWNzJyBwYXNzZWQgaW50byB0aGUgYHB1Ymxpc2hgIGFuZCBgc3Vic2NyaWJlYCBtZXRob2RzLiBUaGlzIGlzIHVzZWZ1bCBpZiB5b3Ugd2FudCB0byBpbXBsZW1lbnQgeW91ciBvd24gc2VyaWFsaXplIGZ1bmN0aW9ucyBmb3IgY29udmVydGluZyBjdXN0b20gb2JqZWN0cyB0byB0b3BpYyBuYW1lcy4gQnkgZGVmYXVsdCwgaXQganVzdCBlY2hvZXMgdGhlIHRvcGljLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqIGB0b3BpY2AgVG9waWMgdG8gcGFyc2UuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgICAgICpcbiAgICAgICAgICogKiAqU3RyaW5nKjogVGhpcyBmdW5jdGlvbiBzaG91bGQgcmV0dXJuIGEgc3RyaW5nIHRvcGljLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICB0b3BpY1Jlc29sdmVyOiBmdW5jdGlvbiAodG9waWMpIHtcbiAgICAgICAgICAgIHJldHVybiB0b3BpYztcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGluc3RhbmNlIG9mIGAkLmNvbWV0ZGAgdG8gaG9vayBvbnRvLlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiBudWxsXG4gICAgfTtcbiAgICB0aGlzLmNoYW5uZWxPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbn07XG5cbnZhciBtYWtlTmFtZSA9IGZ1bmN0aW9uIChjaGFubmVsTmFtZSwgdG9waWMpIHtcbiAgICAvL1JlcGxhY2UgdHJhaWxpbmcvZG91YmxlIHNsYXNoZXNcbiAgICB2YXIgbmV3TmFtZSA9IChjaGFubmVsTmFtZSA/IChjaGFubmVsTmFtZSArICcvJyArIHRvcGljKSA6IHRvcGljKS5yZXBsYWNlKC9cXC9cXC8vZywgJy8nKS5yZXBsYWNlKC9cXC8kLywnJyk7XG4gICAgcmV0dXJuIG5ld05hbWU7XG59O1xuXG5cbkNoYW5uZWwucHJvdG90eXBlID0gJC5leHRlbmQoQ2hhbm5lbC5wcm90b3R5cGUsIHtcblxuICAgIC8vIGZ1dHVyZSBmdW5jdGlvbmFsaXR5OlxuICAgIC8vICAgICAgLy8gU2V0IHRoZSBjb250ZXh0IGZvciB0aGUgY2FsbGJhY2tcbiAgICAvLyAgICAgIGNzLnN1YnNjcmliZSgncnVuJywgZnVuY3Rpb24gKCkgeyB0aGlzLmlubmVySFRNTCA9ICdUcmlnZ2VyZWQnfSwgZG9jdW1lbnQuYm9keSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gQ29udHJvbCB0aGUgb3JkZXIgb2Ygb3BlcmF0aW9ucyBieSBzZXR0aW5nIHRoZSBgcHJpb3JpdHlgXG4gICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4nLCBjYiwgdGhpcywge3ByaW9yaXR5OiA5fSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIDUwXG4gICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4vdmFyaWFibGVzL3ByaWNlJywgY2IsIHRoaXMsIHtwcmlvcml0eTogMzAsIHZhbHVlOiA1MH0pO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIE9ubHkgZXhlY3V0ZSB0aGUgY2FsbGJhY2ssIGBjYmAsIGlmIHRoZSB2YWx1ZSBvZiB0aGUgYHByaWNlYCB2YXJpYWJsZSBpcyBncmVhdGVyIHRoYW4gNTBcbiAgICAgLy8gICAgICBzdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6ICc+NTAnfSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIGV2ZW5cbiAgICAgLy8gICAgICBzdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6IGZ1bmN0aW9uICh2YWwpIHtyZXR1cm4gdmFsICUgMiA9PT0gMH19KTtcblxuXG4gICAgLyoqXG4gICAgICogU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqIFRoZSB0b3BpYyBzaG91bGQgaW5jbHVkZSB0aGUgZnVsbCBwYXRoIG9mIHRoZSBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBmb3IgdGVhbSBwcm9qZWN0cyksIHByb2plY3QgaWQsIGFuZCBncm91cCBuYW1lLiAoSW4gbW9zdCBjYXNlcywgaXQgaXMgc2ltcGxlciB0byB1c2UgdGhlIFtFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLykgaW5zdGVhZCwgaW4gd2hpY2ggY2FzZSB0aGlzIGlzIGNvbmZpZ3VyZWQgZm9yIHlvdS4pXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlcyoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBjYiA9IGZ1bmN0aW9uKHZhbCkgeyBjb25zb2xlLmxvZyh2YWwuZGF0YSk7IH07XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGEgdG9wLWxldmVsICdydW4nIHRvcGljXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4nLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGNoaWxkcmVuIG9mIHRoZSAncnVuJyB0b3BpYy4gTm90ZSB0aGlzIHdpbGwgYWxzbyBiZSB0cmlnZ2VyZWQgZm9yIGNoYW5nZXMgdG8gcnVuLngueS56LlxuICAgICAqICAgICAgY3Muc3Vic2NyaWJlKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuLyonLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGJvdGggdGhlIHRvcC1sZXZlbCAncnVuJyB0b3BpYyBhbmQgaXRzIGNoaWxkcmVuXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoWycvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuJyxcbiAgICAgKiAgICAgICAgICAnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi8qJ10sIGNiKTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSBwYXJ0aWN1bGFyIHZhcmlhYmxlXG4gICAgICogICAgICBzdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vdmFyaWFibGVzL3ByaWNlJywgY2IpO1xuICAgICAqXG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpTdHJpbmcqIFJldHVybnMgYSB0b2tlbiB5b3UgY2FuIGxhdGVyIHVzZSB0byB1bnN1YnNjcmliZS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfEFycmF5fSAgIGB0b3BpY2AgICAgTGlzdCBvZiB0b3BpY3MgdG8gbGlzdGVuIGZvciBjaGFuZ2VzIG9uLlxuICAgICAqIEBwYXJhbSAge0Z1bmN0aW9ufSBgY2FsbGJhY2tgIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGV4ZWN1dGUuIENhbGxiYWNrIGlzIGNhbGxlZCB3aXRoIHNpZ25hdHVyZSBgKGV2dCwgcGF5bG9hZCwgbWV0YWRhdGEpYC5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9ICAgYGNvbnRleHRgICBDb250ZXh0IGluIHdoaWNoIHRoZSBgY2FsbGJhY2tgIGlzIGV4ZWN1dGVkLlxuICAgICAqIEBwYXJhbSAge09iamVjdH0gICBgb3B0aW9uc2AgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICogQHBhcmFtICB7TnVtYmVyfSAgIGBvcHRpb25zLnByaW9yaXR5YCAgVXNlZCB0byBjb250cm9sIG9yZGVyIG9mIG9wZXJhdGlvbnMuIERlZmF1bHRzIHRvIDAuIENhbiBiZSBhbnkgK3ZlIG9yIC12ZSBudW1iZXIuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE51bWJlcnxGdW5jdGlvbn0gICBgb3B0aW9ucy52YWx1ZWAgVGhlIGBjYWxsYmFja2AgaXMgb25seSB0cmlnZ2VyZWQgaWYgdGhpcyBjb25kaXRpb24gbWF0Y2hlcy4gU2VlIGV4YW1wbGVzIGZvciBkZXRhaWxzLlxuICAgICAqXG4gICAgICovXG4gICAgc3Vic2NyaWJlOiBmdW5jdGlvbiAodG9waWMsIGNhbGxiYWNrLCBjb250ZXh0LCBvcHRpb25zKSB7XG5cbiAgICAgICAgdmFyIHRvcGljcyA9IFtdLmNvbmNhdCh0b3BpYyk7XG4gICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgIHZhciBzdWJzY3JpcHRpb25JZHMgPSBbXTtcbiAgICAgICAgdmFyIG9wdHMgPSBtZS5jaGFubmVsT3B0aW9ucztcblxuICAgICAgICBvcHRzLnRyYW5zcG9ydC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAkLmVhY2godG9waWNzLCBmdW5jdGlvbiAoaW5kZXgsIHRvcGljKSB7XG4gICAgICAgICAgICAgICAgdG9waWMgPSBtYWtlTmFtZShvcHRzLmJhc2UsIG9wdHMudG9waWNSZXNvbHZlcih0b3BpYykpO1xuICAgICAgICAgICAgICAgIHN1YnNjcmlwdGlvbklkcy5wdXNoKG9wdHMudHJhbnNwb3J0LnN1YnNjcmliZSh0b3BpYywgY2FsbGJhY2spKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIChzdWJzY3JpcHRpb25JZHNbMV0gPyBzdWJzY3JpcHRpb25JZHMgOiBzdWJzY3JpcHRpb25JZHNbMF0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBQdWJsaXNoIGRhdGEgdG8gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAqXG4gICAgICogICAgICAvLyBTZW5kIGRhdGEgdG8gYWxsIHN1YnNjcmliZXJzIG9mIHRoZSAncnVuJyB0b3BpY1xuICAgICAqICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bicsIHsgY29tcGxldGVkOiBmYWxzZSB9KTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU2VuZCBkYXRhIHRvIGFsbCBzdWJzY3JpYmVycyBvZiB0aGUgJ3J1bi92YXJpYWJsZXMnIHRvcGljXG4gICAgICogICAgICBjcy5wdWJsaXNoKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuL3ZhcmlhYmxlcycsIHsgcHJpY2U6IDUwIH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYHRvcGljYCBUb3BpYyB0byBwdWJsaXNoIHRvLlxuICAgICAqIEBwYXJhbSAgeyp9IGBkYXRhYCAgRGF0YSB0byBwdWJsaXNoIHRvIHRvcGljLlxuICAgICAqXG4gICAgICovXG4gICAgcHVibGlzaDogZnVuY3Rpb24gKHRvcGljLCBkYXRhKSB7XG4gICAgICAgIHZhciB0b3BpY3MgPSBbXS5jb25jYXQodG9waWMpO1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICB2YXIgcmV0dXJuT2JqcyA9IFtdO1xuICAgICAgICB2YXIgb3B0cyA9IG1lLmNoYW5uZWxPcHRpb25zO1xuXG5cbiAgICAgICAgb3B0cy50cmFuc3BvcnQuYmF0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgJC5lYWNoKHRvcGljcywgZnVuY3Rpb24gKGluZGV4LCB0b3BpYykge1xuICAgICAgICAgICAgICAgIHRvcGljID0gbWFrZU5hbWUob3B0cy5iYXNlLCBvcHRzLnRvcGljUmVzb2x2ZXIodG9waWMpKTtcbiAgICAgICAgICAgICAgICBpZiAodG9waWMuY2hhckF0KHRvcGljLmxlbmd0aCAtIDEpID09PSAnKicpIHtcbiAgICAgICAgICAgICAgICAgICAgdG9waWMgPSB0b3BpYy5yZXBsYWNlKC9cXCorJC8sICcnKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdZb3UgY2FuIGNhbm5vdCBwdWJsaXNoIHRvIGNoYW5uZWxzIHdpdGggd2lsZGNhcmRzLiBQdWJsaXNoaW5nIHRvICcsIHRvcGljLCAnaW5zdGVhZCcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5PYmpzLnB1c2gob3B0cy50cmFuc3BvcnQucHVibGlzaCh0b3BpYywgZGF0YSkpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gKHJldHVybk9ianNbMV0gPyByZXR1cm5PYmpzIDogcmV0dXJuT2Jqc1swXSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFVuc3Vic2NyaWJlIGZyb20gY2hhbmdlcyB0byBhIHRvcGljLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgY3MudW5zdWJzY3JpYmUoJ3NhbXBsZVRva2VuJyk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYHRva2VuYCBUaGUgdG9rZW4gZm9yIHRvcGljIGlzIHJldHVybmVkIHdoZW4geW91IGluaXRpYWxseSBzdWJzY3JpYmUuIFBhc3MgaXQgaGVyZSB0byB1bnN1YnNjcmliZSBmcm9tIHRoYXQgdG9waWMuXG4gICAgICovXG4gICAgdW5zdWJzY3JpYmU6IGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICB0aGlzLmNoYW5uZWxPcHRpb25zLnRyYW5zcG9ydC51bnN1YnNjcmliZSh0b2tlbik7XG4gICAgICAgIHJldHVybiB0b2tlbjtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RhcnQgbGlzdGVuaW5nIGZvciBldmVudHMgb24gdGhpcyBpbnN0YW5jZS4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vbi8uXG4gICAgICpcbiAgICAgKiBTdXBwb3J0ZWQgZXZlbnRzIGFyZTogYGNvbm5lY3RgLCBgZGlzY29ubmVjdGAsIGBzdWJzY3JpYmVgLCBgdW5zdWJzY3JpYmVgLCBgcHVibGlzaGAsIGBlcnJvcmAuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqL1xuICAgIG9uOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS5vbi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTdG9wIGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vZmYvLlxuICAgICAqL1xuICAgIG9mZjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub2ZmLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRyaWdnZXIgZXZlbnRzIGFuZCBleGVjdXRlIGhhbmRsZXJzLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqL1xuICAgIHRyaWdnZXI6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIuYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9XG5cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IENoYW5uZWw7XG4iLCIvKipcbiAqIEBjbGFzcyBDb25maWd1cmF0aW9uU2VydmljZVxuICpcbiAqIEFsbCBzZXJ2aWNlcyB0YWtlIGluIGEgY29uZmlndXJhdGlvbiBzZXR0aW5ncyBvYmplY3QgdG8gY29uZmlndXJlIHRoZW1zZWx2ZXMuIEEgSlMgaGFzaCB7fSBpcyBhIHZhbGlkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LCBidXQgb3B0aW9uYWxseSB5b3UgY2FuIHVzZSB0aGUgY29uZmlndXJhdGlvbiBzZXJ2aWNlIHRvIHRvZ2dsZSBjb25maWdzIGJhc2VkIG9uIHRoZSBlbnZpcm9ubWVudFxuICpcbiAqIEBleGFtcGxlXG4gKiAgICAgdmFyIGNzID0gcmVxdWlyZSgnY29uZmlndXJhdGlvbi1zZXJ2aWNlJykoe1xuICogICAgICAgICAgZGV2OiB7IC8vZW52aXJvbm1lbnRcbiAgICAgICAgICAgICAgICBwb3J0OiAzMDAwLFxuICAgICAgICAgICAgICAgIGhvc3Q6ICdsb2NhbGhvc3QnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHByb2Q6IHtcbiAgICAgICAgICAgICAgICBwb3J0OiA4MDgwLFxuICAgICAgICAgICAgICAgIGhvc3Q6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgICAgICAgICBsb2dMZXZlbDogJ25vbmUnXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgbG9nTGV2ZWw6ICdERUJVRycgLy9nbG9iYWxcbiAqICAgICB9KTtcbiAqXG4gKiAgICAgIGNzLmdldCgnbG9nTGV2ZWwnKTsgLy9yZXR1cm5zICdERUJVRydcbiAqXG4gKiAgICAgIGNzLnNldEVudignZGV2Jyk7XG4gKiAgICAgIGNzLmdldCgnbG9nTGV2ZWwnKTsgLy9yZXR1cm5zICdERUJVRydcbiAqXG4gKiAgICAgIGNzLnNldEVudigncHJvZCcpO1xuICogICAgICBjcy5nZXQoJ2xvZ0xldmVsJyk7IC8vcmV0dXJucyAnbm9uZSdcbiAqXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xudmFyIHVybFNlcnZpY2UgPSByZXF1aXJlKCcuL3VybC1jb25maWctc2VydmljZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAvL1RPRE86IEVudmlyb25tZW50c1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgbG9nTGV2ZWw6ICdOT05FJ1xuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHNlcnZpY2VPcHRpb25zLnNlcnZlciA9IHVybFNlcnZpY2Uoc2VydmljZU9wdGlvbnMuc2VydmVyKTtcblxuICAgIHJldHVybiB7XG5cbiAgICAgICAgZGF0YTogc2VydmljZU9wdGlvbnMsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgZW52aXJvbm1lbnQga2V5IHRvIGdldCBjb25maWd1cmF0aW9uIG9wdGlvbnMgZnJvbVxuICAgICAgICAgKiBAcGFyYW0geyBzdHJpbmd9IGVudlxuICAgICAgICAgKi9cbiAgICAgICAgc2V0RW52OiBmdW5jdGlvbiAoZW52KSB7XG5cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd9IHByb3BlcnR5IG9wdGlvbmFsXG4gICAgICAgICAqIEByZXR1cm4geyp9ICAgICAgICAgIFZhbHVlIG9mIHByb3BlcnR5IGlmIHNwZWNpZmllZCwgdGhlIGVudGlyZSBjb25maWcgb2JqZWN0IG90aGVyd2lzZVxuICAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAocHJvcGVydHkpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9uc1twcm9wZXJ0eV07XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCBjb25maWd1cmF0aW9uLlxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5IGlmIGEga2V5IGlzIHByb3ZpZGVkLCBzZXQgYSBrZXkgdG8gdGhhdCB2YWx1ZS4gT3RoZXJ3aXNlIG1lcmdlIG9iamVjdCB3aXRoIGN1cnJlbnQgY29uZmlnXG4gICAgICAgICAqIEBwYXJhbSAgeyp9IHZhbHVlICB2YWx1ZSBmb3IgcHJvdmlkZWQga2V5XG4gICAgICAgICAqL1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9uc1trZXldID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9O1xufTtcblxuIiwiLyoqXG4gKiAjI0RhdGEgQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGUgRGF0YSBBUEkgU2VydmljZSBhbGxvd3MgeW91IHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgbWFuaXB1bGF0ZSBkYXRhIHJlbGF0ZWQgdG8gYW55IG9mIHlvdXIgcHJvamVjdHMuIERhdGEgYXJlIG9yZ2FuaXplZCBpbiBjb2xsZWN0aW9ucy4gRWFjaCBjb2xsZWN0aW9uIGNvbnRhaW5zIGEgZG9jdW1lbnQ7IGVhY2ggZWxlbWVudCBvZiB0aGlzIHRvcC1sZXZlbCBkb2N1bWVudCBpcyBhIEpTT04gb2JqZWN0LiAoU2VlIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24gb24gdGhlIHVuZGVybHlpbmcgW0RhdGEgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvZGF0YV9hcGkvKS4pXG4gKlxuICogQWxsIEFQSSBjYWxscyB0YWtlIGluIGFuIFwib3B0aW9uc1wiIG9iamVjdCBhcyB0aGUgbGFzdCBwYXJhbWV0ZXIuIFRoZSBvcHRpb25zIGNhbiBiZSB1c2VkIHRvIGV4dGVuZC9vdmVycmlkZSB0aGUgRGF0YSBBUEkgU2VydmljZSBkZWZhdWx0cy4gSW4gcGFydGljdWxhciwgdGhlcmUgYXJlIHRocmVlIHJlcXVpcmVkIHBhcmFtZXRlcnMgd2hlbiB5b3UgaW5zdGFudGlhdGUgdGhlIERhdGEgU2VydmljZTpcbiAqXG4gKiAqIGBhY2NvdW50YDogRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICogKiBgcHJvamVjdGA6IEVwaWNlbnRlciBwcm9qZWN0IGlkLlxuICogKiBgcm9vdGA6IFRoZSB0aGUgbmFtZSBvZiB0aGUgY29sbGVjdGlvbi4gSWYgeW91IGhhdmUgbXVsdGlwbGUgY29sbGVjdGlvbnMgd2l0aGluIGVhY2ggb2YgeW91ciBwcm9qZWN0cywgeW91IGNhbiBhbHNvIHBhc3MgdGhlIGNvbGxlY3Rpb24gbmFtZSBhcyBhbiBvcHRpb24gZm9yIGVhY2ggY2FsbC5cbiAqXG4gKiAgICAgICB2YXIgZHMgPSBuZXcgRi5zZXJ2aWNlLkRhdGEoe1xuICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgICAgIHJvb3Q6ICdzdXJ2ZXktcmVzcG9uc2VzJyxcbiAqICAgICAgICAgIHNlcnZlcjogeyBob3N0OiAnYXBpLmZvcmlvLmNvbScgfVxuICogICAgICAgfSk7XG4gKiAgICAgICBkcy5zYXZlQXMoJ3VzZXIxJyxcbiAqICAgICAgICAgIHsgJ3F1ZXN0aW9uMSc6IDIsICdxdWVzdGlvbjInOiAxMCxcbiAqICAgICAgICAgICdxdWVzdGlvbjMnOiBmYWxzZSwgJ3F1ZXN0aW9uNCc6ICdzb21ldGltZXMnIH0gKTtcbiAqICAgICAgIGRzLnNhdmVBcygndXNlcjInLFxuICogICAgICAgICAgeyAncXVlc3Rpb24xJzogMywgJ3F1ZXN0aW9uMic6IDgsXG4gKiAgICAgICAgICAncXVlc3Rpb24zJzogdHJ1ZSwgJ3F1ZXN0aW9uNCc6ICdhbHdheXMnIH0gKTtcbiAqICAgICAgIGRzLnF1ZXJ5KCcnLHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICpcbiAqIE5vdGUgdGhhdCBpbiBhZGRpdGlvbiB0byB0aGUgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgcm9vdGAsIHRoZSBEYXRhIFNlcnZpY2UgcGFyYW1ldGVycyBvcHRpb25hbGx5IGluY2x1ZGUgYSBgc2VydmVyYCBvYmplY3QsIHdob3NlIGBob3N0YCBmaWVsZCBjb250YWlucyB0aGUgVVJJIG9mIHRoZSBGb3JpbyBzZXJ2ZXIuIFRoaXMgaXMgYXV0b21hdGljYWxseSBzZXQsIGJ1dCB5b3UgY2FuIHBhc3MgaXQgZXhwbGljaXRseSBpZiBkZXNpcmVkLiBJdCBpcyBtb3N0IGNvbW1vbmx5IHVzZWQgZm9yIGNsYXJpdHkgd2hlbiB5b3UgYXJlIFtob3N0aW5nIGFuIEVwaWNlbnRlciBwcm9qZWN0IG9uIHlvdXIgb3duIHNlcnZlcl0oLi4vLi4vLi4vaG93X3RvL3NlbGZfaG9zdGluZy8pLlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBzdG9yZSA9IG5ldyBTdG9yYWdlRmFjdG9yeSh7IHN5bmNocm9ub3VzOiB0cnVlIH0pO1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogTmFtZSBvZiBjb2xsZWN0aW9uLiBEZWZhdWx0cyB0byBgL2AsIHRoYXQgaXMsIHRoZSByb290IGxldmVsIG9mIHlvdXIgcHJvamVjdCBhdCBgZm9yaW8uY29tL2FwcC95b3VyLWFjY291bnQtaWQveW91ci1wcm9qZWN0LWlkL2AuIFJlcXVpcmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcm9vdDogJy8nLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRm9yIG9wZXJhdGlvbnMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KCdlcGljZW50ZXIucHJvamVjdC50b2tlbicpIHx8ICcnLFxuXG4gICAgICAgIGRvbWFpbjogJ2ZvcmlvLmNvbScsXG5cbiAgICAgICAgLy9PcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBnZXRVUkwgPSBmdW5jdGlvbiAoa2V5LCByb290KSB7XG4gICAgICAgIGlmICghcm9vdCkge1xuICAgICAgICAgICAgcm9vdCA9IHNlcnZpY2VPcHRpb25zLnJvb3Q7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVybCA9IHVybENvbmZpZy5nZXRBUElQYXRoKCdkYXRhJykgKyBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKHJvb3QpO1xuICAgICAgICBpZiAoa2V5KSB7XG4gICAgICAgICAgICB1cmwrPSBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKGtleSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IGdldFVSTFxuICAgIH0pO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNlYXJjaCBmb3IgZGF0YSB3aXRoaW4gYSBjb2xsZWN0aW9uLlxuICAgICAgICAgKlxuICAgICAgICAgKiBTZWFyY2hpbmcgdXNpbmcgY29tcGFyaXNvbiBvciBsb2dpY2FsIG9wZXJhdG9ycyAoYXMgb3Bwb3NlZCB0byBleGFjdCBtYXRjaGVzKSByZXF1aXJlcyBNb25nb0RCIHN5bnRheC4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLyNzZWFyY2hpbmcpIGZvciBhZGRpdGlvbmFsIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRhdGEgYXNzb2NpYXRlZCB3aXRoIGRvY3VtZW50ICd1c2VyMSdcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgndXNlcjEnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBleGFjdCBtYXRjaGluZzpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvbiB3aGVyZSAncXVlc3Rpb24yJyBpcyA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IDl9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBjb21wYXJpc29uIG9wZXJhdG9yczpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjInIGlzIGdyZWF0ZXIgdGhhbiA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIGxvZ2ljYWwgb3BlcmF0b3JzOlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRvY3VtZW50cyBpbiBjb2xsZWN0aW9uXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgJ3F1ZXN0aW9uMicgaXMgbGVzcyB0aGFuIDEwLCBhbmQgJ3F1ZXN0aW9uMycgaXMgZmFsc2VcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgnJywgeyAnJGFuZCc6IFsgeyAncXVlc3Rpb24yJzogeyAnJGx0JzoxMH0gfSwgeyAncXVlc3Rpb24zJzogZmFsc2UgfV0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gcmVndWxhciBleHByZXNzc2lvbnM6IHVzZSBhbnkgUGVybC1jb21wYXRpYmxlIHJlZ3VsYXIgZXhwcmVzc2lvbnNcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjUnIGNvbnRhaW5zIHRoZSBzdHJpbmcgJy4qZGF5J1xuICAgICAgICAgKiAgICAgIGRzLnF1ZXJ5KCcnLCB7ICdxdWVzdGlvbjUnOiB7ICckcmVnZXgnOiAnLipkYXknIH0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBga2V5YCBUaGUgbmFtZSBvZiB0aGUgZG9jdW1lbnQgdG8gc2VhcmNoLiBQYXNzIHRoZSBlbXB0eSBzdHJpbmcgKCcnKSB0byBzZWFyY2ggdGhlIGVudGlyZSBjb2xsZWN0aW9uLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHF1ZXJ5YCBUaGUgcXVlcnkgb2JqZWN0LiBGb3IgZXhhY3QgbWF0Y2hpbmcsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCBmaWVsZCB2YWx1ZSB0byBtYXRjaC4gRm9yIG1hdGNoaW5nIGJhc2VkIG9uIGNvbXBhcmlzb24sIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCB0aGUgY29tcGFyaXNvbiBleHByZXNzaW9uLiBGb3IgbWF0Y2hpbmcgYmFzZWQgb24gbG9naWNhbCBvcGVyYXRvcnMsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIGFuIGV4cHJlc3Npb24gdXNpbmcgTW9uZ29EQiBzeW50YXguIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8jc2VhcmNoaW5nKSBmb3IgYWRkaXRpb25hbCBleGFtcGxlcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKlxuICAgICAgICAgKi9cbiAgICAgICAgcXVlcnk6IGZ1bmN0aW9uIChrZXksIHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgcTogcXVlcnkgfSwgb3V0cHV0TW9kaWZpZXIpO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGRhdGEgdG8gYW4gYW5vbnltb3VzIGRvY3VtZW50IHdpdGhpbiB0aGUgY29sbGVjdGlvbi5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmUoJ3F1ZXN0aW9uMScsICd5ZXMnKTtcbiAgICAgICAgICogICAgICBkcy5zYXZlKHtxdWVzdGlvbjE6J3llcycsIHF1ZXN0aW9uMjogMzIgfSk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZSh7IG5hbWU6J0pvaG4nLCBjbGFzc05hbWU6ICdDUzEwMScgfSwgeyByb290OiAnc3R1ZGVudHMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xPYmplY3R9IGBrZXlgIElmIGBrZXlgIGlzIGEgc3RyaW5nLCBpdCBpcyB0aGUgaWQgb2YgdGhlIGVsZW1lbnQgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJZiBga2V5YCBpcyBhbiBvYmplY3QsIHRoZSBvYmplY3QgaXMgdGhlIGRhdGEgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJbiBib3RoIGNhc2VzLCB0aGUgaWQgZm9yIHRoZSBkb2N1bWVudCBpcyBnZW5lcmF0ZWQgYXV0b21hdGljYWxseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGB2YWx1ZWAgKE9wdGlvbmFsKSBUaGUgZGF0YSB0byBzYXZlLiBJZiBga2V5YCBpcyBhIHN0cmluZywgdGhpcyBpcyB0aGUgdmFsdWUgdG8gc2F2ZS4gSWYgYGtleWAgaXMgYW4gb2JqZWN0LCB0aGUgdmFsdWUocykgdG8gc2F2ZSBhcmUgYWxyZWFkeSBwYXJ0IG9mIGBrZXlgIGFuZCB0aGlzIGFyZ3VtZW50IGlzIG5vdCByZXF1aXJlZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZTogZnVuY3Rpb24gKGtleSwgdmFsdWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBhdHRycztcbiAgICAgICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0ga2V5O1xuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSB2YWx1ZTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoJycsIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KGF0dHJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgZGF0YSB0byBhIG5hbWVkIGRvY3VtZW50IG9yIGVsZW1lbnQgd2l0aGluIHRoZSBjb2xsZWN0aW9uLiBUaGUgYHJvb3RgIG9mIHRoZSBjb2xsZWN0aW9uIG11c3QgYmUgc3BlY2lmaWVkIHNlcGFyYXRlbHkgaW4gY29uZmlndXJhdGlvbiBvcHRpb25zLCBlaXRoZXIgYXMgcGFydCBvZiB0aGUgY2FsbCBvciBhcyBwYXJ0IG9mIHRoZSBpbml0aWFsaXphdGlvbiBvZiBkcy5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmVBcygndXNlcjEnLFxuICAgICAgICAgKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAyLCAncXVlc3Rpb24yJzogMTAsXG4gICAgICAgICAqICAgICAgICAgICAncXVlc3Rpb24zJzogZmFsc2UsICdxdWVzdGlvbjQnOiAnc29tZXRpbWVzJyB9ICk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZUFzKCdzdHVkZW50MScsXG4gICAgICAgICAqICAgICAgICAgIHsgZmlyc3ROYW1lOiAnam9obicsIGxhc3ROYW1lOiAnc21pdGgnIH0sXG4gICAgICAgICAqICAgICAgICAgIHsgcm9vdDogJ3N0dWRlbnRzJyB9KTtcbiAgICAgICAgICogICAgICBkcy5zYXZlQXMoJ21nbXQxMDAvZ3JvdXBCJyxcbiAgICAgICAgICogICAgICAgICAgeyBzY2VuYXJpb1llYXI6ICcyMDE1JyB9LFxuICAgICAgICAgKiAgICAgICAgICB7IHJvb3Q6ICdteWNsYXNzZXMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYGtleWAgSWQgb2YgdGhlIGRvY3VtZW50LlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbHVlYCAoT3B0aW9uYWwpIFRoZSBkYXRhIHRvIHNhdmUsIGluIGtleTp2YWx1ZSBwYWlycy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZUFzOiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wdXQodmFsdWUsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGRhdGEgZm9yIGEgc3BlY2lmaWMgZG9jdW1lbnQgb3IgZmllbGQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgZHMubG9hZCgndXNlcjEnKTtcbiAgICAgICAgICogICAgICBkcy5sb2FkKCd1c2VyMS9xdWVzdGlvbjMnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYGtleWAgVGhlIGlkIG9mIHRoZSBkYXRhIHRvIHJldHVybi4gQ2FuIGJlIHRoZSBpZCBvZiBhIGRvY3VtZW50LCBvciBhIHBhdGggdG8gZGF0YSB3aXRoaW4gdGhhdCBkb2N1bWVudC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uIChrZXksIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMudXJsID0gZ2V0VVJMKGtleSwgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQob3V0cHV0TW9kaWZpZXIsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBkYXRhIGZyb20gY29sbGVjdGlvbi4gT25seSBkb2N1bWVudHMgKHRvcC1sZXZlbCBlbGVtZW50cyBpbiBlYWNoIGNvbGxlY3Rpb24pIGNhbiBiZSBkZWxldGVkLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgZHMucmVtb3ZlKCd1c2VyMScpO1xuICAgICAgICAgKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xBcnJheX0gYGtleXNgIFRoZSBpZCBvZiB0aGUgZG9jdW1lbnQgdG8gcmVtb3ZlIGZyb20gdGhpcyBjb2xsZWN0aW9uLCBvciBhbiBhcnJheSBvZiBzdWNoIGlkcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgcmVtb3ZlOiBmdW5jdGlvbiAoa2V5cywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBwYXJhbXM7XG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KGtleXMpKSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBpZDoga2V5cyB9O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSAnJztcbiAgICAgICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoa2V5cywgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUocGFyYW1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFcGljZW50ZXIgZG9lc24ndCBhbGxvdyBudWtpbmcgY29sbGVjdGlvbnNcbiAgICAgICAgLy8gICAgIC8qKlxuICAgICAgICAvLyAgICAgICogUmVtb3ZlcyBjb2xsZWN0aW9uIGJlaW5nIHJlZmVyZW5jZWRcbiAgICAgICAgLy8gICAgICAqIEByZXR1cm4gbnVsbFxuICAgICAgICAvLyAgICAgICovXG4gICAgICAgIC8vICAgICBkZXN0cm95OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvLyAgICAgICAgIHJldHVybiB0aGlzLnJlbW92ZSgnJywgb3B0aW9ucyk7XG4gICAgICAgIC8vICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKlxuICogIyNNZW1iZXIgQVBJIEFkYXB0ZXJcbiAqXG4gKiBUaGUgTWVtYmVyIEFQSSBBZGFwdGVyIHByb3ZpZGVzIG1ldGhvZHMgdG8gbG9vayB1cCBpbmZvcm1hdGlvbiBhYm91dCBlbmQgdXNlcnMgZm9yIHlvdXIgcHJvamVjdCBhbmQgaG93IHRoZXkgYXJlIGRpdmlkZWQgYWNyb3NzIGdyb3Vwcy4gSXQgaXMgYmFzZWQgb24gcXVlcnkgY2FwYWJpbGl0aWVzIG9mIHRoZSB1bmRlcmx5aW5nIFJFU1RmdWwgW01lbWJlciBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy91c2VyX21hbmFnZW1lbnQvbWVtYmVyLykuXG4gKlxuICogVGhpcyBpcyBvbmx5IG5lZWRlZCBmb3IgQXV0aGVudGljYXRlZCBwcm9qZWN0cywgdGhhdCBpcywgdGVhbSBwcm9qZWN0cyB3aXRoIFtlbmQgdXNlcnMgYW5kIGdyb3Vwc10oLi4vLi4vLi4vZ3JvdXBzX2FuZF9lbmRfdXNlcnMvKS4gRm9yIGV4YW1wbGUsIGlmIHNvbWUgb2YgeW91ciBlbmQgdXNlcnMgYXJlIGZhY2lsaXRhdG9ycywgb3IgaWYgeW91ciBlbmQgdXNlcnMgc2hvdWxkIGJlIHRyZWF0ZWQgZGlmZmVyZW50bHkgYmFzZWQgb24gd2hpY2ggZ3JvdXAgdGhleSBhcmUgaW4sIHVzZSB0aGUgTWVtYmVyIEFQSSB0byBmaW5kIHRoYXQgaW5mb3JtYXRpb24uXG4gKlxuICogICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gKiAgICAgIG1hLmdldEdyb3Vwc0ZvclVzZXIoeyB1c2VySWQ6ICdiNmIzMTNhMy1hYjg0LTQ3OWMtYmFlYS0yMDZmNmJmZjMzNycgfSk7XG4gKiAgICAgIG1hLmdldEdyb3VwRGV0YWlscyh7IGdyb3VwSWQ6ICcwMGI1MzMwOC05ODMzLTQ3ZjItYjIxZS0xMjc4YzA3ZDUzYjgnIH0pO1xuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIGFwaUVuZHBvaW50ID0gJ21lbWJlci9sb2NhbCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciB1c2VyIGlkLiBEZWZhdWx0cyB0byBhIGJsYW5rIHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciBncm91cCBpZC4gRGVmYXVsdHMgdG8gYSBibGFuayBzdHJpbmcuIE5vdGUgdGhhdCB0aGlzIGlzIHRoZSBncm91cCAqaWQqLCBub3QgdGhlIGdyb3VwICpuYW1lKi5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGdyb3VwSWQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucywgc2VydmljZU9wdGlvbnMpO1xuXG4gICAgdmFyIGdldEZpbmFsUGFyYW1zID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICAgICAgICBpZiAodHlwZW9mIHBhcmFtcyA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnM7XG4gICAgfTtcblxuICAgIHZhciBwYXRjaFVzZXJBY3RpdmVGaWVsZCA9IGZ1bmN0aW9uIChwYXJhbXMsIGFjdGl2ZSwgb3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBwYXJhbXMuZ3JvdXBJZCArICcvJyArIHBhcmFtcy51c2VySWRcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goeyBhY3RpdmU6IGFjdGl2ZSB9LCBodHRwT3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBhbGwgb2YgdGhlIGdyb3VwIG1lbWJlcnNoaXBzIGZvciBvbmUgZW5kIHVzZXIuIFRoZSBtZW1iZXJzaGlwIGRldGFpbHMgYXJlIHJldHVybmVkIGluIGFuIGFycmF5LCB3aXRoIG9uZSBlbGVtZW50IChncm91cCByZWNvcmQpIGZvciBlYWNoIGdyb3VwIHRvIHdoaWNoIHRoZSBlbmQgdXNlciBiZWxvbmdzLlxuICAgICAgICAqXG4gICAgICAgICogSW4gdGhlIG1lbWJlcnNoaXAgYXJyYXksIGVhY2ggZ3JvdXAgcmVjb3JkIGluY2x1ZGVzIHRoZSBncm91cCBpZCwgcHJvamVjdCBpZCwgYWNjb3VudCAodGVhbSkgaWQsIGFuZCBhbiBhcnJheSBvZiBtZW1iZXJzLiBIb3dldmVyLCBvbmx5IHRoZSB1c2VyIHdob3NlIHVzZXJJZCBpcyBpbmNsdWRlZCBpbiB0aGUgY2FsbCBpcyBsaXN0ZWQgaW4gdGhlIG1lbWJlcnMgYXJyYXkgKHJlZ2FyZGxlc3Mgb2Ygd2hldGhlciB0aGVyZSBhcmUgb3RoZXIgbWVtYmVycyBpbiB0aGlzIGdyb3VwKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcignNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24obWVtYmVyc2hpcHMpe1xuICAgICAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpPG1lbWJlcnNoaXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2cobWVtYmVyc2hpcHNbaV0uZ3JvdXBJZCk7XG4gICAgICAgICogICAgICAgICAgICAgICB9XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcih7IHVzZXJJZDogJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdH0gYHBhcmFtc2AgVGhlIHVzZXIgaWQgZm9yIHRoZSBlbmQgdXNlci4gQWx0ZXJuYXRpdmVseSwgYW4gb2JqZWN0IHdpdGggZmllbGQgYHVzZXJJZGAgYW5kIHZhbHVlIHRoZSB1c2VyIGlkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXRHcm91cHNGb3JVc2VyOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKHBhcmFtcyk7XG4gICAgICAgICAgICBpZiAoIWlzU3RyaW5nICYmICFvYmpQYXJhbXMudXNlcklkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyB1c2VySWQgc3BlY2lmaWVkLicpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZ2V0UGFybXMgPSBpc1N0cmluZyA/IHsgdXNlcklkOiBwYXJhbXMgfSA6IF9waWNrKG9ialBhcmFtcywgJ3VzZXJJZCcpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGdldFBhcm1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBvbmUgZ3JvdXAsIGluY2x1ZGluZyBhbiBhcnJheSBvZiBhbGwgaXRzIG1lbWJlcnMuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLmdldEdyb3VwRGV0YWlscygnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oZ3JvdXApe1xuICAgICAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpPGdyb3VwLm1lbWJlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhncm91cC5tZW1iZXJzW2ldLnVzZXJOYW1lKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIH1cbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBtYS5nZXRHcm91cERldGFpbHMoeyBncm91cElkOiAnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd8b2JqZWN0fSBgcGFyYW1zYCBUaGUgZ3JvdXAgaWQuIEFsdGVybmF0aXZlbHksIGFuIG9iamVjdCB3aXRoIGZpZWxkIGBncm91cElkYCBhbmQgdmFsdWUgdGhlIGdyb3VwIGlkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0R3JvdXBEZXRhaWxzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKHBhcmFtcyk7XG4gICAgICAgICAgICBpZiAoIWlzU3RyaW5nICYmICFvYmpQYXJhbXMuZ3JvdXBJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gZ3JvdXBJZCBzcGVjaWZpZWQuJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBncm91cElkID0gaXNTdHJpbmcgPyBwYXJhbXMgOiBvYmpQYXJhbXMuZ3JvdXBJZDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIGdyb3VwSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogU2V0IGEgcGFydGljdWxhciBlbmQgdXNlciBhcyBgYWN0aXZlYC4gQWN0aXZlIGVuZCB1c2VycyBjYW4gYmUgYXNzaWduZWQgdG8gW3dvcmxkc10oLi4vd29ybGQtbWFuYWdlci8pIGluIG11bHRpcGxheWVyIGdhbWVzIGR1cmluZyBhdXRvbWF0aWMgYXNzaWdubWVudC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEubWFrZVVzZXJBY3RpdmUoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBUaGUgZW5kIHVzZXIgYW5kIGdyb3VwIGluZm9ybWF0aW9uLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnVzZXJJZGAgVGhlIGlkIG9mIHRoZSBlbmQgdXNlciB0byBtYWtlIGFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5ncm91cElkYCBUaGUgaWQgb2YgdGhlIGdyb3VwIHRvIHdoaWNoIHRoaXMgZW5kIHVzZXIgYmVsb25ncywgYW5kIGluIHdoaWNoIHRoZSBlbmQgdXNlciBzaG91bGQgYmVjb21lIGFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIG1ha2VVc2VyQWN0aXZlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcGF0Y2hVc2VyQWN0aXZlRmllbGQocGFyYW1zLCB0cnVlLCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBTZXQgYSBwYXJ0aWN1bGFyIGVuZCB1c2VyIGFzIGBpbmFjdGl2ZWAuIEluYWN0aXZlIGVuZCB1c2VycyBhcmUgbm90IGFzc2lnbmVkIHRvIFt3b3JsZHNdKC4uL3dvcmxkLW1hbmFnZXIvKSBpbiBtdWx0aXBsYXllciBnYW1lcyBkdXJpbmcgYXV0b21hdGljIGFzc2lnbm1lbnQuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLm1ha2VVc2VySW5hY3RpdmUoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBUaGUgZW5kIHVzZXIgYW5kIGdyb3VwIGluZm9ybWF0aW9uLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnVzZXJJZGAgVGhlIGlkIG9mIHRoZSBlbmQgdXNlciB0byBtYWtlIGluYWN0aXZlLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmdyb3VwSWRgIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggdGhpcyBlbmQgdXNlciBiZWxvbmdzLCBhbmQgaW4gd2hpY2ggdGhlIGVuZCB1c2VyIHNob3VsZCBiZWNvbWUgaW5hY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBtYWtlVXNlckluYWN0aXZlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcGF0Y2hVc2VyQWN0aXZlRmllbGQocGFyYW1zLCBmYWxzZSwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjI1J1biBBUEkgU2VydmljZVxuICpcbiAqIFRoZSBSdW4gQVBJIFNlcnZpY2UgYWxsb3dzIHlvdSB0byBwZXJmb3JtIGNvbW1vbiB0YXNrcyBhcm91bmQgY3JlYXRpbmcgYW5kIHVwZGF0aW5nIHJ1bnMsIHZhcmlhYmxlcywgYW5kIGRhdGEuXG4gKlxuICogV2hlbiBidWlsZGluZyBpbnRlcmZhY2VzIHRvIHNob3cgcnVuIG9uZSBhdCBhIHRpbWUgKGFzIGZvciBzdGFuZGFyZCBlbmQgdXNlcnMpLCB0eXBpY2FsbHkgeW91IGZpcnN0IGluc3RhbnRpYXRlIGEgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGFuZCB0aGVuIGFjY2VzcyB0aGUgUnVuIFNlcnZpY2UgdGhhdCBpcyBhdXRvbWF0aWNhbGx5IHBhcnQgb2YgdGhlIG1hbmFnZXIsIHJhdGhlciB0aGFuIGluc3RhbnRpYXRpbmcgdGhlIFJ1biBTZXJ2aWNlIGRpcmVjdGx5LiBUaGlzIGlzIGJlY2F1c2UgdGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBjb250cm9sIG92ZXIgcnVuIGNyZWF0aW9uIGRlcGVuZGluZyBvbiBydW4gc3RhdGVzLlxuICpcbiAqIEhvd2V2ZXIsIG1hbnkgb2YgdGhlIEVwaWNlbnRlciBzYW1wbGUgcHJvamVjdHMgdXNlIGEgUnVuIFNlcnZpY2UsIGJlY2F1c2UgZ2VuZXJhbGx5IHRoZSBzYW1wbGUgcHJvamVjdHMgYXJlIHBsYXllZCBpbiBvbmUgZW5kIHVzZXIgc2Vzc2lvbiBhbmQgZG9uJ3QgY2FyZSBhYm91dCBydW4gc3RhdGVzIG9yIFtydW4gc3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKS4gVGhlIFJ1biBBUEkgU2VydmljZSBpcyBhbHNvIHVzZWZ1bCBmb3IgYnVpbGRpbmcgYW4gaW50ZXJmYWNlIGZvciBhIGZhY2lsaXRhdG9yLCBiZWNhdXNlIGl0IG1ha2VzIGl0IGVhc3kgdG8gbGlzdCBkYXRhIGFjcm9zcyBtdWx0aXBsZSBydW5zICh1c2luZyB0aGUgYGZpbHRlcigpYCBhbmQgYHF1ZXJ5KClgIG1ldGhvZHMpLlxuICpcbiAqIFRvIHVzZSB0aGUgUnVuIEFQSSBTZXJ2aWNlLCBpbnN0YW50aWF0ZSBpdCBieSBwYXNzaW5nIGluOlxuICpcbiAqICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gKiAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4gKlxuICogRm9yIGV4YW1wbGUsXG4gKlxuICogICAgICAgdmFyIHJzID0gbmV3IEYuc2VydmljZS5SdW4oe1xuICogICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgIH0pO1xuICogICAgICBycy5jcmVhdGUoJ3N1cHBseV9jaGFpbl9nYW1lLnB5JykudGhlbihmdW5jdGlvbihydW4pIHtcbiAqICAgICAgICAgICAgIHJzLmRvKCdzb21lT3BlcmF0aW9uJyk7XG4gKiAgICAgIH0pO1xuICpcbiAqXG4gKiBBZGRpdGlvbmFsbHksIGFsbCBBUEkgY2FsbHMgdGFrZSBpbiBhbiBcIm9wdGlvbnNcIiBvYmplY3QgYXMgdGhlIGxhc3QgcGFyYW1ldGVyLiBUaGUgb3B0aW9ucyBjYW4gYmUgdXNlZCB0byBleHRlbmQvb3ZlcnJpZGUgdGhlIFJ1biBBUEkgU2VydmljZSBkZWZhdWx0cyBsaXN0ZWQgYmVsb3cuXG4gKlxuICogTm90ZSB0aGF0IGluIGFkZGl0aW9uIHRvIHRoZSBgYWNjb3VudGAsIGBwcm9qZWN0YCwgYW5kIGBtb2RlbGAsIHRoZSBSdW4gU2VydmljZSBwYXJhbWV0ZXJzIG9wdGlvbmFsbHkgaW5jbHVkZSBhIGBzZXJ2ZXJgIG9iamVjdCwgd2hvc2UgYGhvc3RgIGZpZWxkIGNvbnRhaW5zIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4gKlxuICogICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiAqICAgICAgICAgICBydW46IHtcbiAqICAgICAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgICAgICBtb2RlbDogJ3N1cHBseV9jaGFpbl9nYW1lLnB5JyxcbiAqICAgICAgICAgICAgICAgc2VydmVyOiB7IGhvc3Q6ICdhcGkuZm9yaW8uY29tJyB9XG4gKiAgICAgICAgICAgfVxuICogICAgICAgfSk7XG4gKiAgICAgICBybS5nZXRSdW4oKVxuICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1bikge1xuICogICAgICAgICAgICAgICAvLyB0aGUgUnVuTWFuYWdlci5ydW4gY29udGFpbnMgdGhlIGluc3RhbnRpYXRlZCBSdW4gU2VydmljZSxcbiAqICAgICAgICAgICAgICAgLy8gc28gYW55IFJ1biBTZXJ2aWNlIG1ldGhvZCBpcyB2YWxpZCBoZXJlXG4gKiAgICAgICAgICAgICAgIHZhciBycyA9IHJtLnJ1bjtcbiAqICAgICAgICAgICAgICAgcnMuZG8oJ3NvbWVPcGVyYXRpb24nKTtcbiAqICAgICAgIH0pXG4gKlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgcnV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3J1bi11dGlsJyk7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgVmFyaWFibGVzU2VydmljZSA9IHJlcXVpcmUoJy4vdmFyaWFibGVzLWFwaS1zZXJ2aWNlJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIC8vIGNvbmZpZyB8fCAoY29uZmlnID0gY29uZmlnU2VydmljZS5nZXQoKSk7XG4gICAgdmFyIHN0b3JlID0gbmV3IFN0b3JhZ2VGYWN0b3J5KHsgc3luY2hyb25vdXM6IHRydWUgfSk7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogc3RvcmUuZ2V0KCdlcGljZW50ZXIucHJvamVjdC50b2tlbicpIHx8IHN0b3JlLmdldCgnZXBpY2VudGVyLnRva2VuJykgfHwgJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDcml0ZXJpYSBieSB3aGljaCB0byBmaWx0ZXIgcnVucy4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZmlsdGVyOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVuaWVuY2UgYWxpYXMgZm9yIGZpbHRlci5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGlkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRmxhZyBkZXRlcm1pbmVzIGlmIGBYLUF1dG9SZXN0b3JlOiB0cnVlYCBoZWFkZXIgaXMgc2VudCB0byBFcGljZW50ZXIuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBhdXRvUmVzdG9yZTogdHJ1ZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgY29tcGxldGVzIHN1Y2Nlc3NmdWxseS4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIHN1Y2Nlc3M6ICQubm9vcCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgZmFpbHMuIERlZmF1bHRzIHRvIGAkLm5vb3BgLlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICBlcnJvcjogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgdXJsQ29uZmlnLmFjY291bnRQYXRoID0gc2VydmljZU9wdGlvbnMuYWNjb3VudDtcbiAgICB9XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgdXJsQ29uZmlnLnByb2plY3RQYXRoID0gc2VydmljZU9wdGlvbnMucHJvamVjdDtcbiAgICB9XG5cbiAgICB1cmxDb25maWcuZmlsdGVyID0gJzsnO1xuICAgIHVybENvbmZpZy5nZXRGaWx0ZXJVUkwgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJyk7XG4gICAgICAgIHZhciBmaWx0ZXIgPSBxdXRpbC50b01hdHJpeEZvcm1hdChzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpO1xuXG4gICAgICAgIGlmIChmaWx0ZXIpIHtcbiAgICAgICAgICAgIHVybCArPSBmaWx0ZXIgKyAnLyc7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGZpbHRlciA9IHNlcnZpY2VPcHRpb25zLmZpbHRlcjtcbiAgICAgICAgLy8gVGhlIHNlbWljb2xvbiBzZXBhcmF0ZWQgZmlsdGVyIGlzIHVzZWQgd2hlbiBmaWx0ZXIgaXMgYW4gb2JqZWN0XG4gICAgICAgIHZhciBpc0ZpbHRlclJ1bklkID0gZmlsdGVyICYmICQudHlwZShmaWx0ZXIpID09PSAnc3RyaW5nJztcbiAgICAgICAgaWYgKHNlcnZpY2VPcHRpb25zLmF1dG9SZXN0b3JlICYmIGlzRmlsdGVyUnVuSWQpIHtcbiAgICAgICAgICAgIC8vIEJ5IGRlZmF1bHQgYXV0b3JlcGxheSB0aGUgcnVuIGJ5IHNlbmRpbmcgdGhpcyBoZWFkZXIgdG8gZXBpY2VudGVyXG4gICAgICAgICAgICAvLyBodHRwczovL2ZvcmlvLmNvbS9lcGljZW50ZXIvZG9jcy9wdWJsaWMvcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNyZXRyaWV2aW5nXG4gICAgICAgICAgICB2YXIgYXV0b3Jlc3RvcmVPcHRzID0ge1xuICAgICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICAgICAgJ1gtQXV0b1Jlc3RvcmUnOiB0cnVlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCBhdXRvcmVzdG9yZU9wdHMsIG9wdGlvbnMpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG9wdGlvbnM7XG4gICAgfTtcblxuICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0RmlsdGVyVVJMXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG4gICAgaHR0cC5zcGxpdEdldCA9IHJ1dGlsLnNwbGl0R2V0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgc2V0RmlsdGVyT3JUaHJvd0Vycm9yID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMuaWQpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IG9wdGlvbnMuaWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmZpbHRlcjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBmaWx0ZXIgc3BlY2lmaWVkIHRvIGFwcGx5IG9wZXJhdGlvbnMgYWdhaW5zdCcpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBc3luY0FQSSA9IHtcbiAgICAgICAgdXJsQ29uZmlnOiB1cmxDb25maWcsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENyZWF0ZSBhIG5ldyBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqIE5PVEU6IFR5cGljYWxseSB0aGlzIGlzIG5vdCB1c2VkISBVc2UgYFJ1bk1hbmFnZXIuZ2V0UnVuKClgIHdpdGggYSBgc3RyYXRlZ3lgIG9mIGBhbHdheXMtbmV3YCwgb3IgdXNlIGBSdW5NYW5hZ2VyLnJlc2V0KClgLiBTZWUgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGZvciBtb3JlIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHJzLmNyZWF0ZSgnaGVsbG9fd29ybGQuamwnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYHBhcmFtc2AgSWYgYSBzdHJpbmcsIHRoZSBuYW1lIG9mIHRoZSBwcmltYXJ5IFttb2RlbCBmaWxlXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4gVGhpcyBpcyB0aGUgb25lIGZpbGUgaW4gdGhlIHByb2plY3QgdGhhdCBleHBsaWNpdGx5IGV4cG9zZXMgdmFyaWFibGVzIGFuZCBtZXRob2RzLCBhbmQgaXQgbXVzdCBiZSBzdG9yZWQgaW4gdGhlIE1vZGVsIGZvbGRlciBvZiB5b3VyIEVwaWNlbnRlciBwcm9qZWN0LiBJZiBhbiBvYmplY3QsIG1heSBpbmNsdWRlIGBtb2RlbGAsIGBzY29wZWAsIGFuZCBgZmlsZXNgLiAoU2VlIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bl9tYW5hZ2VyLykgZm9yIG1vcmUgaW5mb3JtYXRpb24gb24gYHNjb3BlYCBhbmQgYGZpbGVzYC4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICpcbiAgICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJykgfSk7XG4gICAgICAgICAgICB2YXIgcnVuQXBpUGFyYW1zID0gWydtb2RlbCcsICdzY29wZScsICdmaWxlcyddO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgLy8gdGhpcyBpcyBqdXN0IHRoZSBtb2RlbCBuYW1lXG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBtb2RlbDogcGFyYW1zIH07XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIHdoaXRlbGlzdCB0aGUgZmllbGRzIHRoYXQgd2UgYWN0dWFsbHkgY2FuIHNlbmQgdG8gdGhlIGFwaVxuICAgICAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgcnVuQXBpUGFyYW1zKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBjcmVhdGVPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgICAgICBjcmVhdGVPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSByZXNwb25zZS5pZDsgLy9hbGwgZnV0dXJlIGNoYWluZWQgY2FsbHMgdG8gb3BlcmF0ZSBvbiB0aGlzIGlkXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHJ1bnMsIGJhc2VkIG9uIGNvbmRpdGlvbnMgc3BlY2lmaWVkIGluIHRoZSBgcXNgIG9iamVjdC5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGVsZW1lbnRzIG9mIHRoZSBgcXNgIG9iamVjdCBhcmUgQU5EZWQgdG9nZXRoZXIgd2l0aGluIGEgc2luZ2xlIGNhbGwgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyByZXR1cm5zIHJ1bnMgd2l0aCBzYXZlZCA9IHRydWUgYW5kIHZhcmlhYmxlcy5wcmljZSA+IDEsXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgdmFyaWFibGVzLnByaWNlIGhhcyBiZWVuIHBlcnNpc3RlZCAocmVjb3JkZWQpXG4gICAgICAgICAqICAgICAgLy8gaW4gdGhlIG1vZGVsLlxuICAgICAgICAgKiAgICAgcnMucXVlcnkoe1xuICAgICAgICAgKiAgICAgICAgICAnc2F2ZWQnOiAndHJ1ZScsXG4gICAgICAgICAqICAgICAgICAgICcucHJpY2UnOiAnPjEnXG4gICAgICAgICAqICAgICAgIH0sXG4gICAgICAgICAqICAgICAgIHtcbiAgICAgICAgICogICAgICAgICAgc3RhcnRyZWNvcmQ6IDIsXG4gICAgICAgICAqICAgICAgICAgIGVuZHJlY29yZDogNVxuICAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBxc2AgUXVlcnkgb2JqZWN0LiBFYWNoIGtleSBjYW4gYmUgYSBwcm9wZXJ0eSBvZiB0aGUgcnVuIG9yIHRoZSBuYW1lIG9mIHZhcmlhYmxlIHRoYXQgaGFzIGJlZW4gc2F2ZWQgaW4gdGhlIHJ1biAocHJlZmFjZWQgYnkgYHZhcmlhYmxlcy5gKS4gRWFjaCB2YWx1ZSBjYW4gYmUgYSBsaXRlcmFsIHZhbHVlLCBvciBhIGNvbXBhcmlzb24gb3BlcmF0b3IgYW5kIHZhbHVlLiAoU2VlIFttb3JlIG9uIGZpbHRlcmluZ10oLi4vLi4vLi4vcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNmaWx0ZXJzKSBhbGxvd2VkIGluIHRoZSB1bmRlcmx5aW5nIFJ1biBBUEkuKSBRdWVyeWluZyBmb3IgdmFyaWFibGVzIGlzIGF2YWlsYWJsZSBmb3IgcnVucyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBhbmQgZm9yIHJ1bnMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgaWYgdGhlIHZhcmlhYmxlcyBhcmUgcGVyc2lzdGVkIChlLmcuIHRoYXQgaGF2ZSBiZWVuIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHF1ZXJ5OiBmdW5jdGlvbiAocXMsIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBxczsgLy9zaG91bGRuJ3QgYmUgYWJsZSB0byBvdmVyLXJpZGVcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucyA9IHVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlcihodHRwT3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJldHVybnMgcGFydGljdWxhciBydW5zLCBiYXNlZCBvbiBjb25kaXRpb25zIHNwZWNpZmllZCBpbiB0aGUgYHFzYCBvYmplY3QuXG4gICAgICAgICAqXG4gICAgICAgICAqIFNpbWlsYXIgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBmaWx0ZXJgIEZpbHRlciBvYmplY3QuIEVhY2gga2V5IGNhbiBiZSBhIHByb3BlcnR5IG9mIHRoZSBydW4gb3IgdGhlIG5hbWUgb2YgdmFyaWFibGUgdGhhdCBoYXMgYmVlbiBzYXZlZCBpbiB0aGUgcnVuIChwcmVmYWNlZCBieSBgdmFyaWFibGVzLmApLiBFYWNoIHZhbHVlIGNhbiBiZSBhIGxpdGVyYWwgdmFsdWUsIG9yIGEgY29tcGFyaXNvbiBvcGVyYXRvciBhbmQgdmFsdWUuIChTZWUgW21vcmUgb24gZmlsdGVyaW5nXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkvI2ZpbHRlcnMpIGFsbG93ZWQgaW4gdGhlIHVuZGVybHlpbmcgUnVuIEFQSS4pIEZpbHRlcmluZyBmb3IgdmFyaWFibGVzIGlzIGF2YWlsYWJsZSBmb3IgcnVucyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBhbmQgZm9yIHJ1bnMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgaWYgdGhlIHZhcmlhYmxlcyBhcmUgcGVyc2lzdGVkIChlLmcuIHRoYXQgaGF2ZSBiZWVuIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogZnVuY3Rpb24gKGZpbHRlciwgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qoc2VydmljZU9wdGlvbnMuZmlsdGVyKSkge1xuICAgICAgICAgICAgICAgICQuZXh0ZW5kKHNlcnZpY2VPcHRpb25zLmZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gZmlsdGVyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBkYXRhIGZvciBhIHNwZWNpZmljIHJ1bi4gVGhpcyBpbmNsdWRlcyBzdGFuZGFyZCBydW4gZGF0YSBzdWNoIGFzIHRoZSBhY2NvdW50LCBtb2RlbCwgcHJvamVjdCwgYW5kIGNyZWF0ZWQgYW5kIGxhc3QgbW9kaWZpZWQgZGF0ZXMuIFRvIHJlcXVlc3Qgc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLCBwYXNzIHRoZW0gYXMgcGFydCBvZiB0aGUgYGZpbHRlcnNgIHBhcmFtZXRlci5cbiAgICAgICAgICpcbiAgICAgICAgICogTm90ZSB0aGF0IGlmIHRoZSBydW4gaXMgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSksIGFueSBtb2RlbCB2YXJpYWJsZXMgYXJlIGF2YWlsYWJsZTsgaWYgdGhlIHJ1biBpcyBbaW4gdGhlIGRhdGFiYXNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tZGIpLCBvbmx5IG1vZGVsIHZhcmlhYmxlcyB0aGF0IGhhdmUgYmVlbiBwZXJzaXN0ZWQgJm1kYXNoOyB0aGF0IGlzLCBgcmVjb3JkYGVkIGluIHlvdXIgSnVsaWEgbW9kZWwgJm1kYXNoOyBhcmUgYXZhaWxhYmxlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgcnMubG9hZCgnYmI1ODk2NzctZDQ3Ni00OTcxLWE2OGUtMGM1OGQxOTFlNDUwJywgeyBpbmNsdWRlOiBbJy5wcmljZScsICcuc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGBydW5JRGAgVGhlIHJ1biBpZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBmaWx0ZXJzYCAoT3B0aW9uYWwpIE9iamVjdCBjb250YWluaW5nIGZpbHRlcnMgYW5kIG9wZXJhdGlvbiBtb2RpZmllcnMuIFVzZSBrZXkgYGluY2x1ZGVgIHRvIGxpc3QgbW9kZWwgdmFyaWFibGVzIHRoYXQgeW91IHdhbnQgdG8gaW5jbHVkZSBpbiB0aGUgcmVzcG9uc2UuIE90aGVyIGF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAocnVuSUQsIGZpbHRlcnMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmIChydW5JRCkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHJ1bklEOyAvL3Nob3VsZG4ndCBiZSBhYmxlIHRvIG92ZXItcmlkZVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cblxuICAgICAgICAvKipcbiAgICAgICAgICogU2F2ZSBhdHRyaWJ1dGVzIChkYXRhLCBtb2RlbCB2YXJpYWJsZXMpIG9mIHRoZSBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgLy8gYWRkICdjb21wbGV0ZWQnIGZpZWxkIHRvIHJ1biByZWNvcmRcbiAgICAgICAgICogICAgIHJzLnNhdmUoeyBjb21wbGV0ZWQ6IHRydWUgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAvLyB1cGRhdGUgJ3NhdmVkJyBmaWVsZCBvZiBydW4gcmVjb3JkLCBhbmQgdXBkYXRlIHZhbHVlcyBvZiBtb2RlbCB2YXJpYWJsZXMgZm9yIHRoaXMgcnVuXG4gICAgICAgICAqICAgICBycy5zYXZlKHsgc2F2ZWQ6IHRydWUsIHZhcmlhYmxlczogeyBhOiAyMywgYjogMjMgfSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBhdHRyaWJ1dGVzYCBUaGUgcnVuIGRhdGEgYW5kIHZhcmlhYmxlcyB0byBzYXZlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYGF0dHJpYnV0ZXMudmFyaWFibGVzYCBNb2RlbCB2YXJpYWJsZXMgbXVzdCBiZSBpbmNsdWRlZCBpbiBhIGB2YXJpYWJsZXNgIGZpZWxkIHdpdGhpbiB0aGUgYGF0dHJpYnV0ZXNgIG9iamVjdC4gKE90aGVyd2lzZSB0aGV5IGFyZSB0cmVhdGVkIGFzIHJ1biBkYXRhIGFuZCBhZGRlZCB0byB0aGUgcnVuIHJlY29yZCBkaXJlY3RseS4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uIChhdHRyaWJ1dGVzLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgc2V0RmlsdGVyT3JUaHJvd0Vycm9yKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKGF0dHJpYnV0ZXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBhIG1ldGhvZCBmcm9tIHRoZSBtb2RlbC5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2QgbWF5IG5lZWQgdG8gYmUgZXhwb3NlZCAoZS5nLiBgZXhwb3J0YCBmb3IgYSBKdWxpYSBtb2RlbCkgaW4gdGhlIG1vZGVsIGZpbGUgaW4gb3JkZXIgdG8gYmUgY2FsbGVkIHRocm91Z2ggdGhlIEFQSS4gU2VlIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pKS5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGBwYXJhbXNgIGFyZ3VtZW50IGlzIG5vcm1hbGx5IGFuIGFycmF5IG9mIGFyZ3VtZW50cyB0byB0aGUgYG9wZXJhdGlvbmAuIEluIHRoZSBzcGVjaWFsIGNhc2Ugd2hlcmUgYG9wZXJhdGlvbmAgb25seSB0YWtlcyBvbmUgYXJndW1lbnQsIHlvdSBhcmUgbm90IHJlcXVpcmVkIHRvIHB1dCB0aGF0IGFyZ3VtZW50IGludG8gYW4gYXJyYXkuXG4gICAgICAgICAqXG4gICAgICAgICAqIE5vdGUgdGhhdCB5b3UgY2FuIGNvbWJpbmUgdGhlIGBvcGVyYXRpb25gIGFuZCBgcGFyYW1zYCBhcmd1bWVudHMgaW50byBhIHNpbmdsZSBvYmplY3QgaWYgeW91IHByZWZlciwgYXMgaW4gdGhlIGxhc3QgZXhhbXBsZS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlcyoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwic29sdmVcIiB0YWtlcyBubyBhcmd1bWVudHNcbiAgICAgICAgICogICAgIHJzLmRvKCdzb2x2ZScpO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImVjaG9cIiB0YWtlcyBvbmUgYXJndW1lbnQsIGEgc3RyaW5nXG4gICAgICAgICAqICAgICBycy5kbygnZWNobycsIFsnaGVsbG8nXSk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwiZWNob1wiIHRha2VzIG9uZSBhcmd1bWVudCwgYSBzdHJpbmdcbiAgICAgICAgICogICAgIHJzLmRvKCdlY2hvJywgJ2hlbGxvJyk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwic3VtQXJyYXlcIiB0YWtlcyBvbmUgYXJndW1lbnQsIGFuIGFycmF5XG4gICAgICAgICAqICAgICBycy5kbygnc3VtQXJyYXknLCBbWzQsMiwxXV0pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImFkZFwiIHRha2VzIHR3byBhcmd1bWVudHMsIGJvdGggaW50ZWdlcnNcbiAgICAgICAgICogICAgIHJzLmRvKHsgbmFtZTonYWRkJywgcGFyYW1zOlsyLDRdIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYG9wZXJhdGlvbmAgTmFtZSBvZiBtZXRob2QuXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGBwYXJhbXNgIChPcHRpb25hbCkgQW55IHBhcmFtZXRlcnMgdGhlIG9wZXJhdGlvbiB0YWtlcywgcGFzc2VkIGFzIGFuIGFycmF5LiBJbiB0aGUgc3BlY2lhbCBjYXNlIHdoZXJlIGBvcGVyYXRpb25gIG9ubHkgdGFrZXMgb25lIGFyZ3VtZW50LCB5b3UgYXJlIG5vdCByZXF1aXJlZCB0byBwdXQgdGhhdCBhcmd1bWVudCBpbnRvIGFuIGFycmF5LCBhbmQgY2FuIGp1c3QgcGFzcyBpdCBkaXJlY3RseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgZG86IGZ1bmN0aW9uIChvcGVyYXRpb24sIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coJ2RvJywgb3BlcmF0aW9uLCBwYXJhbXMpO1xuICAgICAgICAgICAgdmFyIG9wc0FyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnM7XG4gICAgICAgICAgICBpZiAob3B0aW9ucykge1xuICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMgPSBvcHRpb25zO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHBhcmFtcykpIHtcbiAgICAgICAgICAgICAgICAgICAgb3BzQXJncyA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zID0gcGFyYW1zO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9uLCBvcHNBcmdzKTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgcG9zdE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBzZXRGaWx0ZXJPclRocm93RXJyb3IoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcHJtcyA9IChyZXN1bHQuYXJnc1swXS5sZW5ndGggJiYgKHJlc3VsdC5hcmdzWzBdICE9PSBudWxsICYmIHJlc3VsdC5hcmdzWzBdICE9PSB1bmRlZmluZWQpKSA/IHJlc3VsdC5hcmdzWzBdIDogW107XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHsgYXJndW1lbnRzOiBwcm1zIH0sICQuZXh0ZW5kKHRydWUsIHt9LCBodHRwT3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ29wZXJhdGlvbnMvJyArIHJlc3VsdC5vcHNbMF0gKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBzZXZlcmFsIG1ldGhvZHMgZnJvbSB0aGUgbW9kZWwsIHNlcXVlbnRpYWxseS5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2RzIG1heSBuZWVkIHRvIGJlIGV4cG9zZWQgKGUuZy4gYGV4cG9ydGAgZm9yIGEgSnVsaWEgbW9kZWwpIGluIHRoZSBtb2RlbCBmaWxlIGluIG9yZGVyIHRvIGJlIGNhbGxlZCB0aHJvdWdoIHRoZSBBUEkuIFNlZSBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKSkuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJpbml0aWFsaXplXCIgYW5kIFwic29sdmVcIiBkbyBub3QgdGFrZSBhbnkgYXJndW1lbnRzXG4gICAgICAgICAqICAgICBycy5zZXJpYWwoWydpbml0aWFsaXplJywgJ3NvbHZlJ10pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJpbml0XCIgYW5kIFwicmVzZXRcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMuc2VyaWFsKFsgIHsgbmFtZTogJ2luaXQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgeyBuYW1lOiAncmVzZXQnLCBwYXJhbXM6IFsyLDNdIH1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJpbml0XCIgdGFrZXMgdHdvIGFyZ3VtZW50cyxcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJydW5tb2RlbFwiIHRha2VzIG5vbmVcbiAgICAgICAgICogICAgIHJzLnNlcmlhbChbICB7IG5hbWU6ICdpbml0JywgcGFyYW1zOiBbMSwyXSB9LFxuICAgICAgICAgKiAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3J1bm1vZGVsJywgcGFyYW1zOiBbXSB9XSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGBvcGVyYXRpb25zYCBJZiBub25lIG9mIHRoZSBtZXRob2RzIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiB0aGUgbWV0aG9kIG5hbWVzIChzdHJpbmdzKS4gSWYgYW55IG9mIHRoZSBtZXRob2RzIGRvIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiBvYmplY3RzLCBlYWNoIG9mIHdoaWNoIGNvbnRhaW5zIGEgbWV0aG9kIG5hbWUgYW5kIGl0cyBvd24gKHBvc3NpYmx5IGVtcHR5KSBhcnJheSBvZiBwYXJhbWV0ZXJzLlxuICAgICAgICAgKiBAcGFyYW0geyp9IGBwYXJhbXNgIFBhcmFtZXRlcnMgdG8gcGFzcyB0byBvcGVyYXRpb25zLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBzZXJpYWw6IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBvcFBhcmFtcyA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHMgPSBvcFBhcmFtcy5vcHM7XG4gICAgICAgICAgICB2YXIgYXJncyA9IG9wUGFyYW1zLmFyZ3M7XG4gICAgICAgICAgICB2YXIgbWUgPSB0aGlzO1xuXG4gICAgICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZG9TaW5nbGVPcCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB2YXIgb3AgPSBvcHMuc2hpZnQoKTtcbiAgICAgICAgICAgICAgICB2YXIgYXJnID0gYXJncy5zaGlmdCgpO1xuXG4gICAgICAgICAgICAgICAgbWUuZG8ob3AsIGFyZywge1xuICAgICAgICAgICAgICAgICAgICBzdWNjZXNzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAob3BzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvU2luZ2xlT3AoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zLnN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICRkLnJlamVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuZXJyb3IuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgZG9TaW5nbGVPcCgpO1xuXG4gICAgICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsIHNldmVyYWwgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbCwgZXhlY3V0aW5nIHRoZW0gaW4gcGFyYWxsZWwuXG4gICAgICAgICAqXG4gICAgICAgICAqIERlcGVuZGluZyBvbiB0aGUgbGFuZ3VhZ2UgaW4gd2hpY2ggeW91IGhhdmUgd3JpdHRlbiB5b3VyIG1vZGVsLCB0aGUgbWV0aG9kcyBtYXkgbmVlZCB0byBiZSBleHBvc2VkIChlLmcuIGBleHBvcnRgIGZvciBhIEp1bGlhIG1vZGVsKSBpbiB0aGUgbW9kZWwgZmlsZSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdGhyb3VnaCB0aGUgQVBJLiBTZWUgW1dyaXRpbmcgeW91ciBNb2RlbF0oLi4vLi4vLi4vd3JpdGluZ195b3VyX21vZGVsLykpLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJzb2x2ZVwiIGFuZCBcInJlc2V0XCIgZG8gbm90IHRha2UgYW55IGFyZ3VtZW50c1xuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoWydzb2x2ZScsICdyZXNldCddKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiYWRkXCIgYW5kIFwic3VidHJhY3RcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoWyB7IG5hbWU6ICdhZGQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3N1YnRyYWN0JywgcGFyYW1zOlsyLDNdIH1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiYWRkXCIgYW5kIFwic3VidHJhY3RcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoeyBhZGQ6IFsxLDJdLCBzdWJ0cmFjdDogWzIsNF0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fSBgb3BlcmF0aW9uc2AgSWYgbm9uZSBvZiB0aGUgbWV0aG9kcyB0YWtlIHBhcmFtZXRlcnMsIHBhc3MgYW4gYXJyYXkgb2YgdGhlIG1ldGhvZCBuYW1lcyAoYXMgc3RyaW5ncykuIElmIGFueSBvZiB0aGUgbWV0aG9kcyBkbyB0YWtlIHBhcmFtZXRlcnMsIHlvdSBoYXZlIHR3byBvcHRpb25zLiBZb3UgY2FuIHBhc3MgYW4gYXJyYXkgb2Ygb2JqZWN0cywgZWFjaCBvZiB3aGljaCBjb250YWlucyBhIG1ldGhvZCBuYW1lIGFuZCBpdHMgb3duIChwb3NzaWJseSBlbXB0eSkgYXJyYXkgb2YgcGFyYW1ldGVycy4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBwYXNzIGEgc2luZ2xlIG9iamVjdCB3aXRoIHRoZSBtZXRob2QgbmFtZSBhbmQgYSAocG9zc2libHkgZW1wdHkpIGFycmF5IG9mIHBhcmFtZXRlcnMuXG4gICAgICAgICAqIEBwYXJhbSB7Kn0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBwYXNzIHRvIG9wZXJhdGlvbnMuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHBhcmFsbGVsOiBmdW5jdGlvbiAob3BlcmF0aW9ucywgcGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG5cbiAgICAgICAgICAgIHZhciBvcFBhcmFtcyA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHMgPSBvcFBhcmFtcy5vcHM7XG4gICAgICAgICAgICB2YXIgYXJncyA9IG9wUGFyYW1zLmFyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcXVldWUgID0gW107XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaTwgb3BzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgcXVldWUucHVzaChcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kbyhvcHNbaV0sIGFyZ3NbaV0pXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgICQud2hlbi5hcHBseSh0aGlzLCBxdWV1ZSlcbiAgICAgICAgICAgICAgICAuZG9uZShmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlc29sdmUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuc3VjY2Vzcy5hcHBseSh0aGlzLmFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZmFpbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlamVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucy5lcnJvci5hcHBseSh0aGlzLmFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY1N5bmNBUEkgPSB7XG4gICAgICAgIGdldEN1cnJlbnRDb25maWc6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucztcbiAgICAgICAgfSxcbiAgICAgICAgLyoqXG4gICAgICAgICAgKiBSZXR1cm5zIGEgVmFyaWFibGVzIFNlcnZpY2UgaW5zdGFuY2UuIFVzZSB0aGUgdmFyaWFibGVzIGluc3RhbmNlIHRvIGxvYWQsIHNhdmUsIGFuZCBxdWVyeSBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLiBTZWUgdGhlIFtWYXJpYWJsZSBBUEkgU2VydmljZV0oLi4vdmFyaWFibGVzLWFwaS1zZXJ2aWNlLykgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG4gICAgICAgICAgKlxuICAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAgICAgIHZhciB2cyA9IHJzLnZhcmlhYmxlcygpO1xuICAgICAgICAgICogICAgICB2cy5zYXZlKHsgc2FtcGxlX2ludDogNCB9KTtcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBjb25maWdgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAgKi9cbiAgICAgICAgdmFyaWFibGVzOiBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICAgICAgICB2YXIgdnMgPSBuZXcgVmFyaWFibGVzU2VydmljZSgkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIGNvbmZpZywge1xuICAgICAgICAgICAgICAgIHJ1blNlcnZpY2U6IHRoaXNcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgIHJldHVybiB2cztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBc3luY0FQSSk7XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljU3luY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4gKiAjI1N0YXRlIEFQSSBBZGFwdGVyXG4gKlxuICogVGhlIFN0YXRlIEFQSSBBZGFwdGVyIGFsbG93cyB5b3UgdG8gcmVwbGF5IG9yIGNsb25lIHJ1bnMuIEl0IGJyaW5ncyBleGlzdGluZywgcGVyc2lzdGVkIHJ1biBkYXRhIGZyb20gdGhlIGRhdGFiYXNlIGJhY2sgaW50byBtZW1vcnksIHVzaW5nIHRoZSBzYW1lIHJ1biBpZCAoYHJlcGxheWApIG9yIGEgbmV3IHJ1biBpZCAoYGNsb25lYCkuIFJ1bnMgbXVzdCBiZSBpbiBtZW1vcnkgaW4gb3JkZXIgZm9yIHlvdSB0byB1cGRhdGUgdmFyaWFibGVzIG9yIGNhbGwgb3BlcmF0aW9ucyBvbiB0aGVtLlxuICpcbiAqIFNwZWNpZmljYWxseSwgdGhlIFN0YXRlIEFQSSBBZGFwdGVyIHdvcmtzIGJ5IFwicmUtcnVubmluZ1wiIHRoZSBydW4gKHVzZXIgaW50ZXJhY3Rpb25zKSBmcm9tIHRoZSBjcmVhdGlvbiBvZiB0aGUgcnVuIHVwIHRvIHRoZSB0aW1lIGl0IHdhcyBsYXN0IHBlcnNpc3RlZCBpbiB0aGUgZGF0YWJhc2UuIFRoaXMgcHJvY2VzcyB1c2VzIHRoZSBjdXJyZW50IHZlcnNpb24gb2YgdGhlIHJ1bidzIG1vZGVsLiBUaGVyZWZvcmUsIGlmIHRoZSBtb2RlbCBoYXMgY2hhbmdlZCBzaW5jZSB0aGUgb3JpZ2luYWwgcnVuIHdhcyBjcmVhdGVkLCB0aGUgcmV0cmlldmVkIHJ1biB3aWxsIHVzZSB0aGUgbmV3IG1vZGVsIOKAlCBhbmQgbWF5IGVuZCB1cCBoYXZpbmcgZGlmZmVyZW50IHZhbHVlcyBvciBiZWhhdmlvciBhcyBhIHJlc3VsdC4gVXNlIHdpdGggY2FyZSFcbiAqXG4gKiBUbyB1c2UgdGhlIFN0YXRlIEFQSSBBZGFwdGVyLCBpbnN0YW50aWF0ZSBpdCBhbmQgdGhlbiBjYWxsIGl0cyBtZXRob2RzOlxuICpcbiAqICAgICAgdmFyIHNhID0gbmV3IEYuc2VydmljZS5TdGF0ZSgpO1xuICogICAgICBzYS5yZXBsYXkoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJ30pO1xuICpcbiAqIFRoZSBjb25zdHJ1Y3RvciB0YWtlcyBhbiBvcHRpb25hbCBgb3B0aW9uc2AgcGFyYW1ldGVyIGluIHdoaWNoIHlvdSBjYW4gc3BlY2lmeSB0aGUgYGFjY291bnRgIGFuZCBgcHJvamVjdGAgaWYgdGhleSBhcmUgbm90IGFscmVhZHkgYXZhaWxhYmxlIGluIHRoZSBjdXJyZW50IGNvbnRleHQuXG4gKlxuICovXG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBhcGlFbmRwb2ludCA9ICdtb2RlbC9zdGF0ZSc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgfTtcblxuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcbiAgICB2YXIgcGFyc2VSdW5JZE9yRXJyb3IgPSBmdW5jdGlvbiAocGFyYW1zKSB7XG4gICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3QocGFyYW1zKSAmJiBwYXJhbXMucnVuSWQpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXJhbXMucnVuSWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwYXNzIGluIGEgcnVuIGlkJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICogUmVwbGF5IGEgcnVuLiBBZnRlciB0aGlzIGNhbGwsIHRoZSBydW4sIHdpdGggaXRzIG9yaWdpbmFsIHJ1biBpZCwgaXMgbm93IGF2YWlsYWJsZSBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KS4gKEl0IGNvbnRpbnVlcyB0byBiZSBwZXJzaXN0ZWQgaW50byB0aGUgRXBpY2VudGVyIGRhdGFiYXNlIGF0IHJlZ3VsYXIgaW50ZXJ2YWxzLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gICAgICAgICogICAgICBzYS5yZXBsYXkoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJywgc3RvcEJlZm9yZTogJ2NhbGN1bGF0ZVNjb3JlJ30pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFBhcmFtZXRlcnMgb2JqZWN0LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnJ1bklkYCBUaGUgaWQgb2YgdGhlIHJ1biB0byBicmluZyBiYWNrIHRvIG1lbW9yeS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5zdG9wQmVmb3JlYCAoT3B0aW9uYWwpIFRoZSBydW4gaXMgYWR2YW5jZWQgb25seSB1cCB0byB0aGUgZmlyc3Qgb2NjdXJyZW5jZSBvZiB0aGlzIG1ldGhvZC5cbiAgICAgICAgKiBAcGFyYW0ge2FycmF5fSBgcGFyYW1zLmV4Y2x1ZGVgIChPcHRpb25hbCkgQXJyYXkgb2YgbWV0aG9kcyB0byBleGNsdWRlIHdoZW4gYWR2YW5jaW5nIHRoZSBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICByZXBsYXk6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBydW5JZCA9IHBhcnNlUnVuSWRPckVycm9yKHBhcmFtcyk7XG5cbiAgICAgICAgICAgIHZhciByZXBsYXlPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcnVuSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gJC5leHRlbmQodHJ1ZSwgeyBhY3Rpb246ICdyZXBsYXknIH0sIF9waWNrKHBhcmFtcywgWydzdG9wQmVmb3JlJywgJ2V4Y2x1ZGUnXSkpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgcmVwbGF5T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ2xvbmUgYSBnaXZlbiBydW4gYW5kIHJldHVybiBhIG5ldyBydW4gaW4gdGhlIHNhbWUgc3RhdGUgYXMgdGhlIGdpdmVuIHJ1bi5cbiAgICAgICAgKlxuICAgICAgICAqIFRoZSBuZXcgcnVuIGlkIGlzIG5vdyBhdmFpbGFibGUgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkuIFRoZSBuZXcgcnVuIGluY2x1ZGVzIGEgY29weSBvZiBhbGwgb2YgdGhlIGRhdGEgZnJvbSB0aGUgb3JpZ2luYWwgcnVuLCBFWENFUFQ6XG4gICAgICAgICpcbiAgICAgICAgKiAqIFRoZSBgc2F2ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyBub3QgY29waWVkIGZyb20gdGhlIG9yaWdpbmFsIHJ1biByZWNvcmQuIEl0IGRlZmF1bHRzIHRvIGBmYWxzZWAuXG4gICAgICAgICogKiBUaGUgYGluaXRpYWxpemVkYCBmaWVsZCBpbiB0aGUgbmV3IHJ1biByZWNvcmQgaXMgbm90IGNvcGllZCBmcm9tIHRoZSBvcmlnaW5hbCBydW4gcmVjb3JkLiBJdCBkZWZhdWx0cyB0byBgZmFsc2VgIGJ1dCBtYXkgY2hhbmdlIHRvIGB0cnVlYCBhcyB0aGUgbmV3IHJ1biBpcyBhZHZhbmNlZC4gRm9yIGV4YW1wbGUsIGlmIHRoZXJlIGhhcyBiZWVuIGEgY2FsbCB0byB0aGUgYHN0ZXBgIGZ1bmN0aW9uIChmb3IgVmVuc2ltIG1vZGVscyksIHRoZSBgaW5pdGlhbGl6ZWRgIGZpZWxkIGlzIHNldCB0byBgdHJ1ZWAuXG4gICAgICAgICogKiBUaGUgYGNyZWF0ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyB0aGUgZGF0ZSBhbmQgdGltZSBhdCB3aGljaCB0aGUgY2xvbmUgd2FzIGNyZWF0ZWQgKG5vdCB0aGUgdGltZSB0aGF0IHRoZSBvcmlnaW5hbCBydW4gd2FzIGNyZWF0ZWQuKVxuICAgICAgICAqXG4gICAgICAgICogVGhlIG9yaWdpbmFsIHJ1biByZW1haW5zIG9ubHkgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLWRiKS5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gICAgICAgICogICAgICBzYS5jbG9uZSh7cnVuSWQ6ICcxODQyYmI1Yy04M2FkLTRiYTgtYTk1NS1iZDEzY2MyZmRiNGYnLCBzdG9wQmVmb3JlOiAnY2FsY3VsYXRlU2NvcmUnLCBleGNsdWRlOiBbJ2ludGVyaW1DYWxjdWxhdGlvbiddIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFBhcmFtZXRlcnMgb2JqZWN0LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnJ1bklkYCBUaGUgaWQgb2YgdGhlIHJ1biB0byBjbG9uZSBmcm9tIG1lbW9yeS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5zdG9wQmVmb3JlYCAoT3B0aW9uYWwpIFRoZSBuZXdseSBjbG9uZWQgcnVuIGlzIGFkdmFuY2VkIG9ubHkgdXAgdG8gdGhlIGZpcnN0IG9jY3VycmVuY2Ugb2YgdGhpcyBtZXRob2QuXG4gICAgICAgICogQHBhcmFtIHthcnJheX0gYHBhcmFtcy5leGNsdWRlYCAoT3B0aW9uYWwpIEFycmF5IG9mIG1ldGhvZHMgdG8gZXhjbHVkZSB3aGVuIGFkdmFuY2luZyB0aGUgbmV3bHkgY2xvbmVkIHJ1bi5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGNsb25lOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcnVuSWQgPSBwYXJzZVJ1bklkT3JFcnJvcihwYXJhbXMpO1xuXG4gICAgICAgICAgICB2YXIgcmVwbGF5T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHJ1bklkIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgYWN0aW9uOiAnY2xvbmUnIH0sIF9waWNrKHBhcmFtcywgWydzdG9wQmVmb3JlJywgJ2V4Y2x1ZGUnXSkpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgcmVwbGF5T3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBlcGlWZXJzaW9uID0gcmVxdWlyZSgnLi4vYXBpLXZlcnNpb24uanNvbicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAvL1RPRE86IHVybHV0aWxzIHRvIGdldCBob3N0LCBzaW5jZSBubyB3aW5kb3cgb24gbm9kZVxuXG4gICAgdmFyIEFQSV9QUk9UT0NPTCA9ICdodHRwcyc7XG4gICAgdmFyIEhPU1RfQVBJX01BUFBJTkcgPSB7XG4gICAgICAgICdmb3Jpby5jb20nOiAnYXBpLmZvcmlvLmNvbScsXG4gICAgICAgICdmb3Jpb2Rldi5jb20nOiAnYXBpLmVwaWNlbnRlci5mb3Jpb2Rldi5jb20nXG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNFeHBvcnRzID0ge1xuICAgICAgICBwcm90b2NvbDogQVBJX1BST1RPQ09MLFxuXG4gICAgICAgIGFwaTogJycsXG5cbiAgICAgICAgaG9zdDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBob3N0ID0gd2luZG93LmxvY2F0aW9uLmhvc3Q7XG4gICAgICAgICAgICBpZiAoIWhvc3QgfHwgaG9zdC5pbmRleE9mKCdsb2NhbCcpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIGhvc3QgPSAnZm9yaW8uY29tJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAoSE9TVF9BUElfTUFQUElOR1tob3N0XSkgPyBIT1NUX0FQSV9NQVBQSU5HW2hvc3RdIDogJ2FwaS4nICsgaG9zdDtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBhcHBQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHBhdGggPSB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUuc3BsaXQoJ1xcLycpO1xuXG4gICAgICAgICAgICByZXR1cm4gcGF0aCAmJiBwYXRoWzFdIHx8ICcnO1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIGFjY291bnRQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFjY250ID0gJyc7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZS5zcGxpdCgnXFwvJyk7XG4gICAgICAgICAgICBpZiAocGF0aCAmJiBwYXRoWzFdID09PSAnYXBwJykge1xuICAgICAgICAgICAgICAgIGFjY250ID0gcGF0aFsyXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhY2NudDtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBwcm9qZWN0UGF0aDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBwcmogPSAnJztcbiAgICAgICAgICAgIHZhciBwYXRoID0gd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLnNwbGl0KCdcXC8nKTtcbiAgICAgICAgICAgIGlmIChwYXRoICYmIHBhdGhbMV0gPT09ICdhcHAnKSB7XG4gICAgICAgICAgICAgICAgcHJqID0gcGF0aFszXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBwcmo7XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgdmVyc2lvblBhdGg6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgdmVyc2lvbiA9IGVwaVZlcnNpb24udmVyc2lvbiA/IGVwaVZlcnNpb24udmVyc2lvbiArICcvJyA6ICcnO1xuICAgICAgICAgICAgcmV0dXJuIHZlcnNpb247XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgaXNMb2NhbGhvc3Q6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBob3N0ID0gd2luZG93LmxvY2F0aW9uLmhvc3Q7XG4gICAgICAgICAgICByZXR1cm4gKCFob3N0IHx8IGhvc3QuaW5kZXhPZignbG9jYWwnKSAhPT0gLTEpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGdldEFQSVBhdGg6IGZ1bmN0aW9uIChhcGkpIHtcbiAgICAgICAgICAgIHZhciBQUk9KRUNUX0FQSVMgPSBbJ3J1bicsICdkYXRhJywgJ2ZpbGUnXTtcblxuICAgICAgICAgICAgdmFyIGFwaVBhdGggPSB0aGlzLnByb3RvY29sICsgJzovLycgKyB0aGlzLmhvc3QgKyAnLycgKyB0aGlzLnZlcnNpb25QYXRoICsgYXBpICsgJy8nO1xuXG4gICAgICAgICAgICBpZiAoJC5pbkFycmF5KGFwaSwgUFJPSkVDVF9BUElTKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICBhcGlQYXRoICs9IHRoaXMuYWNjb3VudFBhdGggKyAnLycgKyB0aGlzLnByb2plY3RQYXRoICArICcvJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhcGlQYXRoO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHB1YmxpY0V4cG9ydHMsIGNvbmZpZyk7XG4gICAgcmV0dXJuIHB1YmxpY0V4cG9ydHM7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4qICMjVXNlciBBUEkgQWRhcHRlclxuKlxuKiBUaGUgVXNlciBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHJldHJpZXZlIGRldGFpbHMgYWJvdXQgZW5kIHVzZXJzIGluIHlvdXIgdGVhbSAoYWNjb3VudCkuIEl0IGlzIGJhc2VkIG9uIHRoZSBxdWVyeWluZyBjYXBhYmlsaXRpZXMgb2YgdGhlIHVuZGVybHlpbmcgUkVTVGZ1bCBbVXNlciBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy91c2VyX21hbmFnZW1lbnQvdXNlci8pLlxuKlxuKiBUbyB1c2UgdGhlIFVzZXIgQVBJIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGNhbGwgaXRzIG1ldGhvZHMuXG4qXG4qICAgICAgIHZhciB1YSA9IG5ldyBGLnNlcnZpY2UuVXNlcih7XG4qICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgICB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nXG4qICAgICAgIH0pO1xuKiAgICAgICB1YS5nZXRCeUlkKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKTtcbiogICAgICAgdWEuZ2V0KHsgdXNlck5hbWU6ICdqc21pdGgnIH0pO1xuKiAgICAgICB1YS5nZXQoeyBpZDogWyc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuKiAgICAgICAgICAgICAgICAgICAnNGVhNzU2MzEtNGM4ZC00ODcyLTlkODAtYjQ2MDAxNDY0NzhlJ10gfSk7XG4qXG4qIFRoZSBjb25zdHJ1Y3RvciB0YWtlcyBhbiBvcHRpb25hbCBgb3B0aW9uc2AgcGFyYW1ldGVyIGluIHdoaWNoIHlvdSBjYW4gc3BlY2lmeSB0aGUgYGFjY291bnRgIGFuZCBgdG9rZW5gIGlmIHRoZXkgYXJlIG5vdCBhbHJlYWR5IGF2YWlsYWJsZSBpbiB0aGUgY3VycmVudCBjb250ZXh0LlxuKi9cblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2Nlc3MgdG9rZW4gdG8gdXNlIHdoZW4gc2VhcmNoaW5nIGZvciBlbmQgdXNlcnMuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgdG9rZW46ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgcGFydGljdWxhciBlbmQgdXNlcnMgaW4geW91ciB0ZWFtLCBiYXNlZCBvbiB1c2VyIG5hbWUgb3IgdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXQoeyB1c2VyTmFtZTogJ2pzbWl0aCcgfSk7XG4gICAgICAgICogICAgICAgdWEuZ2V0KHsgaWQ6IFsnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAnNGVhNzU2MzEtNGM4ZC00ODcyLTlkODAtYjQ2MDAxNDY0NzhlJ10gfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgZmlsdGVyYCBPYmplY3Qgd2l0aCBmaWVsZCBgdXNlck5hbWVgIGFuZCB2YWx1ZSBvZiB0aGUgdXNlcm5hbWUuIEFsdGVybmF0aXZlbHksIG9iamVjdCB3aXRoIGZpZWxkIGBpZGAgYW5kIHZhbHVlIG9mIGFuIGFycmF5IG9mIHVzZXIgaWRzLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChmaWx0ZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICAgICAgZmlsdGVyID0gZmlsdGVyIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnNcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciB0b1FGaWx0ZXIgPSBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJlcyA9IHt9O1xuXG4gICAgICAgICAgICAgICAgLy8gQVBJIG9ubHkgc3VwcG9ydHMgZmlsdGVyaW5nIGJ5IHVzZXJuYW1lIGZvciBub3dcbiAgICAgICAgICAgICAgICBpZiAoZmlsdGVyLnVzZXJOYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlcy5xID0gZmlsdGVyLnVzZXJOYW1lO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgdG9JZEZpbHRlcnMgPSBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZCA9ICQuaXNBcnJheShpZCkgPyBpZCA6IFtpZF07XG4gICAgICAgICAgICAgICAgcmV0dXJuICdpZD0nICsgaWQuam9pbignJmlkPScpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIGdldEZpbHRlcnMgPSBbXG4gICAgICAgICAgICAgICAgJ2FjY291bnQ9JyArIGdldE9wdGlvbnMuYWNjb3VudCxcbiAgICAgICAgICAgICAgICB0b0lkRmlsdGVycyhmaWx0ZXIuaWQpLFxuICAgICAgICAgICAgICAgIHF1dGlsLnRvUXVlcnlGb3JtYXQodG9RRmlsdGVyKGZpbHRlcikpXG4gICAgICAgICAgICBdLmpvaW4oJyYnKTtcblxuICAgICAgICAgICAgLy8gc3BlY2lhbCBjYXNlIGZvciBxdWVyaWVzIHdpdGggbGFyZ2UgbnVtYmVyIG9mIGlkc1xuICAgICAgICAgICAgLy8gbWFrZSBpdCBhcyBhIHBvc3Qgd2l0aCBHRVQgc2VtYW50aWNzXG4gICAgICAgICAgICB2YXIgdGhyZXNob2xkID0gMzA7XG4gICAgICAgICAgICBpZiAoZmlsdGVyLmlkICYmICQuaXNBcnJheShmaWx0ZXIuaWQpICYmIGZpbHRlci5pZC5sZW5ndGggPj0gdGhyZXNob2xkKSB7XG4gICAgICAgICAgICAgICAgZ2V0T3B0aW9ucy51cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpICsgJz9fbWV0aG9kPUdFVCc7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdCh7IGlkOiBmaWx0ZXIuaWQgfSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChnZXRGaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXRyaWV2ZSBkZXRhaWxzIGFib3V0IGEgc2luZ2xlIGVuZCB1c2VyIGluIHlvdXIgdGVhbSwgYmFzZWQgb24gdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXRCeUlkKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSB1c2VyIGlkIGZvciB0aGUgZW5kIHVzZXIgaW4geW91ciB0ZWFtLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXRCeUlkOiBmdW5jdGlvbiAodXNlcklkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcHVibGljQVBJLmdldCh7IGlkOiB1c2VySWQgfSwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG5cblxuXG5cbiIsIi8qKlxuICpcbiAqICMjVmFyaWFibGVzIEFQSSBTZXJ2aWNlXG4gKlxuICogVXNlZCBpbiBjb25qdW5jdGlvbiB3aXRoIHRoZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSB0byByZWFkLCB3cml0ZSwgYW5kIHNlYXJjaCBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLlxuICpcbiAqICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuICogICAgICAgICAgIHJ1bjoge1xuICogICAgICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5LWNoYWluLW1vZGVsLmpsJ1xuICogICAgICAgICAgIH1cbiAqICAgICAgfSk7XG4gKiAgICAgcm0uZ2V0UnVuKClcbiAqICAgICAgIC50aGVuKGZ1bmN0aW9uKCkge1xuICogICAgICAgICAgdmFyIHZzID0gcm0ucnVuLnZhcmlhYmxlcygpO1xuICogICAgICAgICAgdnMuc2F2ZSh7c2FtcGxlX2ludDogNH0pO1xuICogICAgICAgIH0pO1xuICpcbiAqL1xuXG5cbiAndXNlIHN0cmljdCc7XG5cbiB2YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG4gdmFyIHJ1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9ydW4tdXRpbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcnVucyBvYmplY3QgdG8gd2hpY2ggdGhlIHZhcmlhYmxlIGZpbHRlcnMgYXBwbHkuIERlZmF1bHRzIHRvIG51bGwuXG4gICAgICAgICAqIEB0eXBlIHtydW5TZXJ2aWNlfVxuICAgICAgICAgKi9cbiAgICAgICAgcnVuU2VydmljZTogbnVsbFxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIGdldFVSTCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zLnJ1blNlcnZpY2UudXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ3ZhcmlhYmxlcy8nO1xuICAgIH07XG5cbiAgICB2YXIgYWRkQXV0b1Jlc3RvcmVIZWFkZXIgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnMucnVuU2VydmljZS51cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIob3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBodHRwT3B0aW9ucyA9IHtcbiAgICAgICAgdXJsOiBnZXRVUkxcbiAgICB9O1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcbiAgICBodHRwLnNwbGl0R2V0ID0gcnV0aWwuc3BsaXRHZXRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCB2YWx1ZXMgZm9yIGEgdmFyaWFibGUuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMubG9hZCgnc2FtcGxlX2ludCcpXG4gICAgICAgICAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHZhbCl7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgY29udGFpbnMgdGhlIHZhbHVlIG9mIHNhbXBsZV9pbnRcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgdmFyaWFibGVgIE5hbWUgb2YgdmFyaWFibGUgdG8gbG9hZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9hZDogZnVuY3Rpb24gKHZhcmlhYmxlLCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KG91dHB1dE1vZGlmaWVyLCAkLmV4dGVuZCh7fSwgaHR0cE9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IGdldFVSTCgpICsgdmFyaWFibGUgKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHZhcmlhYmxlcywgYmFzZWQgb24gY29uZGl0aW9ucyBzcGVjaWZpZWQgaW4gdGhlIGBxdWVyeWAgb2JqZWN0LlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHZzLnF1ZXJ5KFsncHJpY2UnLCAnc2FsZXMnXSlcbiAgICAgICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24odmFsKSB7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgaXMgYW4gb2JqZWN0IHdpdGggdGhlIHZhbHVlcyBvZiB0aGUgcmVxdWVzdGVkIHZhcmlhYmxlczogdmFsLnByaWNlLCB2YWwuc2FsZXNcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMucXVlcnkoeyBpbmNsdWRlOlsncHJpY2UnLCAnc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8QXJyYXl9IGBxdWVyeWAgVGhlIG5hbWVzIG9mIHRoZSB2YXJpYWJsZXMgcmVxdWVzdGVkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG91dHB1dE1vZGlmaWVyYCAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqXG4gICAgICAgICAqL1xuICAgICAgICBxdWVyeTogZnVuY3Rpb24gKHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgLy9RdWVyeSBhbmQgb3V0cHV0TW9kaWZpZXIgYXJlIGJvdGggcXVlcnlzdHJpbmdzIGluIHRoZSB1cmw7IG9ubHkgY2FsbGluZyB0aGVtIG91dCBzZXBhcmF0ZWx5IGhlcmUgdG8gYmUgY29uc2lzdGVudCB3aXRoIHRoZSBvdGhlciBjYWxsc1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KHF1ZXJ5KSkge1xuICAgICAgICAgICAgICAgIHF1ZXJ5ID0geyBpbmNsdWRlOiBxdWVyeSB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgJC5leHRlbmQocXVlcnksIG91dHB1dE1vZGlmaWVyKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KHF1ZXJ5LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgdmFsdWVzIHRvIG1vZGVsIHZhcmlhYmxlcy4gT3ZlcndyaXRlcyBleGlzdGluZyB2YWx1ZXMuIE5vdGUgdGhhdCB5b3UgY2FuIG9ubHkgdXBkYXRlIG1vZGVsIHZhcmlhYmxlcyBpZiB0aGUgcnVuIGlzIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLiAoQW4gYWx0ZXJuYXRlIHdheSB0byB1cGRhdGUgbW9kZWwgdmFyaWFibGVzIGlzIHRvIGNhbGwgYSBtZXRob2QgZnJvbSB0aGUgbW9kZWwgYW5kIG1ha2Ugc3VyZSB0aGF0IHRoZSBtZXRob2QgcGVyc2lzdHMgdGhlIHZhcmlhYmxlcy4gU2VlIGBkb2AsIGBzZXJpYWxgLCBhbmQgYHBhcmFsbGVsYCBpbiB0aGUgW1J1biBBUEkgU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykgZm9yIGNhbGxpbmcgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbC4pXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMuc2F2ZSgncHJpY2UnLCA0KTtcbiAgICAgICAgICogICAgICB2cy5zYXZlKHsgcHJpY2U6IDQsIHF1YW50aXR5OiA1LCBwcm9kdWN0czogWzIsMyw0XSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgdmFyaWFibGVgIEFuIG9iamVjdCBjb21wb3NlZCBvZiB0aGUgbW9kZWwgdmFyaWFibGVzIGFuZCB0aGUgdmFsdWVzIHRvIHNhdmUuIEFsdGVybmF0aXZlbHksIGEgc3RyaW5nIHdpdGggdGhlIG5hbWUgb2YgdGhlIHZhcmlhYmxlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbGAgKE9wdGlvbmFsKSBJZiBwYXNzaW5nIGEgc3RyaW5nIGZvciBgdmFyaWFibGVgLCB1c2UgdGhpcyBhcmd1bWVudCBmb3IgdGhlIHZhbHVlIHRvIHNhdmUuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uICh2YXJpYWJsZSwgdmFsLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHZhcmlhYmxlID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHZhbDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW3ZhcmlhYmxlXSA9IHZhbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoLmNhbGwodGhpcywgYXR0cnMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIE5vdCBBdmFpbGFibGUgdW50aWwgdW5kZXJseWluZyBBUEkgc3VwcG9ydHMgUFVULiBPdGhlcndpc2Ugc2F2ZSB3b3VsZCBiZSBQVVQgYW5kIG1lcmdlIHdvdWxkIGJlIFBBVENIXG4gICAgICAgIC8vICpcbiAgICAgICAgLy8gICogU2F2ZSB2YWx1ZXMgdG8gdGhlIGFwaS4gTWVyZ2VzIGFycmF5cywgYnV0IG90aGVyd2lzZSBzYW1lIGFzIHNhdmVcbiAgICAgICAgLy8gICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSB2YXJpYWJsZSBPYmplY3Qgd2l0aCBhdHRyaWJ1dGVzLCBvciBzdHJpbmcga2V5XG4gICAgICAgIC8vICAqIEBwYXJhbSB7T2JqZWN0fSB2YWwgT3B0aW9uYWwgaWYgcHJldiBwYXJhbWV0ZXIgd2FzIGEgc3RyaW5nLCBzZXQgdmFsdWUgaGVyZVxuICAgICAgICAvLyAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xuICAgICAgICAvLyAgKlxuICAgICAgICAvLyAgKiBAZXhhbXBsZVxuICAgICAgICAvLyAgKiAgICAgdnMubWVyZ2UoeyBwcmljZTogNCwgcXVhbnRpdHk6IDUsIHByb2R1Y3RzOiBbMiwzLDRdIH0pXG4gICAgICAgIC8vICAqICAgICB2cy5tZXJnZSgncHJpY2UnLCA0KTtcblxuICAgICAgICAvLyBtZXJnZTogZnVuY3Rpb24gKHZhcmlhYmxlLCB2YWwsIG9wdGlvbnMpIHtcbiAgICAgICAgLy8gICAgIHZhciBhdHRycztcbiAgICAgICAgLy8gICAgIGlmICh0eXBlb2YgdmFyaWFibGUgPT09ICdvYmplY3QnKSB7XG4gICAgICAgIC8vICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgIC8vICAgICAgIG9wdGlvbnMgPSB2YWw7XG4gICAgICAgIC8vICAgICB9IGVsc2Uge1xuICAgICAgICAvLyAgICAgICAoYXR0cnMgPSB7fSlbdmFyaWFibGVdID0gdmFsO1xuICAgICAgICAvLyAgICAgfVxuICAgICAgICAvLyAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAvLyAgICAgcmV0dXJuIGh0dHAucGF0Y2guY2FsbCh0aGlzLCBhdHRycywgaHR0cE9wdGlvbnMpO1xuICAgICAgICAvLyB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICogIyNXb3JsZCBBUEkgQWRhcHRlclxuICpcbiAqIEEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsIC0tIGluY2x1ZGluZyBzZXR0aW5nIHZhcmlhYmxlcywgbWFraW5nIGRlY2lzaW9ucywgYW5kIGNhbGxpbmcgb3BlcmF0aW9ucy4gRm9yIGJ1aWxkaW5nIG11bHRpcGxheWVyIHNpbXVsYXRpb25zIHlvdSB0eXBpY2FsbHkgd2FudCBtdWx0aXBsZSBlbmQgdXNlcnMgdG8gc2hhcmUgdGhlIHNhbWUgc2V0IG9mIGludGVyYWN0aW9ucywgYW5kIHdvcmsgd2l0aGluIGEgY29tbW9uIHN0YXRlLiBFcGljZW50ZXIgYWxsb3dzIHlvdSB0byBjcmVhdGUgXCJ3b3JsZHNcIiB0byBoYW5kbGUgc3VjaCBjYXNlcy4gT25seSBbdGVhbSBwcm9qZWN0c10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIGNhbiBiZSBtdWx0aXBsYXllci5cbiAqXG4gKiBUaGUgV29ybGQgQVBJIEFkYXB0ZXIgYWxsb3dzIHlvdSB0byBjcmVhdGUsIGFjY2VzcywgYW5kIG1hbmlwdWxhdGUgbXVsdGlwbGF5ZXIgd29ybGRzIHdpdGhpbiB5b3VyIEVwaWNlbnRlciBwcm9qZWN0LiBZb3UgY2FuIHVzZSB0aGlzIHRvIGFkZCBhbmQgcmVtb3ZlIGVuZCB1c2VycyBmcm9tIHRoZSB3b3JsZCwgYW5kIHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgcmVtb3ZlIHRoZWlyIHJ1bnMuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4gKFRoZSByZWxhdGVkIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyLykgcHJvdmlkZXMgYW4gZWFzeSB3YXkgdG8gYWNjZXNzIHJ1bnMgYW5kIHdvcmxkcyBmb3IgcGFydGljdWxhciBlbmQgdXNlcnMsIHNvIGlzIHR5cGljYWxseSB1c2VkIGluIHBhZ2VzIHRoYXQgZW5kIHVzZXJzIHdpbGwgaW50ZXJhY3Qgd2l0aC4pXG4gKlxuICogQXMgd2l0aCBhbGwgdGhlIG90aGVyIFtBUEkgQWRhcHRlcnNdKC4uLy4uLyksIGFsbCBtZXRob2RzIHRha2UgaW4gYW4gXCJvcHRpb25zXCIgb2JqZWN0IGFzIHRoZSBsYXN0IHBhcmFtZXRlci4gVGhlIG9wdGlvbnMgY2FuIGJlIHVzZWQgdG8gZXh0ZW5kL292ZXJyaWRlIHRoZSBXb3JsZCBBUEkgU2VydmljZSBkZWZhdWx0cy5cbiAqXG4gKiBUbyB1c2UgdGhlIFdvcmxkIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSksIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKSwgYW5kIGdyb3VwICgqKkdyb3VwIE5hbWUqKikuXG4gKlxuICogICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gKiAgICAgICB3YS5jcmVhdGUoKVxuICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAqICAgICAgICAgICAgICAvLyBjYWxsIG1ldGhvZHMsIGUuZy4gd2EuYWRkVXNlcnMoKVxuICogICAgICAgICAgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG4vLyB2YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcblxudmFyIGFwaUJhc2UgPSAnbXVsdGlwbGF5ZXIvJztcbnZhciBhc3NpZ25tZW50RW5kcG9pbnQgPSBhcGlCYXNlICsgJ2Fzc2lnbic7XG52YXIgYXBpRW5kcG9pbnQgPSBhcGlCYXNlICsgJ3dvcmxkJztcbnZhciBwcm9qZWN0RW5kcG9pbnQgPSBhcGlCYXNlICsgJ3Byb2plY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkoeyBzeW5jaHJvbm91czogdHJ1ZSB9KTtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgdG9rZW46IHN0b3JlLmdldCgnZXBpY2VudGVyLnByb2plY3QudG9rZW4nKSB8fCAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGdyb3VwIG5hbWUuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgZ3JvdXA6IHVuZGVmaW5lZCxcblxuICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbW9kZWwgZmlsZSB0byB1c2UgdG8gY3JlYXRlIHJ1bnMgaW4gdGhpcyB3b3JsZC4gRGVmYXVsdHMgdG8gdW5kZWZpbmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgbW9kZWw6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ3JpdGVyaWEgYnkgd2hpY2ggdG8gZmlsdGVyIHdvcmxkLiBDdXJyZW50bHkgb25seSBzdXBwb3J0cyB3b3JsZC1pZHMgYXMgZmlsdGVycy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlbmllbmNlIGFsaWFzIGZvciBmaWx0ZXJcbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGlkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBjb21wbGV0ZXMgc3VjY2Vzc2Z1bGx5LiBEZWZhdWx0cyB0byBgJC5ub29wYC5cbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgc3VjY2VzczogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBmYWlscy4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIGVycm9yOiAkLm5vb3BcbiAgICB9O1xuXG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMucHJvamVjdCA9IHVybENvbmZpZy5wcm9qZWN0UGF0aDtcbiAgICB9XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBzZXRJZEZpbHRlck9yVGhyb3dFcnJvciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGlmIChvcHRpb25zLmlkKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmlkO1xuICAgICAgICB9XG4gICAgICAgIGlmIChvcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gb3B0aW9ucy5maWx0ZXI7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gd29ybGQgaWQgc3BlY2lmaWVkIHRvIGFwcGx5IG9wZXJhdGlvbnMgYWdhaW5zdC4gVGhpcyBjb3VsZCBoYXBwZW4gaWYgdGhlIHVzZXIgaXMgbm90IGFzc2lnbmVkIHRvIGEgd29ybGQgYW5kIGlzIHRyeWluZyB0byB3b3JrIHdpdGggcnVucyBmcm9tIHRoYXQgd29ybGQuJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICBpZiAoIW9wdGlvbnMubW9kZWwpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gbW9kZWwgc3BlY2lmaWVkIHRvIGdldCB0aGUgY3VycmVudCBydW4nKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIENyZWF0ZXMgYSBuZXcgV29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBVc2luZyB0aGlzIG1ldGhvZCBpcyByYXJlLiBJdCBpcyBtb3JlIGNvbW1vbiB0byBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkgd2hpbGUgeW91IGBhdXRvQXNzaWduKClgIGVuZCB1c2VycyB0byB3b3JsZHMuIChJbiB0aGlzIGNhc2UsIGNvbmZpZ3VyYXRpb24gZGF0YSBmb3IgdGhlIHdvcmxkLCBzdWNoIGFzIHRoZSByb2xlcywgYXJlIHJlYWQgZnJvbSB0aGUgcHJvamVjdC1sZXZlbCB3b3JsZCBjb25maWd1cmF0aW9uIGluZm9ybWF0aW9uLCBmb3IgZXhhbXBsZSBieSBgZ2V0UHJvamVjdFNldHRpbmdzKClgLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSh7XG4gICAgICAgICogICAgICAgICAgIHJvbGVzOiBbJ1ZQIE1hcmtldGluZycsICdWUCBTYWxlcycsICdWUCBFbmdpbmVlcmluZyddXG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBjcmVhdGUgdGhlIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmdyb3VwYCAoT3B0aW9uYWwpIFRoZSAqKkdyb3VwIE5hbWUqKiB0byBjcmVhdGUgdGhpcyB3b3JsZCB1bmRlci4gT25seSBlbmQgdXNlcnMgaW4gdGhpcyBncm91cCBhcmUgZWxpZ2libGUgdG8gam9pbiB0aGUgd29ybGQuIE9wdGlvbmFsIGhlcmU7IHJlcXVpcmVkIHdoZW4gaW5zdGFudGlhdGluZyB0aGUgc2VydmljZSAoYG5ldyBGLnNlcnZpY2UuV29ybGQoKWApLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zLnJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbXVzdCoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIHJvbGVzIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMub3B0aW9uYWxSb2xlc2AgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gYHBhcmFtcy5taW5Vc2Vyc2AgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgfSk7XG4gICAgICAgICAgICB2YXIgd29ybGRBcGlQYXJhbXMgPSBbJ3Njb3BlJywgJ2ZpbGVzJywgJ3JvbGVzJywgJ29wdGlvbmFsUm9sZXMnLCAnbWluVXNlcnMnLCAnZ3JvdXAnLCAnbmFtZSddO1xuICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIHdvcmxkQXBpUGFyYW1zKTtcblxuICAgICAgICAgICAgLy8gYWNjb3VudCBhbmQgcHJvamVjdCBnbyBpbiB0aGUgYm9keSwgbm90IGluIHRoZSB1cmxcbiAgICAgICAgICAgICQuZXh0ZW5kKHBhcmFtcywgX3BpY2soc2VydmljZU9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pKTtcblxuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBjcmVhdGVPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgICAgICBjcmVhdGVPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSByZXNwb25zZS5pZDsgLy9hbGwgZnV0dXJlIGNoYWluZWQgY2FsbHMgdG8gb3BlcmF0ZSBvbiB0aGlzIGlkXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBVcGRhdGVzIGEgV29ybGQsIGZvciBleGFtcGxlIHRvIHJlcGxhY2UgdGhlIHJvbGVzIGluIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgeW91IGNvbXBsZXRlIHdvcmxkIGNvbmZpZ3VyYXRpb24gYXQgdGhlIHByb2plY3QgbGV2ZWwsIHJhdGhlciB0aGFuIGF0IHRoZSB3b3JsZCBsZXZlbC4gRm9yIGV4YW1wbGUsIGVhY2ggd29ybGQgaW4geW91ciBwcm9qZWN0IHByb2JhYmx5IGhhcyB0aGUgc2FtZSByb2xlcyBmb3IgZW5kIHVzZXJzLiBBbmQgeW91ciBwcm9qZWN0IGlzIHByb2JhYmx5IGVpdGhlciBjb25maWd1cmVkIHNvIHRoYXQgYWxsIGVuZCB1c2VycyBzaGFyZSB0aGUgc2FtZSB3b3JsZCAoYW5kIHJ1biksIG9yIHNtYWxsZXIgc2V0cyBvZiBlbmQgdXNlcnMgc2hhcmUgd29ybGRzIOKAlCBidXQgbm90IGJvdGguIEhvd2V2ZXIsIHRoaXMgbWV0aG9kIGlzIGF2YWlsYWJsZSBpZiB5b3UgbmVlZCB0byB1cGRhdGUgdGhlIGNvbmZpZ3VyYXRpb24gb2YgYSBwYXJ0aWN1bGFyIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnVwZGF0ZSh7IHJvbGVzOiBbJ1ZQIE1hcmtldGluZycsICdWUCBTYWxlcycsICdWUCBFbmdpbmVlcmluZyddIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBQYXJhbWV0ZXJzIHRvIHVwZGF0ZSB0aGUgd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMubmFtZWAgQSBzdHJpbmcgaWRlbnRpZmllciBmb3IgdGhlIGxpbmtlZCBlbmQgdXNlcnMsIGZvciBleGFtcGxlLCBcIm5hbWVcIjogXCJPdXIgVGVhbVwiLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zLnJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbXVzdCoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIHJvbGVzIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMub3B0aW9uYWxSb2xlc2AgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gYHBhcmFtcy5taW5Vc2Vyc2AgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHdoaXRlbGlzdCA9IFsncm9sZXMnLCAnb3B0aW9uYWxSb2xlcycsICdtaW5Vc2VycyddO1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIHVwZGF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gX3BpY2socGFyYW1zIHx8IHt9LCB3aGl0ZWxpc3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wYXRjaChwYXJhbXMsIHVwZGF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgYW4gZXhpc3Rpbmcgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBUaGlzIGZ1bmN0aW9uIG9wdGlvbmFsbHkgdGFrZXMgb25lIGFyZ3VtZW50LiBJZiB0aGUgYXJndW1lbnQgaXMgYSBzdHJpbmcsIGl0IGlzIHRoZSBpZCBvZiB0aGUgd29ybGQgdG8gZGVsZXRlLiBJZiB0aGUgYXJndW1lbnQgaXMgYW4gb2JqZWN0LCBpdCBpcyB0aGUgb3ZlcnJpZGUgZm9yIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmRlbGV0ZSgpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBkZWxldGUsIG9yIG9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSAob3B0aW9ucyAmJiAodHlwZW9mIG9wdGlvbnMgPT09ICdzdHJpbmcnKSkgPyB7IGZpbHRlcjogb3B0aW9ucyB9IDoge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRlbGV0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGRlbGV0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBjdXJyZW50IGluc3RhbmNlIG9mIHRoZSBXb3JsZCBBUEkgQWRhcHRlciAoaW5jbHVkaW5nIGFsbCBzdWJzZXF1ZW50IGZ1bmN0aW9uIGNhbGxzLCB1bnRpbCB0aGUgY29uZmlndXJhdGlvbiBpcyB1cGRhdGVkIGFnYWluKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoey4uLn0pLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogJzEyMycgfSkuYWRkVXNlcih7IHVzZXJJZDogJzEyMycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgY29uZmlnYCBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgdG8gdXNlIGluIHVwZGF0aW5nIGV4aXN0aW5nIGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZUNvbmZpZzogZnVuY3Rpb24gKGNvbmZpZykge1xuICAgICAgICAgICAgJC5leHRlbmQoc2VydmljZU9wdGlvbnMsIGNvbmZpZyk7XG5cbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIExpc3RzIGFsbCB3b3JsZHMgZm9yIGEgZ2l2ZW4gYWNjb3VudCwgcHJvamVjdCwgYW5kIGdyb3VwLiBBbGwgdGhyZWUgYXJlIHJlcXVpcmVkLCBhbmQgaWYgbm90IHNwZWNpZmllZCBhcyBwYXJhbWV0ZXJzLCBhcmUgcmVhZCBmcm9tIHRoZSBzZXJ2aWNlLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGxpc3RzIGFsbCB3b3JsZHMgaW4gZ3JvdXAgXCJ0ZWFtMVwiXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5saXN0KCk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGxpc3RzIGFsbCB3b3JsZHMgaW4gZ3JvdXAgXCJvdGhlci1ncm91cC1uYW1lXCJcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmxpc3QoeyBncm91cDogJ290aGVyLWdyb3VwLW5hbWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBsaXN0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBmaWx0ZXJzID0gX3BpY2soZ2V0T3B0aW9ucywgWydhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGFsbCB3b3JsZHMgdGhhdCBhbiBlbmQgdXNlciBiZWxvbmdzIHRvIGZvciBhIGdpdmVuIGFjY291bnQgKHRlYW0pLCBwcm9qZWN0LCBhbmQgZ3JvdXAuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuZ2V0V29ybGRzRm9yVXNlcignYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJylcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZHMgYXJlIGJlaW5nIHJldHJpZXZlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGdldFdvcmxkc0ZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB2YXIgZmlsdGVycyA9ICQuZXh0ZW5kKFxuICAgICAgICAgICAgICAgIF9waWNrKGdldE9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pLFxuICAgICAgICAgICAgICAgIHsgdXNlcklkOiB1c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGZpbHRlcnMsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2FkIGluZm9ybWF0aW9uIGZvciBhIHNwZWNpZmljIHdvcmxkLiBBbGwgZnVydGhlciBjYWxscyB0byB0aGUgd29ybGQgc2VydmljZSB3aWxsIHVzZSB0aGUgaWQgcHJvdmlkZWQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgd29ybGRJZGAgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBsb2FkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSB3b3JsZElkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwcm92aWRlIGEgd29ybGRpZCB0byBsb2FkJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy8nIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQWRkcyBhbiBlbmQgdXNlciBvciBsaXN0IG9mIGVuZCB1c2VycyB0byBhIGdpdmVuIHdvcmxkLiBUaGUgZW5kIHVzZXIgbXVzdCBiZSBhIG1lbWJlciBvZiB0aGUgYGdyb3VwYCB0aGF0IGlzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBvbmUgdXNlclxuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoWydiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2Vycyh7IHVzZXJJZDogJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHJvbGU6ICdWUCBTYWxlcycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBzZXZlcmFsIHVzZXJzXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgeyB1c2VySWQ6ICdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgcm9sZTogJ1ZQIE1hcmtldGluZycgfSxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICB7IHVzZXJJZDogJzhmMjYwNGNmLTk2Y2QtNDQ5Zi04MmZhLWUzMzE1MzA3MzRlZScsXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgICByb2xlOiAnVlAgRW5naW5lZXJpbmcnIH1cbiAgICAgICAgKiAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgICAgICAgICAvLyBhZGQgb25lIHVzZXIgdG8gYSBzcGVjaWZpYyB3b3JsZFxuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB7IGZpbHRlcjogd29ybGQuaWQgfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKiogUGFyYW1ldGVycyAqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdHxhcnJheX0gYHVzZXJzYCBVc2VyIGlkLCBhcnJheSBvZiB1c2VyIGlkcywgb2JqZWN0LCBvciBhcnJheSBvZiBvYmplY3RzIG9mIHRoZSB1c2VycyB0byBhZGQgdG8gdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJzLnJvbGVgIFRoZSBgcm9sZWAgdGhlIHVzZXIgc2hvdWxkIGhhdmUgaW4gdGhlIHdvcmxkLiBJdCBpcyB1cCB0byB0aGUgY2FsbGVyIHRvIGVuc3VyZSwgaWYgbmVlZGVkLCB0aGF0IHRoZSBgcm9sZWAgcGFzc2VkIGluIGlzIG9uZSBvZiB0aGUgYHJvbGVzYCBvciBgb3B0aW9uYWxSb2xlc2Agb2YgdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHdvcmxkSWRgIFRoZSB3b3JsZCB0byB3aGljaCB0aGUgdXNlcnMgc2hvdWxkIGJlIGFkZGVkLiBJZiBub3Qgc3BlY2lmaWVkLCB0aGUgZmlsdGVyIHBhcmFtZXRlciBvZiB0aGUgYG9wdGlvbnNgIG9iamVjdCBpcyB1c2VkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgYWRkVXNlcnM6IGZ1bmN0aW9uICh1c2Vycywgd29ybGRJZCwgb3B0aW9ucykge1xuXG4gICAgICAgICAgICBpZiAoIXVzZXJzKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhIGxpc3Qgb2YgdXNlcnMgdG8gYWRkIHRvIHRoZSB3b3JsZCcpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBub3JtYWxpemUgdGhlIGxpc3Qgb2YgdXNlcnMgdG8gYW4gYXJyYXkgb2YgdXNlciBvYmplY3RzXG4gICAgICAgICAgICB1c2VycyA9ICQubWFwKFtdLmNvbmNhdCh1c2VycyksIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgdmFyIGlzT2JqZWN0ID0gJC5pc1BsYWluT2JqZWN0KHUpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB1ICE9PSAnc3RyaW5nJyAmJiAhaXNPYmplY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTb21lIG9mIHRoZSB1c2VycyBpbiB0aGUgbGlzdCBhcmUgbm90IGluIHRoZSB2YWxpZCBmb3JtYXQ6ICcgKyB1KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gaXNPYmplY3QgPyB1IDogeyB1c2VySWQ6IHUgfTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyBjaGVjayBpZiBvcHRpb25zIHdlcmUgcGFzc2VkIGFzIHRoZSBzZWNvbmQgcGFyYW1ldGVyXG4gICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHdvcmxkSWQpICYmICFvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHdvcmxkSWQ7XG4gICAgICAgICAgICAgICAgd29ybGRJZCA9IG51bGw7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICAvLyB3ZSBtdXN0IGhhdmUgb3B0aW9ucyBieSBub3dcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygd29ybGRJZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgdXBkYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvdXNlcnMnIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QodXNlcnMsIHVwZGF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIHJvbGUgb2YgYW4gZW5kIHVzZXIgaW4gYSBnaXZlbiB3b3JsZC4gKFlvdSBjYW4gb25seSB1cGRhdGUgb25lIGVuZCB1c2VyIGF0IGEgdGltZS4pXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuY3JlYXRlKCkudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJyk7XG4gICAgICAgICogICAgICAgICAgIHdhLnVwZGF0ZVVzZXIoeyB1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCByb2xlOiAnbGVhZGVyJyB9KTtcbiAgICAgICAgKiAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHVzZXJgIFVzZXIgb2JqZWN0IHdpdGggYHVzZXJJZGAgYW5kIHRoZSBuZXcgYHJvbGVgLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICB1cGRhdGVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICghdXNlciB8fCAhdXNlci51c2VySWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1lvdSBuZWVkIHRvIHBhc3MgYSB1c2VySWQgdG8gdXBkYXRlIGZyb20gdGhlIHdvcmxkJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcGF0Y2hPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goX3BpY2sodXNlciwgJ3JvbGUnKSwgcGF0Y2hPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZW1vdmVzIGFuIGVuZCB1c2VyIGZyb20gYSBnaXZlbiB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbJ2E2ZmUwYzFlLWY0YjgtNGYwMS05ZjVmLTAxY2NmNGMyZWQ0NCcsICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5yZW1vdmVVc2VyKCdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnJlbW92ZVVzZXIoeyB1c2VySWQ6ICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdHxzdHJpbmd9IGB1c2VyYCBUaGUgYHVzZXJJZGAgb2YgdGhlIHVzZXIgdG8gcmVtb3ZlIGZyb20gdGhlIHdvcmxkLCBvciBhbiBvYmplY3QgY29udGFpbmluZyB0aGUgYHVzZXJJZGAgZmllbGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICByZW1vdmVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICh0eXBlb2YgdXNlciA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICB1c2VyID0geyB1c2VySWQ6IHVzZXIgfTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCF1c2VyLnVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignWW91IG5lZWQgdG8gcGFzcyBhIHVzZXJJZCB0byByZW1vdmUgZnJvbSB0aGUgd29ybGQnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIHJ1biBpZCBvZiBjdXJyZW50IHJ1biBmb3IgdGhlIGdpdmVuIHdvcmxkLiBJZiB0aGUgd29ybGQgZG9lcyBub3QgaGF2ZSBhIHJ1biwgY3JlYXRlcyBhIG5ldyBvbmUgYW5kIHJldHVybnMgdGhlIHJ1biBpZC5cbiAgICAgICAgKlxuICAgICAgICAqIFJlbWVtYmVyIHRoYXQgYSBbcnVuXSguLi8uLi9nbG9zc2FyeS8jcnVuKSBpcyBhIGNvbGxlY3Rpb24gb2YgaW50ZXJhY3Rpb25zIHdpdGggYSBwcm9qZWN0IGFuZCBpdHMgbW9kZWwuIEluIHRoZSBjYXNlIG9mIG11bHRpcGxheWVyIHByb2plY3RzLCB0aGUgcnVuIGlzIHNoYXJlZCBieSBhbGwgZW5kIHVzZXJzIGluIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5nZXRDdXJyZW50UnVuSWQoeyBtb2RlbDogJ21vZGVsLnB5JyB9KTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9ucy5tb2RlbGAgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRSdW5JZDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3J1bicgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvcihnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QoX3BpY2soZ2V0T3B0aW9ucywgJ21vZGVsJyksIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIGN1cnJlbnQgKG1vc3QgcmVjZW50KSB3b3JsZCBmb3IgdGhlIGdpdmVuIGVuZCB1c2VyIGluIHRoZSBnaXZlbiBncm91cC4gQnJpbmdzIHRoaXMgbW9zdCByZWNlbnQgd29ybGQgaW50byBtZW1vcnkgaWYgbmVlZGVkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIHVzZSBkYXRhIGZyb20gd29ybGRcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSBjdXJyZW50IChtb3N0IHJlY2VudCkgd29ybGQgaXMgYmVpbmcgcmV0cmlldmVkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIFRoZSBuYW1lIG9mIHRoZSBncm91cC4gSWYgbm90IHByb3ZpZGVkLCBkZWZhdWx0cyB0byB0aGUgZ3JvdXAgdXNlZCB0byBjcmVhdGUgdGhlIHNlcnZpY2UuXG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRXb3JsZEZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIGdyb3VwTmFtZSkge1xuICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgICAgICB0aGlzLmdldFdvcmxkc0ZvclVzZXIodXNlcklkLCB7IGdyb3VwOiBncm91cE5hbWUgfSlcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGRzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGFzc3VtZSB0aGUgbW9zdCByZWNlbnQgd29ybGQgYXMgdGhlICdhY3RpdmUnIHdvcmxkXG4gICAgICAgICAgICAgICAgICAgIHdvcmxkcy5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7IHJldHVybiBuZXcgRGF0ZShiLmxhc3RNb2RpZmllZCkgLSBuZXcgRGF0ZShhLmxhc3RNb2RpZmllZCk7IH0pO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3VycmVudFdvcmxkID0gd29ybGRzWzBdO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChjdXJyZW50V29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9ICBjdXJyZW50V29ybGQuaWQ7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShjdXJyZW50V29ybGQsIG1lKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBEZWxldGVzIHRoZSBjdXJyZW50IHJ1biBmcm9tIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIChOb3RlIHRoYXQgdGhlIHdvcmxkIGlkIHJlbWFpbnMgcGFydCBvZiB0aGUgcnVuIHJlY29yZCwgaW5kaWNhdGluZyB0aGF0IHRoZSBydW4gd2FzIGZvcm1lcmx5IGFuIGFjdGl2ZSBydW4gZm9yIHRoZSB3b3JsZC4pXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmRlbGV0ZVJ1bignc2FtcGxlLXdvcmxkLWlkJyk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHdvcmxkSWRgIFRoZSBgd29ybGRJZGAgb2YgdGhlIHdvcmxkIGZyb20gd2hpY2ggdGhlIGN1cnJlbnQgcnVuIGlzIGJlaW5nIGRlbGV0ZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBkZWxldGVSdW46IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZGVsZXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvcnVuJyB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZGVsZXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIG5ldyBydW4gZm9yIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgd2EubmV3UnVuRm9yV29ybGQod29ybGQuaWQpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgd29ybGRJZGAgd29ybGRJZCBpbiB3aGljaCB3ZSBjcmVhdGUgdGhlIG5ldyBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9ucy5tb2RlbGAgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICovXG4gICAgICAgIG5ld1J1bkZvcldvcmxkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGN1cnJlbnRSdW5PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IGZpbHRlcjogd29ybGRJZCB8fCBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgICAgIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IoY3VycmVudFJ1bk9wdGlvbnMpO1xuXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5kZWxldGVSdW4od29ybGRJZCwgb3B0aW9ucylcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5nZXRDdXJyZW50UnVuSWQoY3VycmVudFJ1bk9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEFzc2lnbnMgZW5kIHVzZXJzIHRvIHdvcmxkcywgY3JlYXRpbmcgbmV3IHdvcmxkcyBhcyBhcHByb3ByaWF0ZSwgYXV0b21hdGljYWxseS4gQXNzaWducyBhbGwgZW5kIHVzZXJzIGluIHRoZSBncm91cCwgYW5kIGNyZWF0ZXMgbmV3IHdvcmxkcyBhcyBuZWVkZWQgYmFzZWQgb24gdGhlIHByb2plY3QtbGV2ZWwgd29ybGQgY29uZmlndXJhdGlvbiAocm9sZXMsIG9wdGlvbmFsIHJvbGVzLCBhbmQgbWluaW11bSBlbmQgdXNlcnMgcGVyIHdvcmxkKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5hdXRvQXNzaWduKCk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBhdXRvQXNzaWduOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhc3NpZ25tZW50RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBwYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgYWNjb3VudDogb3B0LmFjY291bnQsXG4gICAgICAgICAgICAgICAgcHJvamVjdDogb3B0LnByb2plY3QsXG4gICAgICAgICAgICAgICAgZ3JvdXA6IG9wdC5ncm91cFxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKG9wdC5tYXhVc2Vycykge1xuICAgICAgICAgICAgICAgIHBhcmFtcy5tYXhVc2VycyA9IG9wdC5tYXhVc2VycztcbiAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgb3B0KTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIHRoZSBwcm9qZWN0J3Mgd29ybGQgY29uZmlndXJhdGlvbi5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgZXZlcnkgaW50ZXJhY3Rpb24gd2l0aCB5b3VyIHByb2plY3QgdXNlcyB0aGUgc2FtZSBjb25maWd1cmF0aW9uIG9mIGVhY2ggd29ybGQuIEZvciBleGFtcGxlLCBlYWNoIHdvcmxkIGluIHlvdXIgcHJvamVjdCBwcm9iYWJseSBoYXMgdGhlIHNhbWUgcm9sZXMgZm9yIGVuZCB1c2Vycy4gQW5kIHlvdXIgcHJvamVjdCBpcyBwcm9iYWJseSBlaXRoZXIgY29uZmlndXJlZCBzbyB0aGF0IGFsbCBlbmQgdXNlcnMgc2hhcmUgdGhlIHNhbWUgd29ybGQgKGFuZCBydW4pLCBvciBzbWFsbGVyIHNldHMgb2YgZW5kIHVzZXJzIHNoYXJlIHdvcmxkcyDigJQgYnV0IG5vdCBib3RoLlxuICAgICAgICAqXG4gICAgICAgICogKFRoZSBbTXVsdGlwbGF5ZXIgUHJvamVjdCBSRVNUIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL211bHRpcGxheWVyX3Byb2plY3QvKSBhbGxvd3MgeW91IHRvIHNldCB0aGVzZSBwcm9qZWN0LWxldmVsIHdvcmxkIGNvbmZpZ3VyYXRpb25zLiBUaGUgV29ybGQgQWRhcHRlciBzaW1wbHkgcmV0cmlldmVzIHRoZW0sIGZvciBleGFtcGxlIHNvIHRoZXkgY2FuIGJlIHVzZWQgaW4gYXV0by1hc3NpZ25tZW50IG9mIGVuZCB1c2VycyB0byB3b3JsZHMuKVxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmdldFByb2plY3RTZXR0aW5ncygpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHNldHRpbmdzKSB7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5yb2xlcyk7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5vcHRpb25hbFJvbGVzKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0UHJvamVjdFNldHRpbmdzOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChwcm9qZWN0RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIG9wdC51cmwgKz0gW29wdC5hY2NvdW50LCBvcHQucHJvamVjdF0uam9pbignLycpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQobnVsbCwgb3B0KTtcbiAgICAgICAgfVxuXG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKiBAY2xhc3MgQ29va2llIFN0b3JhZ2UgU2VydmljZVxuICpcbiAqIEBleGFtcGxlXG4gKiAgICAgIHZhciBwZW9wbGUgPSByZXF1aXJlKCdjb29raWUtc3RvcmUnKSh7IHJvb3Q6ICdwZW9wbGUnIH0pO1xuICAgICAgICBwZW9wbGVcbiAgICAgICAgICAgIC5zYXZlKHtsYXN0TmFtZTogJ3NtaXRoJyB9KVxuXG4gKi9cblxuXG4ndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIE5hbWUgb2YgY29sbGVjdGlvblxuICAgICAgICAgKiBAdHlwZSB7IHN0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHJvb3Q6ICcvJyxcblxuICAgICAgICBkb21haW46ICcuZm9yaW8uY29tJ1xuICAgIH07XG4gICAgdGhpcy5zZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG4gICAgICAgIC8vICogVEJEXG4gICAgICAgIC8vICAqIFF1ZXJ5IGNvbGxlY3Rpb247IHVzZXMgTW9uZ29EQiBzeW50YXhcbiAgICAgICAgLy8gICogQHNlZSAgPFRCRDogRGF0YSBBUEkgVVJMPlxuICAgICAgICAvLyAgKlxuICAgICAgICAvLyAgKiBAcGFyYW0geyBzdHJpbmd9IHFzIFF1ZXJ5IEZpbHRlclxuICAgICAgICAvLyAgKiBAcGFyYW0geyBzdHJpbmd9IGxpbWl0ZXJzIEBzZWUgPFRCRDogdXJsIGZvciBsaW1pdHMsIHBhZ2luZyBldGM+XG4gICAgICAgIC8vICAqXG4gICAgICAgIC8vICAqIEBleGFtcGxlXG4gICAgICAgIC8vICAqICAgICBjcy5xdWVyeShcbiAgICAgICAgLy8gICogICAgICB7IG5hbWU6ICdKb2huJywgY2xhc3NOYW1lOiAnQ1NDMTAxJyB9LFxuICAgICAgICAvLyAgKiAgICAgIHtsaW1pdDogMTB9XG4gICAgICAgIC8vICAqICAgICApXG5cbiAgICAgICAgLy8gcXVlcnk6IGZ1bmN0aW9uIChxcywgbGltaXRlcnMpIHtcblxuICAgICAgICAvLyB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGNvb2tpZSB2YWx1ZVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5ICAgSWYgZ2l2ZW4gYSBrZXkgc2F2ZSB2YWx1ZXMgdW5kZXIgaXQsIGlmIGdpdmVuIGFuIG9iamVjdCBkaXJlY3RseSwgc2F2ZSB0byB0b3AtbGV2ZWwgYXBpXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gdmFsdWUgKE9wdGlvbmFsKVxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBPdmVycmlkZXMgZm9yIHNlcnZpY2Ugb3B0aW9uc1xuICAgICAgICAgKlxuICAgICAgICAgKiBAcmV0dXJuIHsqfSBUaGUgc2F2ZWQgdmFsdWVcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLnNldCgncGVyc29uJywgeyBmaXJzdE5hbWU6ICdqb2huJywgbGFzdE5hbWU6ICdzbWl0aCcgfSk7XG4gICAgICAgICAqICAgICBjcy5zZXQoeyBuYW1lOidzbWl0aCcsIGFnZTonMzInIH0pO1xuICAgICAgICAgKi9cbiAgICAgICAgc2V0OiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHNldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdGhpcy5zZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBkb21haW4gPSBzZXRPcHRpb25zLmRvbWFpbjtcbiAgICAgICAgICAgIHZhciBwYXRoID0gc2V0T3B0aW9ucy5yb290O1xuXG4gICAgICAgICAgICBkb2N1bWVudC5jb29raWUgPSBlbmNvZGVVUklDb21wb25lbnQoa2V5KSArICc9JyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuY29kZVVSSUNvbXBvbmVudCh2YWx1ZSkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZG9tYWluID8gJzsgZG9tYWluPScgKyBkb21haW4gOiAnJykgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocGF0aCA/ICc7IHBhdGg9JyArIHBhdGggOiAnJyk7XG5cbiAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTG9hZCBjb29raWUgdmFsdWVcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xPYmplY3R9IGtleSAgIElmIGdpdmVuIGEga2V5IHNhdmUgdmFsdWVzIHVuZGVyIGl0LCBpZiBnaXZlbiBhbiBvYmplY3QgZGlyZWN0bHksIHNhdmUgdG8gdG9wLWxldmVsIGFwaVxuICAgICAgICAgKiBAcmV0dXJuIHsqfSBUaGUgdmFsdWUgc3RvcmVkXG4gICAgICAgICAqXG4gICAgICAgICAqIEBleGFtcGxlXG4gICAgICAgICAqICAgICBjcy5nZXQoJ3BlcnNvbicpO1xuICAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgICAgICB2YXIgY29va2llUmVnID0gbmV3IFJlZ0V4cCgnKD86KD86XnwuKjspXFxcXHMqJyArIGVuY29kZVVSSUNvbXBvbmVudChrZXkpLnJlcGxhY2UoL1tcXC1cXC5cXCtcXCpdL2csICdcXFxcJCYnKSArICdcXFxccypcXFxcPVxcXFxzKihbXjtdKikuKiQpfF4uKiQnKTtcbiAgICAgICAgICAgIHZhciB2YWwgPSBkb2N1bWVudC5jb29raWUucmVwbGFjZShjb29raWVSZWcsICckMScpO1xuICAgICAgICAgICAgdmFsID0gZGVjb2RlVVJJQ29tcG9uZW50KHZhbCkgfHwgbnVsbDtcbiAgICAgICAgICAgIHJldHVybiB2YWw7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMga2V5IGZyb20gY29sbGVjdGlvblxuICAgICAgICAgKiBAcGFyYW0geyBzdHJpbmd9IGtleSBrZXkgdG8gcmVtb3ZlXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9IGtleSBUaGUga2V5IHJlbW92ZWRcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLnJlbW92ZSgncGVyc29uJyk7XG4gICAgICAgICAqL1xuICAgICAgICByZW1vdmU6IGZ1bmN0aW9uIChrZXksIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciByZW1PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMuc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZG9tYWluID0gcmVtT3B0aW9ucy5kb21haW47XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHJlbU9wdGlvbnMucm9vdDtcblxuICAgICAgICAgICAgZG9jdW1lbnQuY29va2llID0gZW5jb2RlVVJJQ29tcG9uZW50KGtleSkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICc9OyBleHBpcmVzPVRodSwgMDEgSmFuIDE5NzAgMDA6MDA6MDAgR01UJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKGRvbWFpbiA/ICc7IGRvbWFpbj0nICsgZG9tYWluIDogJycpICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAocGF0aCA/ICc7IHBhdGg9JyArIHBhdGggOiAnJyk7XG4gICAgICAgICAgICByZXR1cm4ga2V5O1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZW1vdmVzIGNvbGxlY3Rpb24gYmVpbmcgcmVmZXJlbmNlZFxuICAgICAgICAgKiBAcmV0dXJuIHsgYXJyYXl9IGtleXMgQWxsIHRoZSBrZXlzIHJlbW92ZWRcbiAgICAgICAgICovXG4gICAgICAgIGRlc3Ryb3k6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBhS2V5cyA9IGRvY3VtZW50LmNvb2tpZS5yZXBsYWNlKC8oKD86XnxcXHMqOylbXlxcPV0rKSg/PTt8JCl8Xlxccyp8XFxzKig/OlxcPVteO10qKT8oPzpcXDF8JCkvZywgJycpLnNwbGl0KC9cXHMqKD86XFw9W147XSopPztcXHMqLyk7XG4gICAgICAgICAgICBmb3IgKHZhciBuSWR4ID0gMDsgbklkeCA8IGFLZXlzLmxlbmd0aDsgbklkeCsrKSB7XG4gICAgICAgICAgICAgICAgdmFyIGNvb2tpZUtleSA9IGRlY29kZVVSSUNvbXBvbmVudChhS2V5c1tuSWR4XSk7XG4gICAgICAgICAgICAgICAgdGhpcy5yZW1vdmUoY29va2llS2V5KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhS2V5cztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICAgIERlY2lkZXMgdHlwZSBvZiBzdG9yZSB0byBwcm92aWRlXG4qL1xuXG4ndXNlIHN0cmljdCc7XG4vLyB2YXIgaXNOb2RlID0gZmFsc2U7IEZJWE1FOiBCcm93c2VyaWZ5L21pbmlmeWlmeSBoYXMgaXNzdWVzIHdpdGggdGhlIG5leHQgbGlua1xuLy8gdmFyIHN0b3JlID0gKGlzTm9kZSkgPyByZXF1aXJlKCcuL3Nlc3Npb24tc3RvcmUnKSA6IHJlcXVpcmUoJy4vY29va2llLXN0b3JlJyk7XG52YXIgc3RvcmUgPSByZXF1aXJlKCcuL2Nvb2tpZS1zdG9yZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHN0b3JlO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgcXV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICB1cmw6ICcnLFxuXG4gICAgICAgIGNvbnRlbnRUeXBlOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICAgIGhlYWRlcnM6IHt9LFxuICAgICAgICBzdGF0dXNDb2RlOiB7XG4gICAgICAgICAgICA0MDQ6ICQubm9vcFxuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPTkxZIGZvciBzdHJpbmdzIGluIHRoZSB1cmwuIEFsbCBHRVQgJiBERUxFVEUgcGFyYW1zIGFyZSBydW4gdGhyb3VnaCB0aGlzXG4gICAgICAgICAqIEB0eXBlIHtbdHlwZV0gfVxuICAgICAgICAgKi9cbiAgICAgICAgcGFyYW1ldGVyUGFyc2VyOiBxdXRpbHMudG9RdWVyeUZvcm1hdCxcblxuICAgICAgICAvLyBUbyBhbGxvdyBlcGljZW50ZXIudG9rZW4gYW5kIG90aGVyIHNlc3Npb24gY29va2llcyB0byBiZSBwYXNzZWRcbiAgICAgICAgLy8gd2l0aCB0aGUgcmVxdWVzdHNcbiAgICAgICAgeGhyRmllbGRzOiB7XG4gICAgICAgICAgICB3aXRoQ3JlZGVudGlhbHM6IHRydWVcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciByZXN1bHQgPSBmdW5jdGlvbiAoZCkge1xuICAgICAgICByZXR1cm4gKCQuaXNGdW5jdGlvbihkKSkgPyBkKCkgOiBkO1xuICAgIH07XG5cbiAgICB2YXIgY29ubmVjdCA9IGZ1bmN0aW9uIChtZXRob2QsIHBhcmFtcywgY29ubmVjdE9wdGlvbnMpIHtcbiAgICAgICAgcGFyYW1zID0gcmVzdWx0KHBhcmFtcyk7XG4gICAgICAgIHBhcmFtcyA9ICgkLmlzUGxhaW5PYmplY3QocGFyYW1zKSB8fCAkLmlzQXJyYXkocGFyYW1zKSkgPyBKU09OLnN0cmluZ2lmeShwYXJhbXMpIDogcGFyYW1zO1xuXG4gICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHRyYW5zcG9ydE9wdGlvbnMsIGNvbm5lY3RPcHRpb25zLCB7XG4gICAgICAgICAgICB0eXBlOiBtZXRob2QsXG4gICAgICAgICAgICBkYXRhOiBwYXJhbXNcbiAgICAgICAgfSk7XG4gICAgICAgIHZhciBBTExPV0VEX1RPX0JFX0ZVTkNUSU9OUyA9IFsnZGF0YScsICd1cmwnXTtcbiAgICAgICAgJC5lYWNoKG9wdGlvbnMsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICBpZiAoJC5pc0Z1bmN0aW9uKHZhbHVlKSAmJiAkLmluQXJyYXkoa2V5LCBBTExPV0VEX1RPX0JFX0ZVTkNUSU9OUykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9uc1trZXldID0gdmFsdWUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKG9wdGlvbnMubG9nTGV2ZWwgJiYgb3B0aW9ucy5sb2dMZXZlbCA9PT0gJ0RFQlVHJykge1xuICAgICAgICAgICAgY29uc29sZS5sb2cob3B0aW9ucy51cmwpO1xuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3NGbiA9IG9wdGlvbnMuc3VjY2VzcyB8fCAkLm5vb3A7XG4gICAgICAgICAgICBvcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UsIGFqYXhTdGF0dXMsIGFqYXhSZXEpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhyZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgb2xkU3VjY2Vzc0ZuLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGJlZm9yZVNlbmQgPSBvcHRpb25zLmJlZm9yZVNlbmQ7XG4gICAgICAgIG9wdGlvbnMuYmVmb3JlU2VuZCA9IGZ1bmN0aW9uICh4aHIsIHNldHRpbmdzKSB7XG4gICAgICAgICAgICB4aHIucmVxdWVzdFVybCA9IChjb25uZWN0T3B0aW9ucyB8fCB7fSkudXJsO1xuICAgICAgICAgICAgaWYgKGJlZm9yZVNlbmQpIHtcbiAgICAgICAgICAgICAgICBiZWZvcmVTZW5kLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuICQuYWpheChvcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgZ2V0OmZ1bmN0aW9uIChwYXJhbXMsIGFqYXhPcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCB0cmFuc3BvcnRPcHRpb25zLCBhamF4T3B0aW9ucyk7XG4gICAgICAgICAgICBwYXJhbXMgPSBvcHRpb25zLnBhcmFtZXRlclBhcnNlcihyZXN1bHQocGFyYW1zKSk7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5jYWxsKHRoaXMsICdHRVQnLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuICAgICAgICBzcGxpdEdldDogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgIH0sXG4gICAgICAgIHBvc3Q6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncG9zdCddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfSxcbiAgICAgICAgcGF0Y2g6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncGF0Y2gnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIHB1dDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydwdXQnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKHBhcmFtcywgYWpheE9wdGlvbnMpIHtcbiAgICAgICAgICAgIC8vREVMRVRFIGRvZXNuJ3Qgc3VwcG9ydCBib2R5IHBhcmFtcywgYnV0IGpRdWVyeSB0aGlua3MgaXQgZG9lcy5cbiAgICAgICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQoe30sIHRyYW5zcG9ydE9wdGlvbnMsIGFqYXhPcHRpb25zKTtcbiAgICAgICAgICAgIHBhcmFtcyA9IG9wdGlvbnMucGFyYW1ldGVyUGFyc2VyKHJlc3VsdChwYXJhbXMpKTtcbiAgICAgICAgICAgIGlmICgkLnRyaW0ocGFyYW1zKSkge1xuICAgICAgICAgICAgICAgIHZhciBkZWxpbWl0ZXIgPSAocmVzdWx0KG9wdGlvbnMudXJsKS5pbmRleE9mKCc/JykgPT09IC0xKSA/ICc/JyA6ICcmJztcbiAgICAgICAgICAgICAgICBvcHRpb25zLnVybCA9IHJlc3VsdChvcHRpb25zLnVybCkgKyBkZWxpbWl0ZXIgKyBwYXJhbXM7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5jYWxsKHRoaXMsICdERUxFVEUnLCBudWxsLCBvcHRpb25zKTtcbiAgICAgICAgfSxcbiAgICAgICAgaGVhZDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydoZWFkJ10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9LFxuICAgICAgICBvcHRpb25zOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ29wdGlvbnMnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcmV0dXJuICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyB2YXIgaXNOb2RlID0gZmFsc2U7IEZJWE1FOiBCcm93c2VyaWZ5L21pbmlmeWlmeSBoYXMgaXNzdWVzIHdpdGggdGhlIG5leHQgbGlua1xuLy8gdmFyIHRyYW5zcG9ydCA9IChpc05vZGUpID8gcmVxdWlyZSgnLi9ub2RlLWh0dHAtdHJhbnNwb3J0JykgOiByZXF1aXJlKCcuL2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcbnZhciB0cmFuc3BvcnQgPSByZXF1aXJlKCcuL2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcbm1vZHVsZS5leHBvcnRzID0gdHJhbnNwb3J0O1xuIiwiLyoqXG4vKiBJbmhlcml0IGZyb20gYSBjbGFzcyAodXNpbmcgcHJvdG90eXBlIGJvcnJvd2luZylcbiovXG4ndXNlIHN0cmljdCc7XG5cbmZ1bmN0aW9uIGluaGVyaXQoQywgUCkge1xuICAgIHZhciBGID0gZnVuY3Rpb24gKCkge307XG4gICAgRi5wcm90b3R5cGUgPSBQLnByb3RvdHlwZTtcbiAgICBDLnByb3RvdHlwZSA9IG5ldyBGKCk7XG4gICAgQy5fX3N1cGVyID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDO1xufVxuXG4vKipcbiogU2hhbGxvdyBjb3B5IG9mIGFuIG9iamVjdFxuKi9cbnZhciBleHRlbmQgPSBmdW5jdGlvbiAoZGVzdCAvKiwgdmFyX2FyZ3MqLykge1xuICAgIHZhciBvYmogPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgIHZhciBjdXJyZW50O1xuICAgIGZvciAodmFyIGogPSAwOyBqPG9iai5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAoIShjdXJyZW50ID0gb2JqW2pdKSkge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkbyBub3Qgd3JhcCBpbm5lciBpbiBkZXN0Lmhhc093blByb3BlcnR5IG9yIGJhZCB0aGluZ3Mgd2lsbCBoYXBwZW5cbiAgICAgICAgLypqc2hpbnQgLVcwODkgKi9cbiAgICAgICAgZm9yICh2YXIga2V5IGluIGN1cnJlbnQpIHtcbiAgICAgICAgICAgIGRlc3Rba2V5XSA9IGN1cnJlbnRba2V5XTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBkZXN0O1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoYmFzZSwgcHJvcHMsIHN0YXRpY1Byb3BzKSB7XG4gICAgdmFyIHBhcmVudCA9IGJhc2U7XG4gICAgdmFyIGNoaWxkO1xuXG4gICAgY2hpbGQgPSBwcm9wcyAmJiBwcm9wcy5oYXNPd25Qcm9wZXJ0eSgnY29uc3RydWN0b3InKSA/IHByb3BzLmNvbnN0cnVjdG9yIDogZnVuY3Rpb24gKCkgeyByZXR1cm4gcGFyZW50LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7IH07XG5cbiAgICAvLyBhZGQgc3RhdGljIHByb3BlcnRpZXMgdG8gdGhlIGNoaWxkIGNvbnN0cnVjdG9yIGZ1bmN0aW9uXG4gICAgZXh0ZW5kKGNoaWxkLCBwYXJlbnQsIHN0YXRpY1Byb3BzKTtcblxuICAgIC8vIGFzc29jaWF0ZSBwcm90b3R5cGUgY2hhaW5cbiAgICBpbmhlcml0KGNoaWxkLCBwYXJlbnQpO1xuXG4gICAgLy8gYWRkIGluc3RhbmNlIHByb3BlcnRpZXNcbiAgICBpZiAocHJvcHMpIHtcbiAgICAgICAgZXh0ZW5kKGNoaWxkLnByb3RvdHlwZSwgcHJvcHMpO1xuICAgIH1cblxuICAgIC8vIGRvbmVcbiAgICByZXR1cm4gY2hpbGQ7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLypqc2hpbnQgbG9vcGZ1bmM6ZmFsc2UgKi9cblxuZnVuY3Rpb24gX3codmFsKSB7XG4gICAgaWYgKHZhbCAmJiB2YWwudGhlbikge1xuICAgICAgICByZXR1cm4gdmFsO1xuICAgIH1cbiAgICB2YXIgcCA9ICQuRGVmZXJyZWQoKTtcbiAgICBwLnJlc29sdmUodmFsKTtcblxuICAgIHJldHVybiBwLnByb21pc2UoKTtcbn1cblxuZnVuY3Rpb24gc2VxKCkge1xuICAgIHZhciBsaXN0ID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmFwcGx5KGFyZ3VtZW50cyk7XG5cbiAgICBmdW5jdGlvbiBuZXh0KHApIHtcbiAgICAgICAgdmFyIGN1ciA9IGxpc3Quc3BsaWNlKDAsMSlbMF07XG5cbiAgICAgICAgaWYgKCFjdXIpIHtcbiAgICAgICAgICAgIHJldHVybiBwO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIF93KGN1cihwKSkudGhlbihuZXh0KTtcbiAgICB9XG5cbiAgICByZXR1cm4gZnVuY3Rpb24gKHNlZWQpIHtcbiAgICAgICAgcmV0dXJuIG5leHQoc2VlZCkuZmFpbChzZXEuZmFpbCk7XG4gICAgfTtcbn1cblxuZnVuY3Rpb24gTWFrZVNlcShvYmopIHtcbiAgICB2YXIgcmVzID0ge1xuICAgICAgICBfX2NhbGxzOiBbXSxcblxuICAgICAgICBvcmlnaW5hbDogb2JqLFxuXG4gICAgICAgIHRoZW46IGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgICAgdGhpcy5fX2NhbGxzLnB1c2goZm4pO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgc3RhcnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgICAgIC8vIGNsZWFuIHVwXG4gICAgICAgICAgICB0aGlzLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIF90aGlzLl9fY2FsbHMubGVuZ3RoID0gMDtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiBzZXEuYXBwbHkobnVsbCwgdGhpcy5fX2NhbGxzKSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGZhaWw6IGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgICAgc2VxLmZhaWwgPSBmbjtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBmdW5jTWFrZXIgPSBmdW5jdGlvbiAocCwgb2JqKSB7XG4gICAgICAgIHZhciBmbiA9IG9ialtwXS5iaW5kKG9iaik7XG4gICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5hcHBseShhcmd1bWVudHMpO1xuICAgICAgICAgICAgdGhpcy5fX2NhbGxzLnB1c2goRnVuY3Rpb24uYmluZC5hcHBseShmbiwgW251bGxdLmNvbmNhdChhcmdzKSkpO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH07XG4gICAgfTtcblxuICAgIGZvciAodmFyIHByb3AgaW4gb2JqKSB7XG4gICAgICAgIGlmICh0eXBlb2Ygb2JqW3Byb3BdID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICByZXNbcHJvcF0gPSBmdW5jTWFrZXIocHJvcCwgb2JqKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJlc1twcm9wXSA9IG9ialtwcm9wXTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXM7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gTWFrZVNlcTtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgX3BpY2s6IGZ1bmN0aW9uIChvYmosIHByb3BzKSB7XG4gICAgICAgIHZhciByZXMgPSB7fTtcbiAgICAgICAgZm9yICh2YXIgcCBpbiBvYmopIHtcbiAgICAgICAgICAgIGlmIChwcm9wcy5pbmRleE9mKHApICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIHJlc1twXSA9IG9ialtwXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxufTtcbiIsIi8qKlxuICogVXRpbGl0aWVzIGZvciB3b3JraW5nIHdpdGggcXVlcnkgc3RyaW5nc1xuKi9cbid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSAoZnVuY3Rpb24gKCkge1xuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlcnRzIHRvIG1hdHJpeCBmb3JtYXRcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBxcyBPYmplY3QgdG8gY29udmVydCB0byBxdWVyeSBzdHJpbmdcbiAgICAgICAgICogQHJldHVybiB7IHN0cmluZ30gICAgTWF0cml4LWZvcm1hdCBxdWVyeSBwYXJhbWV0ZXJzXG4gICAgICAgICAqL1xuICAgICAgICB0b01hdHJpeEZvcm1hdDogZnVuY3Rpb24gKHFzKSB7XG4gICAgICAgICAgICBpZiAocXMgPT09IG51bGwgfHwgcXMgPT09IHVuZGVmaW5lZCB8fCBxcyA9PT0gJycpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJzsnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHR5cGVvZiBxcyA9PT0gJ3N0cmluZycgfHwgcXMgaW5zdGFuY2VvZiBTdHJpbmcpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcXM7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciByZXR1cm5BcnJheSA9IFtdO1xuICAgICAgICAgICAgdmFyIE9QRVJBVE9SUyA9IFsnPCcsICc+JywgJyEnXTtcbiAgICAgICAgICAgICQuZWFjaChxcywgZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlICE9PSAnc3RyaW5nJyB8fCAkLmluQXJyYXkoJC50cmltKHZhbHVlKS5jaGFyQXQoMCksIE9QRVJBVE9SUykgPT09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gJz0nICsgdmFsdWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkFycmF5LnB1c2goa2V5ICsgdmFsdWUpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHZhciBtdHJ4ID0gJzsnICsgcmV0dXJuQXJyYXkuam9pbignOycpO1xuICAgICAgICAgICAgcmV0dXJuIG10cng7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlcnRzIHN0cmluZ3MvYXJyYXlzL29iamVjdHMgdG8gdHlwZSAnYT1iJmI9YydcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xBcnJheXxPYmplY3R9IHFzXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b1F1ZXJ5Rm9ybWF0OiBmdW5jdGlvbiAocXMpIHtcbiAgICAgICAgICAgIGlmIChxcyA9PT0gbnVsbCB8fCBxcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHR5cGVvZiBxcyA9PT0gJ3N0cmluZycgfHwgcXMgaW5zdGFuY2VvZiBTdHJpbmcpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcXM7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciByZXR1cm5BcnJheSA9IFtdO1xuICAgICAgICAgICAgJC5lYWNoKHFzLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIGlmICgkLmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gdmFsdWUuam9pbignLCcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHZhbHVlKSkge1xuICAgICAgICAgICAgICAgICAgICAvL01vc3RseSBmb3IgZGF0YSBhcGlcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBKU09OLnN0cmluZ2lmeSh2YWx1ZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkFycmF5LnB1c2goa2V5ICsgJz0nICsgdmFsdWUpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHZhciByZXN1bHQgPSByZXR1cm5BcnJheS5qb2luKCcmJyk7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZXJ0cyBzdHJpbmdzIG9mIHR5cGUgJ2E9YiZiPWMnIHRvIHsgYTpiLCBiOmN9XG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd9IHFzXG4gICAgICAgICAqIEByZXR1cm4ge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHFzVG9PYmplY3Q6IGZ1bmN0aW9uIChxcykge1xuICAgICAgICAgICAgaWYgKHFzID09PSBudWxsIHx8IHFzID09PSB1bmRlZmluZWQgfHwgcXMgPT09ICcnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcXNBcnJheSA9IHFzLnNwbGl0KCcmJyk7XG4gICAgICAgICAgICB2YXIgcmV0dXJuT2JqID0ge307XG4gICAgICAgICAgICAkLmVhY2gocXNBcnJheSwgZnVuY3Rpb24gKGluZGV4LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHZhciBxS2V5ID0gdmFsdWUuc3BsaXQoJz0nKVswXTtcbiAgICAgICAgICAgICAgICB2YXIgcVZhbCA9IHZhbHVlLnNwbGl0KCc9JylbMV07XG5cbiAgICAgICAgICAgICAgICBpZiAocVZhbC5pbmRleE9mKCcsJykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHFWYWwgPSBxVmFsLnNwbGl0KCcsJyk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuT2JqW3FLZXldID0gcVZhbDtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gcmV0dXJuT2JqO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBOb3JtYWxpemVzIGFuZCBtZXJnZXMgc3RyaW5ncyBvZiB0eXBlICdhPWInLCB7IGI6Y30gdG8geyBhOmIsIGI6Y31cbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xBcnJheXxPYmplY3R9IHFzMVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfEFycmF5fE9iamVjdH0gcXMyXG4gICAgICAgICAqIEByZXR1cm4ge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIG1lcmdlUVM6IGZ1bmN0aW9uIChxczEsIHFzMikge1xuICAgICAgICAgICAgdmFyIG9iajEgPSB0aGlzLnFzVG9PYmplY3QodGhpcy50b1F1ZXJ5Rm9ybWF0KHFzMSkpO1xuICAgICAgICAgICAgdmFyIG9iajIgPSB0aGlzLnFzVG9PYmplY3QodGhpcy50b1F1ZXJ5Rm9ybWF0KHFzMikpO1xuICAgICAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHRydWUsIHt9LCBvYmoxLCBvYmoyKTtcbiAgICAgICAgfSxcblxuICAgICAgICBhZGRUcmFpbGluZ1NsYXNoOiBmdW5jdGlvbiAodXJsKSB7XG4gICAgICAgICAgICBpZiAoIXVybCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAodXJsLmNoYXJBdCh1cmwubGVuZ3RoIC0gMSkgPT09ICcvJykgPyB1cmwgOiAodXJsICsgJy8nKTtcbiAgICAgICAgfVxuICAgIH07XG59KCkpO1xuXG5cblxuIiwiLyoqXG4gKiBVdGlsaXRpZXMgZm9yIHdvcmtpbmcgd2l0aCB0aGUgcnVuIHNlcnZpY2VcbiovXG4ndXNlIHN0cmljdCc7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuL3F1ZXJ5LXV0aWwnKTtcbnZhciBNQVhfVVJMX0xFTkdUSCA9IDIwNDg7XG5cbm1vZHVsZS5leHBvcnRzID0gKGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICAvKipcbiAgICAgICAgICogcmV0dXJucyBvcGVyYXRpb25zIG9mIHRoZSBmb3JtIGBbW29wMSxvcDJdLCBbYXJnMSwgYXJnMl1dYFxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R8QXJyYXl8U3RyaW5nfSBgb3BlcmF0aW9uc2Agb3BlcmF0aW9ucyB0byBwZXJmb3JtXG4gICAgICAgICAqIEBwYXJhbSAge0FycmF5fSBgYXJnc2AgYXJndW1lbnRzIGZvciBvcGVyYXRpb25cbiAgICAgICAgICogQHJldHVybiB7U3RyaW5nfSAgICBNYXRyaXgtZm9ybWF0IHF1ZXJ5IHBhcmFtZXRlcnNcbiAgICAgICAgICovXG4gICAgICAgIG5vcm1hbGl6ZU9wZXJhdGlvbnM6IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBhcmdzKSB7XG4gICAgICAgICAgICBpZiAoIWFyZ3MpIHtcbiAgICAgICAgICAgICAgICBhcmdzID0gW107XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgcmV0dXJuTGlzdCA9IHtcbiAgICAgICAgICAgICAgICBvcHM6IFtdLFxuICAgICAgICAgICAgICAgIGFyZ3M6IFtdXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgX2NvbmNhdCA9IGZ1bmN0aW9uIChhcnIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gKGFyciAhPT0gbnVsbCAmJiBhcnIgIT09IHVuZGVmaW5lZCkgPyBbXS5jb25jYXQoYXJyKSA6IFtdO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgLy97IGFkZDogWzEsMl0sIHN1YnRyYWN0OiBbMiw0XSB9XG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZVBsYWluT2JqZWN0cyA9IGZ1bmN0aW9uIChvcGVyYXRpb25zLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICQuZWFjaChvcGVyYXRpb25zLCBmdW5jdGlvbiAob3BuLCBhcmcpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5vcHMucHVzaChvcG4pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0LmFyZ3MucHVzaChfY29uY2F0KGFyZykpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIC8veyBuYW1lOiAnYWRkJywgcGFyYW1zOiBbMV0gfVxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVTdHJ1Y3R1cmVkT2JqZWN0cyA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5vcHMucHVzaChvcGVyYXRpb24ubmFtZSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5hcmdzLnB1c2goX2NvbmNhdChvcGVyYXRpb24ucGFyYW1zKSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZU9iamVjdCA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gKChvcGVyYXRpb24ubmFtZSkgPyBfbm9ybWFsaXplU3RydWN0dXJlZE9iamVjdHMgOiBfbm9ybWFsaXplUGxhaW5PYmplY3RzKShvcGVyYXRpb24sIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVMaXRlcmFscyA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIGFyZ3MsIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5vcHMucHVzaChvcGVyYXRpb24pO1xuICAgICAgICAgICAgICAgIHJldHVybkxpc3QuYXJncy5wdXNoKF9jb25jYXQoYXJncykpO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcblxuXG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZUFycmF5cyA9IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBhcmcsIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgJC5lYWNoKG9wZXJhdGlvbnMsIGZ1bmN0aW9uIChpbmRleCwgb3BuKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qob3BuKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgX25vcm1hbGl6ZU9iamVjdChvcG4sIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgX25vcm1hbGl6ZUxpdGVyYWxzKG9wbiwgYXJnc1tpbmRleF0sIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KG9wZXJhdGlvbnMpKSB7XG4gICAgICAgICAgICAgICAgX25vcm1hbGl6ZU9iamVjdChvcGVyYXRpb25zLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoJC5pc0FycmF5KG9wZXJhdGlvbnMpKSB7XG4gICAgICAgICAgICAgICAgX25vcm1hbGl6ZUFycmF5cyhvcGVyYXRpb25zLCBhcmdzLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgX25vcm1hbGl6ZUxpdGVyYWxzKG9wZXJhdGlvbnMsIGFyZ3MsIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgfSxcblxuICAgICAgICBzcGxpdEdldEZhY3Rvcnk6IGZ1bmN0aW9uIChodHRwT3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgICAgICB2YXIgaHR0cCA9IHRoaXM7XG4gICAgICAgICAgICAgICAgdmFyIGdldFZhbHVlID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZhbHVlID0gb3B0aW9uc1tuYW1lXSB8fCBodHRwT3B0aW9uc1tuYW1lXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSB2YWx1ZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIHZhciBnZXRGaW5hbFVybCA9IGZ1bmN0aW9uIChwYXJhbXMpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHVybCA9IGdldFZhbHVlKCd1cmwnLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGRhdGEgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgICAgIC8vIFRoZXJlIGlzIGVhc3kgKG9yIGtub3duKSB3YXkgdG8gZ2V0IHRoZSBmaW5hbCBVUkwganF1ZXJ5IGlzIGdvaW5nIHRvIHNlbmQgc29cbiAgICAgICAgICAgICAgICAgICAgLy8gd2UncmUgcmVwbGljYXRpbmcgaXQuIFRoZSBwcm9jZXNzIG1pZ2h0IGNoYW5nZSBhdCBzb21lIHBvaW50IGJ1dCBpdCBwcm9iYWJseSB3aWxsIG5vdC5cbiAgICAgICAgICAgICAgICAgICAgLy8gMS4gUmVtb3ZlIGhhc2hcbiAgICAgICAgICAgICAgICAgICAgdXJsID0gdXJsLnJlcGxhY2UoLyMuKiQvLCAnJyk7XG4gICAgICAgICAgICAgICAgICAgIC8vIDEuIEFwcGVuZCBxdWVyeSBzdHJpbmdcbiAgICAgICAgICAgICAgICAgICAgdmFyIHF1ZXJ5UGFyYW1zID0gcXV0aWwudG9RdWVyeUZvcm1hdChkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHF1ZXN0aW9uSWR4ID0gdXJsLmluZGV4T2YoJz8nKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHF1ZXJ5UGFyYW1zICYmIHF1ZXN0aW9uSWR4ID4gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB1cmwgKyAnJicgKyBxdWVyeVBhcmFtcztcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChxdWVyeVBhcmFtcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVybCArICc/JyArIHF1ZXJ5UGFyYW1zO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB1cmw7XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB2YXIgdXJsID0gZ2V0RmluYWxVcmwocGFyYW1zKTtcbiAgICAgICAgICAgICAgICAvLyBXZSBtdXN0IHNwbGl0IHRoZSBHRVQgaW4gbXVsdGlwbGUgc2hvcnQgVVJMJ3NcbiAgICAgICAgICAgICAgICAvLyBUaGUgb25seSBwcm9wZXJ0eSBhbGxvd2VkIHRvIGJlIHNwbGl0IGlzIFwiaW5jbHVkZVwiXG4gICAgICAgICAgICAgICAgaWYgKHBhcmFtcyAmJiBwYXJhbXMuaW5jbHVkZSAmJiB1cmwubGVuZ3RoID4gTUFYX1VSTF9MRU5HVEgpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHBhcmFtc0NvcHkgPSAkLmV4dGVuZCh0cnVlLCB7fSwgcGFyYW1zKTtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHBhcmFtc0NvcHkuaW5jbHVkZTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHVybE5vSW5jbHVkZXMgPSBnZXRGaW5hbFVybChwYXJhbXNDb3B5KTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGRpZmYgPSBNQVhfVVJMX0xFTkdUSCAtIHVybE5vSW5jbHVkZXMubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICB2YXIgb2xkU3VjY2VzcyA9IG9wdGlvbnMuc3VjY2VzcyB8fCBodHRwT3B0aW9ucy5zdWNjZXNzIHx8ICQubm9vcDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9sZEVycm9yID0gb3B0aW9ucy5lcnJvciB8fCBodHRwT3B0aW9ucy5lcnJvciB8fCAkLm5vb3A7XG4gICAgICAgICAgICAgICAgICAgIC8vIHJlbW92ZSB0aGUgb3JpZ2luYWwgc3VjY2VzcyBhbmQgZXJyb3IgY2FsbGJhY2tzXG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuc3VjY2VzcyA9ICQubm9vcDtcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5lcnJvciA9ICQubm9vcDtcblxuICAgICAgICAgICAgICAgICAgICB2YXIgaW5jbHVkZSA9IHBhcmFtcy5pbmNsdWRlO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3VyckluY2x1ZGVzID0gW107XG4gICAgICAgICAgICAgICAgICAgIHZhciBpbmNsdWRlT3B0cyA9IFtjdXJySW5jbHVkZXNdO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3Vyckxlbmd0aCA9ICc/aW5jbHVkZT0nLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZhcmlhYmxlID0gaW5jbHVkZS5wb3AoKTtcbiAgICAgICAgICAgICAgICAgICAgd2hpbGUgKHZhcmlhYmxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVc2UgYSBncmVlZHkgYXBwcm9hY2ggZm9yIG5vdywgY2FuIGJlIG9wdGltaXplZCB0byBiZSBzb2x2ZWQgaW4gYSBtb3JlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBlZmZpY2llbnQgd2F5XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyArIDEgaXMgdGhlIGNvbW1hXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY3Vyckxlbmd0aCArIHZhcmlhYmxlLmxlbmd0aCArIDEgPCBkaWZmKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyckluY2x1ZGVzLnB1c2godmFyaWFibGUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJMZW5ndGggKz0gdmFyaWFibGUubGVuZ3RoICsgMTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyckluY2x1ZGVzID0gW3ZhcmlhYmxlXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlT3B0cy5wdXNoKGN1cnJJbmNsdWRlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3Vyckxlbmd0aCA9ICc/aW5jbHVkZT0nLmxlbmd0aCArIHZhcmlhYmxlLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlID0gaW5jbHVkZS5wb3AoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB2YXIgcmVxcyA9ICQubWFwKGluY2x1ZGVPcHRzLCBmdW5jdGlvbiAoaW5jbHVkZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJlcVBhcmFtcyA9ICQuZXh0ZW5kKHt9LCBwYXJhbXMsIHsgaW5jbHVkZTogaW5jbHVkZSB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChyZXFQYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgJC53aGVuLmFwcGx5KCQsIHJlcXMpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRWFjaCBhcmd1bWVudCBhcmUgYXJyYXlzIG9mIHRoZSBhcmd1bWVudHMgb2YgZWFjaCBkb25lIHJlcXVlc3RcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNvIHRoZSBmaXJzdCBhcmd1bWVudCBvZiB0aGUgZmlyc3QgYXJyYXkgb2YgYXJndW1lbnRzIGlzIHRoZSBkYXRhXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNWYWxpZCA9IGFyZ3VtZW50c1swXSAmJiBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWlzVmFsaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTaG91bGQgbmV2ZXIgaGFwcGVuLi4uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkRXJyb3IoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZHRkLnJlamVjdCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZpcnN0UmVzcG9uc2UgPSBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNPYmplY3QgPSAkLmlzUGxhaW5PYmplY3QoZmlyc3RSZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNSdW5BUEkgPSAoaXNPYmplY3QgJiYgJC5pc1BsYWluT2JqZWN0KGZpcnN0UmVzcG9uc2UudmFyaWFibGVzKSkgfHwgIWlzT2JqZWN0O1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzUnVuQVBJKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzT2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFnZ3JlZ2F0ZSB0aGUgdmFyaWFibGVzIHByb3BlcnR5IG9ubHlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGFnZ3JlZ2F0ZVJ1biA9IGFyZ3VtZW50c1swXVswXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJ1biA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmV4dGVuZCh0cnVlLCBhZ2dyZWdhdGVSdW4udmFyaWFibGVzLCBydW4udmFyaWFibGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlUnVuLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZVJ1biwgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFycmF5IG9mIHJ1bnNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQWdyZWdhdGUgdmFyaWFibGVzIGluIGVhY2ggcnVuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVkUnVucyA9IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2goYXJndW1lbnRzLCBmdW5jdGlvbiAoaWR4LCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcnVucyA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISQuaXNBcnJheShydW5zKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChydW5zLCBmdW5jdGlvbiAoaWR4UnVuLCBydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocnVuLmlkICYmICFhZ2dyZWdhdGVkUnVuc1tydW4uaWRdKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bi52YXJpYWJsZXMgPSBydW4udmFyaWFibGVzIHx8IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyZWdhdGVkUnVuc1tydW4uaWRdID0gcnVuO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAocnVuLmlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZWRSdW5zW3J1bi5pZF0udmFyaWFibGVzLCBydW4udmFyaWFibGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHR1cm4gaXQgaW50byBhbiBhcnJheVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyZWdhdGVkUnVucyA9ICQubWFwKGFnZ3JlZ2F0ZWRSdW5zLCBmdW5jdGlvbiAocnVuKSB7IHJldHVybiBydW47IH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRTdWNjZXNzKGFnZ3JlZ2F0ZWRSdW5zLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZWRSdW5zLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpcyB2YXJpYWJsZXMgQVBJXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWdncmVnYXRlIHRoZSByZXNwb25zZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVkVmFyaWFibGVzID0ge307XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgdmFycyA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIHZhcnMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlZFZhcmlhYmxlcywgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgb2xkRXJyb3IuYXBwbHkoaHR0cCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZWplY3QuYXBwbHkoZHRkLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH07XG59KCkpO1xuIl19 diff --git a/dist/epicenter.min.js b/dist/epicenter.min.js index f8f0590e..98e39325 100644 --- a/dist/epicenter.min.js +++ b/dist/epicenter.min.js @@ -17,7 +17,7 @@ var F={util:{},factory:{},transport:{},store:{},service:{},manager:{strategy:{}} }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./api-version.json":5,"./managers/auth-manager":7,"./managers/epicenter-channel-manager":9,"./managers/run-manager":11,"./managers/run-strategies/always-new-strategy":12,"./managers/run-strategies/conditional-creation-strategy":13,"./managers/run-strategies/identity-strategy":14,"./managers/run-strategies/new-if-initialized-strategy":16,"./managers/run-strategies/new-if-missing-strategy":17,"./managers/run-strategies/new-if-persisted-strategy":18,"./managers/scenario-manager":21,"./managers/world-manager":23,"./service/admin-file-service":24,"./service/asset-api-adapter":25,"./service/auth-api-service":26,"./service/channel-service":27,"./service/configuration-service":28,"./service/data-api-service":29,"./service/member-api-adapter":30,"./service/run-api-service":31,"./service/state-api-adapter":32,"./service/url-config-service":33,"./service/user-api-adapter":34,"./service/variables-api-service":35,"./service/world-api-adapter":36,"./store/cookie-store":37,"./store/store-factory":38,"./transport/ajax-http-transport":39,"./transport/http-transport-factory":40,"./util/inherit":41,"./util/make-sequence":42,"./util/query-util":44,"./util/run-util":45}],7:[function(require,module,exports){ -"use strict";function saveSession(userInfo){var serialized=JSON.stringify(userInfo);store.set(EPI_SESSION_KEY,serialized),store.set(EPI_COOKIE_KEY,userInfo.auth_token)}function getSession(){var session=store.get(EPI_SESSION_KEY)||"{}";return JSON.parse(session)}function AuthManager(options){this.options=$.extend(!0,{},defaults,options);var urlConfig=new ConfigService(this.options).get("server");this.options.account||(this.options.account=urlConfig.accountPath),void 0===this.options.project&&(this.options.project=urlConfig.projectPath),store=new StorageFactory(this.options.store),session=getSession(),token=store.get(EPI_COOKIE_KEY)||"",this.authAdapter=new AuthAdapter(this.options,{token:session.auth_token})}var ConfigService=require("../service/configuration-service");var AuthAdapter=require("../service/auth-api-service");var MemberAdapter=require("../service/member-api-adapter");var StorageFactory=require("../store/store-factory");var Buffer=require("buffer").Buffer;var keyNames=require("./key-names");var defaults={store:{synchronous:!0}};var EPI_COOKIE_KEY=keyNames.EPI_COOKIE_KEY;var EPI_SESSION_KEY=keyNames.EPI_SESSION_KEY;var store;var token;var session;var _findUserInGroup=function(members,id){for(var j=0;j1&&groupId){var filteredGroups=$.grep(memberInfo,function(resGroup){return resGroup.groupId===groupId});group=1===filteredGroups.length?filteredGroups[0]:null}if(group){var groupSelection=group.groupId;data.groupSelection[adapterOptions.project]=groupSelection;var sessionInfoWithGroup=$.extend({},sessionInfo,{groupId:group.groupId,groupName:group.name,isFac:"facilitator"===_findUserInGroup(group.members,userInfo.user_id).role});saveSession(sessionInfoWithGroup),outSuccess.apply(this,[data]),$d.resolve(data)}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)};return adapterOptions.success=handleSuccess,adapterOptions.error=function(response){return adapterOptions.account?(adapterOptions.account=null,adapterOptions.error=function(){outError.apply(this,arguments),$d.reject(response)},void _this.authAdapter.login(adapterOptions)):(outError.apply(this,arguments),void $d.reject(response))},this.authAdapter.login(adapterOptions),$d.promise()},logout:function(options){var adapterOptions=$.extend(!0,{token:token},this.options,options);var removeCookieFn=function(response){store.remove(EPI_COOKIE_KEY,adapterOptions),store.remove(EPI_SESSION_KEY,adapterOptions),token=""};return this.authAdapter.logout(adapterOptions).done(removeCookieFn)},getToken:function(options){var httpOptions=$.extend(!0,this.options,options);var $d=$.Deferred();return token?$d.resolve(token):this.login(httpOptions).then($d.resolve),$d.promise()},getUserGroups:function(params,options){var adapterOptions=$.extend(!0,{success:$.noop},this.options,options);var $d=$.Deferred();var outSuccess=adapterOptions.success;adapterOptions.success=function(memberInfo){adapterOptions.project&&(memberInfo=$.grep(memberInfo,function(group){return group.project===adapterOptions.project})),outSuccess.apply(this,[memberInfo]),$d.resolve(memberInfo)};var memberAdapter=new MemberAdapter({token:params.token});return memberAdapter.getGroupsForUser(params,adapterOptions).fail($d.reject),$d.promise()},getCurrentUserSessionInfo:function(options){return getSession(options)}}),module.exports=AuthManager; +"use strict";function saveSession(userInfo,store){var serialized=JSON.stringify(userInfo);store.set(EPI_SESSION_KEY,serialized),store.set(EPI_COOKIE_KEY,userInfo.auth_token)}function getSession(store){var session=store.get(EPI_SESSION_KEY)||"{}";return JSON.parse(session)}function AuthManager(options){this.options=$.extend(!0,{},defaults,options);var urlConfig=new ConfigService(this.options).get("server");this.isLocal=urlConfig.isLocalhost(),this.options.account||(this.options.account=urlConfig.accountPath),void 0===this.options.project&&(this.options.project=urlConfig.projectPath),this.store=new StorageFactory(this.options.store),session=getSession(this.store),token=this.store.get(EPI_COOKIE_KEY)||"",this.authAdapter=new AuthAdapter(this.options,{token:session.auth_token})}var ConfigService=require("../service/configuration-service");var AuthAdapter=require("../service/auth-api-service");var MemberAdapter=require("../service/member-api-adapter");var StorageFactory=require("../store/store-factory");var Buffer=require("buffer").Buffer;var keyNames=require("./key-names");var defaults={store:{synchronous:!0}};var EPI_COOKIE_KEY=keyNames.EPI_COOKIE_KEY;var EPI_SESSION_KEY=keyNames.EPI_SESSION_KEY;var token;var session;var _findUserInGroup=function(members,id){for(var j=0;j1&&groupId){var filteredGroups=$.grep(memberInfo,function(resGroup){return resGroup.groupId===groupId});group=1===filteredGroups.length?filteredGroups[0]:null}if(group){var groupSelection=group.groupId;data.groupSelection[adapterOptions.project]=groupSelection;var sessionInfoWithGroup=$.extend({},sessionInfo,{groupId:group.groupId,groupName:group.name,isFac:"facilitator"===_findUserInGroup(group.members,userInfo.user_id).role});saveSession(sessionInfoWithGroup,_this.store),outSuccess.apply(this,[data]),$d.resolve(data)}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)};return adapterOptions.success=handleSuccess,adapterOptions.error=function(response){return adapterOptions.account?(adapterOptions.account=null,adapterOptions.error=function(){outError.apply(this,arguments),$d.reject(response)},void _this.authAdapter.login(adapterOptions)):(outError.apply(this,arguments),void $d.reject(response))},this.authAdapter.login(adapterOptions),$d.promise()},logout:function(options){var _this=this;var adapterOptions=$.extend(!0,{token:token},this.options,options);var removeCookieFn=function(response){_this.store.remove(EPI_COOKIE_KEY,adapterOptions),_this.store.remove(EPI_SESSION_KEY,adapterOptions),token=""};return this.authAdapter.logout(adapterOptions).done(removeCookieFn)},getToken:function(options){var httpOptions=$.extend(!0,this.options,options);var $d=$.Deferred();return token?$d.resolve(token):this.login(httpOptions).then($d.resolve),$d.promise()},getUserGroups:function(params,options){var adapterOptions=$.extend(!0,{success:$.noop},this.options,options);var $d=$.Deferred();var outSuccess=adapterOptions.success;adapterOptions.success=function(memberInfo){adapterOptions.project&&(memberInfo=$.grep(memberInfo,function(group){return group.project===adapterOptions.project})),outSuccess.apply(this,[memberInfo]),$d.resolve(memberInfo)};var memberAdapter=new MemberAdapter({token:params.token});return memberAdapter.getGroupsForUser(params,adapterOptions).fail($d.reject),$d.promise()},getCurrentUserSessionInfo:function(options){return getSession(this.store,options)}}),module.exports=AuthManager; },{"../service/auth-api-service":26,"../service/configuration-service":28,"../service/member-api-adapter":30,"../store/store-factory":38,"./key-names":10,"buffer":1}],8:[function(require,module,exports){ "use strict";var Channel=require("../service/channel-service");var ChannelManager=function(options){if(!$.cometd)throw new Error("Cometd library not found. Please include epicenter-multiplayer-dependencies.js");if(!options||!options.url)throw new Error("Please provide an url for the cometd server");var defaults={url:"",logLevel:"info",websocketEnabled:!1,shareConnection:!1,channel:{}};var defaultCometOptions=$.extend(!0,{},defaults,options);if(this.currentSubscriptions=[],this.options=defaultCometOptions,defaultCometOptions.shareConnection&&ChannelManager.prototype._cometd)return this.cometd=ChannelManager.prototype._cometd,this;var cometd=new $.Cometd;ChannelManager.prototype._cometd=cometd,cometd.websocketEnabled=defaultCometOptions.websocketEnabled,this.isConnected=!1;var connectionBroken=function(message){$(this).trigger("disconnect",message)};var connectionSucceeded=function(message){$(this).trigger("connect",message)};var me=this;cometd.configure(defaultCometOptions),cometd.addListener("/meta/connect",function(message){var wasConnected=this.isConnected;this.isConnected=message.successful===!0,!wasConnected&&this.isConnected?connectionSucceeded.call(this,message):wasConnected&&!this.isConnected&&connectionBroken.call(this,message)}.bind(this)),cometd.addListener("/meta/disconnect",connectionBroken),cometd.addListener("/meta/handshake",function(message){message.successful&&cometd.batch(function(){$(me.currentSubscriptions).each(function(index,subs){cometd.resubscribe(subs)})})}),cometd.addListener("/meta/subscribe",function(message){$(me).trigger("subscribe",message)}),cometd.addListener("/meta/unsubscribe",function(message){$(me).trigger("unsubscribe",message)}),cometd.addListener("/meta/publish",function(message){$(me).trigger("publish",message)}),cometd.addListener("/meta/unsuccessful",function(message){$(me).trigger("error",message)}),cometd.handshake(),this.cometd=cometd};ChannelManager.prototype=$.extend(ChannelManager.prototype,{getChannel:function(options){options&&!$.isPlainObject(options)&&(options={base:options});var defaults={transport:this.cometd};var channel=new Channel($.extend(!0,{},this.options.channel,defaults,options));var subs=channel.subscribe;channel.subscribe=function(){var subid=subs.apply(channel,arguments);return this.currentSubscriptions=this.currentSubscriptions.concat(subid),subid}.bind(this);var unsubs=channel.unsubscribe;return channel.unsubscribe=function(){var removed=unsubs.apply(channel,arguments);for(var i=0;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.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","/**\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 && 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 = '?include='.length;\n var variable = include.pop();\n while (variable) {\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 + variable.length + 1 < diff) {\n currIncludes.push(variable);\n currLength += variable.length + 1;\n } else {\n currIncludes = [variable];\n includeOpts.push(currIncludes);\n currLength = '?include='.length + variable.length;\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 StorageFactory = require('../store/store-factory');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n // config || (config = configService.get());\n var store = new StorageFactory({ synchronous: true });\n\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: store.get('epicenter.project.token') || store.get('epicenter.token') || '',\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: '',\n\n /**\n * The project id. Defaults to empty string.\n * @type {String}\n */\n project: '',\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 var serviceOptions = $.extend({}, 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 {String} `folderType` One of Model|Static|Node\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getContents: function (filePath, folderType, options) {\n var path = 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 $.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 StorageFactory = require('../store/store-factory');\nvar qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n\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: '',\n\n /**\n * The project id. Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: '',\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: store.get('epicenter.project.token') || '',\n\n domain: 'forio.com',\n\n //Options to pass on to the underlying transport layer\n transport: {}\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 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 methods for logging in and logging out. On login, this service 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 * auth.logout();\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 /**\n * Logs user out from specified accounts.\n * Epicenter logout is not implemented yet, added 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 * ##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');\nvar StorageFactory = require('../store/store-factory');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\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 store = new StorageFactory({ synchronous: true });\n\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: store.get('epicenter.project.token') || '',\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 var serviceOptions = $.extend({}, 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 // 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 $.extend(params, _pick(serviceOptions, ['account', 'project', 'group']));\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 * ##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 apiEndpoint = 'model/state';\n\nmodule.exports = function (config) {\n\n var defaults = {\n\n };\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(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","'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 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: '',\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: '',\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 var serviceOptions = $.extend({}, 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 _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: '',\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: '',\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(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 StorageFactory = require('../store/store-factory');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar keyNames = require('../managers/key-names');\n\nvar apiEndpoint = 'asset';\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n var session = JSON.parse(store.get(keyNames.EPI_SESSION_KEY) || '{}');\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: store.get(keyNames.EPI_COOKIE_KEY) || '',\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: session.groupName,\n /**\n * The user id. Defaults to session's `userId`.\n * @type {String}\n */\n userId: session.userId,\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 var serviceOptions = $.extend(true, {}, 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\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Name of collection\n * @type { string}\n */\n root: '/',\n\n domain: '.forio.com'\n };\n var 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, {}, serviceOptions, options);\n\n var domain = setOptions.domain;\n var path = setOptions.root;\n\n document.cookie = encodeURIComponent(key) + '=' +\n encodeURIComponent(value) +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '');\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 cookieReg = new RegExp('(?:(?:^|.*;)\\\\s*' + encodeURIComponent(key).replace(/[\\-\\.\\+\\*]/g, '\\\\$&') + '\\\\s*\\\\=\\\\s*([^;]*).*$)|^.*$');\n var val = document.cookie.replace(cookieReg, '$1');\n val = decodeURIComponent(val) || 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, {}, serviceOptions, options);\n\n var domain = remOptions.domain;\n var path = remOptions.root;\n\n document.cookie = encodeURIComponent(key) +\n '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '');\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 aKeys = document.cookie.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 ConfigService = require('../service/configuration-service');\nvar AuthAdapter = require('../service/auth-api-service');\nvar MemberAdapter = require('../service/member-api-adapter');\nvar StorageFactory = require('../store/store-factory');\nvar Buffer = require('buffer').Buffer;\nvar keyNames = require('./key-names');\n\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 EPI_COOKIE_KEY = keyNames.EPI_COOKIE_KEY;\nvar EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY;\nvar store;\nvar token;\nvar session;\n\nfunction saveSession(userInfo) {\n var serialized = JSON.stringify(userInfo);\n store.set(EPI_SESSION_KEY, serialized);\n\n //jshint camelcase: false\n //jscs:disable\n store.set(EPI_COOKIE_KEY, userInfo.auth_token);\n}\n\nfunction getSession() {\n var session = store.get(EPI_SESSION_KEY) || '{}';\n return JSON.parse(session);\n}\n\nfunction AuthManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n var urlConfig = new ConfigService(this.options).get('server');\n if (!this.options.account) {\n this.options.account = urlConfig.accountPath;\n }\n\n // null might specified to disable project filtering\n if (this.options.project === undefined) {\n this.options.project = urlConfig.projectPath;\n }\n\n store = new StorageFactory(this.options.store);\n session = getSession();\n token = store.get(EPI_COOKIE_KEY) || '';\n //jshint camelcase: false\n //jscs:disable\n this.authAdapter = new AuthAdapter(this.options, { token: session.auth_token });\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 groupSelection = group.groupId;\n data.groupSelection[adapterOptions.project] = groupSelection;\n var sessionInfoWithGroup = $.extend({}, sessionInfo, {\n 'groupId': group.groupId,\n 'groupName': group.name,\n 'isFac': _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator'\n });\n saveSession(sessionInfoWithGroup);\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.\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 adapterOptions = $.extend(true, { token: token }, this.options, options);\n\n var removeCookieFn = function (response) {\n store.remove(EPI_COOKIE_KEY, adapterOptions);\n store.remove(EPI_SESSION_KEY, adapterOptions);\n token = '';\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 = $.extend(true, this.options, options);\n\n var $d = $.Deferred();\n if (token) {\n $d.resolve(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 = $.extend(true, { success: $.noop }, this.options, 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 * By default, session information is stored in a cookie in the browser. You can change this with the `store` configuration option. \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 getSession(options);\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 * * `server` Object with details about the Epicenter project for this Epicenter Channel Manager instance.\n * * `server.account` The Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `server.project` Epicenter project id.\n */\n\nvar ChannelManager = require('./channel-manager');\nvar classFrom = require('../util/inherit');\nvar urlService = require('../service/url-config-service');\n\nvar AuthManager = require('./auth-manager');\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 var userInfo = session.getCurrentUserSessionInfo();\n\n var defaults = {\n account: userInfo.account,\n project: userInfo.project,\n };\n var defaultCometOptions = $.extend(true, {}, defaults, userInfo, 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 this.options = defaultCometOptions;\n return __super.constructor.call(this, defaultCometOptions);\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');\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');\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');\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/users', 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');\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/users', 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 gc = cm.getDataChannel('survey-responses');\n * gc.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","'use strict';\n\nmodule.exports = {\n EPI_COOKIE_KEY: 'epicenter.project.token',\n EPI_SESSION_KEY: 'epicenter.user.session',\n STRATEGY_SESSION_KEY: 'epicenter-scenario'\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');\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 var defaultCometOptions = $.extend(true, {}, 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();\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","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\nvar base64 = require('base64-js')\nvar ieee754 = require('ieee754')\nvar isArray = require('is-array')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\nBuffer.poolSize = 8192 // not used by this implementation\n\nvar rootParent = {}\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 * - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property\n * on objects.\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\nfunction typedArraySupport () {\n function Bar () {}\n try {\n var arr = new Uint8Array(1)\n arr.foo = function () { return 42 }\n arr.constructor = Bar\n return arr.foo() === 42 && // typed array instances can be augmented\n arr.constructor === Bar && // constructor can be set\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\n/**\n * Class: Buffer\n * =============\n *\n * The Buffer constructor returns instances of `Uint8Array` that are augmented\n * with function properties for all the node `Buffer` API functions. We use\n * `Uint8Array` so that square bracket notation works as expected -- it returns\n * a single octet.\n *\n * By augmenting the instances, we can avoid modifying the `Uint8Array`\n * prototype.\n */\nfunction Buffer (arg) {\n if (!(this instanceof Buffer)) {\n // Avoid going through an ArgumentsAdaptorTrampoline in the common case.\n if (arguments.length > 1) return new Buffer(arg, arguments[1])\n return new Buffer(arg)\n }\n\n this.length = 0\n this.parent = undefined\n\n // Common case.\n if (typeof arg === 'number') {\n return fromNumber(this, arg)\n }\n\n // Slightly less common case.\n if (typeof arg === 'string') {\n return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8')\n }\n\n // Unusual.\n return fromObject(this, arg)\n}\n\nfunction fromNumber (that, length) {\n that = allocate(that, length < 0 ? 0 : checked(length) | 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) {\n for (var i = 0; i < length; i++) {\n that[i] = 0\n }\n }\n return that\n}\n\nfunction fromString (that, string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8'\n\n // Assumption: byteLength() return value is always < kMaxLength.\n var length = byteLength(string, encoding) | 0\n that = allocate(that, length)\n\n that.write(string, encoding)\n return that\n}\n\nfunction fromObject (that, object) {\n if (Buffer.isBuffer(object)) return fromBuffer(that, object)\n\n if (isArray(object)) return fromArray(that, object)\n\n if (object == null) {\n throw new TypeError('must start with number, buffer, array or string')\n }\n\n if (typeof ArrayBuffer !== 'undefined') {\n if (object.buffer instanceof ArrayBuffer) {\n return fromTypedArray(that, object)\n }\n if (object instanceof ArrayBuffer) {\n return fromArrayBuffer(that, object)\n }\n }\n\n if (object.length) return fromArrayLike(that, object)\n\n return fromJsonObject(that, object)\n}\n\nfunction fromBuffer (that, buffer) {\n var length = checked(buffer.length) | 0\n that = allocate(that, length)\n buffer.copy(that, 0, 0, length)\n return that\n}\n\nfunction fromArray (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\n// Duplicate of fromArray() to keep fromArray() monomorphic.\nfunction fromTypedArray (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n // Truncating the elements is probably not what people expect from typed\n // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior\n // of the old Buffer constructor.\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) {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n array.byteLength\n that = Buffer._augment(new Uint8Array(array))\n } else {\n // Fallback: Return an object instance of the Buffer class\n that = fromTypedArray(that, new Uint8Array(array))\n }\n return that\n}\n\nfunction fromArrayLike (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\n// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object.\n// Returns a zero-length buffer for inputs that don't conform to the spec.\nfunction fromJsonObject (that, object) {\n var array\n var length = 0\n\n if (object.type === 'Buffer' && isArray(object.data)) {\n array = object.data\n length = checked(array.length) | 0\n }\n that = allocate(that, length)\n\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n Buffer.prototype.__proto__ = Uint8Array.prototype\n Buffer.__proto__ = Uint8Array\n}\n\nfunction allocate (that, length) {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = Buffer._augment(new Uint8Array(length))\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n that.length = length\n that._isBuffer = true\n }\n\n var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1\n if (fromPool) that.parent = rootParent\n\n return that\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 (subject, encoding) {\n if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding)\n\n var buf = new Buffer(subject, encoding)\n delete buf.parent\n return buf\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 var i = 0\n var len = Math.min(x, y)\n while (i < len) {\n if (a[i] !== b[i]) break\n\n ++i\n }\n\n if (i !== len) {\n x = a[i]\n y = b[i]\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)) throw new TypeError('list argument must be an Array of Buffers.')\n\n if (list.length === 0) {\n return new Buffer(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 buf = new Buffer(length)\n var pos = 0\n for (i = 0; i < list.length; i++) {\n var item = list[i]\n item.copy(buf, pos)\n pos += item.length\n }\n return buf\n}\n\nfunction byteLength (string, encoding) {\n if (typeof string !== 'string') string = '' + string\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 // Deprecated\n case 'raw':\n case 'raws':\n return len\n case 'utf8':\n case 'utf-8':\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\n// pre-set for values that may exist in the future\nBuffer.prototype.length = undefined\nBuffer.prototype.parent = undefined\n\nfunction slowToString (encoding, start, end) {\n var loweredCase = false\n\n start = start | 0\n end = end === undefined || end === Infinity ? this.length : end | 0\n\n if (!encoding) encoding = 'utf8'\n if (start < 0) start = 0\n if (end > this.length) end = this.length\n if (end <= start) return ''\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\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 (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return 0\n return Buffer.compare(this, b)\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset) {\n if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff\n else if (byteOffset < -0x80000000) byteOffset = -0x80000000\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 if (val.length === 0) return -1 // special case: looking for empty string always fails\n return String.prototype.indexOf.call(this, val, byteOffset)\n }\n if (Buffer.isBuffer(val)) {\n return arrayIndexOf(this, val, byteOffset)\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)\n }\n\n function arrayIndexOf (arr, val, byteOffset) {\n var foundIndex = -1\n for (var i = 0; byteOffset + i < arr.length; i++) {\n if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) {\n if (foundIndex === -1) foundIndex = i\n if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex\n } else {\n foundIndex = -1\n }\n }\n return -1\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\n// `get` is deprecated\nBuffer.prototype.get = function get (offset) {\n console.log('.get() is deprecated. Access using array indexes instead.')\n return this.readUInt8(offset)\n}\n\n// `set` is deprecated\nBuffer.prototype.set = function set (v, offset) {\n console.log('.set() is deprecated. Access using array indexes instead.')\n return this.writeUInt8(v, offset)\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)) throw new Error('Invalid hex string')\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 var swap = encoding\n encoding = offset\n offset = length | 0\n length = swap\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 = Buffer._augment(this.subarray(start, end))\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 if (newBuf.length) newBuf.parent = this.parent || this\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 must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('value 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) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\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) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\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 = value < 0 ? 1 : 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\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 = value < 0 ? 1 : 0\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\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 (value > max || value < min) throw new RangeError('value is out of bounds')\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 target._set(this.subarray(start, start + len), targetStart)\n }\n\n return len\n}\n\n// fill(value, start=0, end=buffer.length)\nBuffer.prototype.fill = function fill (value, start, end) {\n if (!value) value = 0\n if (!start) start = 0\n if (!end) end = this.length\n\n if (end < start) throw new RangeError('end < start')\n\n // Fill 0 bytes; we're done\n if (end === start) return\n if (this.length === 0) return\n\n if (start < 0 || start >= this.length) throw new RangeError('start out of bounds')\n if (end < 0 || end > this.length) throw new RangeError('end out of bounds')\n\n var i\n if (typeof value === 'number') {\n for (i = start; i < end; i++) {\n this[i] = value\n }\n } else {\n var bytes = utf8ToBytes(value.toString())\n var len = bytes.length\n for (i = start; i < end; i++) {\n this[i] = bytes[i % len]\n }\n }\n\n return this\n}\n\n/**\n * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.\n * Added in Node 0.12. Only available in browsers that support ArrayBuffer.\n */\nBuffer.prototype.toArrayBuffer = function toArrayBuffer () {\n if (typeof Uint8Array !== 'undefined') {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n return (new Buffer(this)).buffer\n } else {\n var buf = new Uint8Array(this.length)\n for (var i = 0, len = buf.length; i < len; i += 1) {\n buf[i] = this[i]\n }\n return buf.buffer\n }\n } else {\n throw new TypeError('Buffer.toArrayBuffer not supported in this browser')\n }\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar BP = Buffer.prototype\n\n/**\n * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods\n */\nBuffer._augment = function _augment (arr) {\n arr.constructor = Buffer\n arr._isBuffer = true\n\n // save reference to original Uint8Array set method before overwriting\n arr._set = arr.set\n\n // deprecated\n arr.get = BP.get\n arr.set = BP.set\n\n arr.write = BP.write\n arr.toString = BP.toString\n arr.toLocaleString = BP.toString\n arr.toJSON = BP.toJSON\n arr.equals = BP.equals\n arr.compare = BP.compare\n arr.indexOf = BP.indexOf\n arr.copy = BP.copy\n arr.slice = BP.slice\n arr.readUIntLE = BP.readUIntLE\n arr.readUIntBE = BP.readUIntBE\n arr.readUInt8 = BP.readUInt8\n arr.readUInt16LE = BP.readUInt16LE\n arr.readUInt16BE = BP.readUInt16BE\n arr.readUInt32LE = BP.readUInt32LE\n arr.readUInt32BE = BP.readUInt32BE\n arr.readIntLE = BP.readIntLE\n arr.readIntBE = BP.readIntBE\n arr.readInt8 = BP.readInt8\n arr.readInt16LE = BP.readInt16LE\n arr.readInt16BE = BP.readInt16BE\n arr.readInt32LE = BP.readInt32LE\n arr.readInt32BE = BP.readInt32BE\n arr.readFloatLE = BP.readFloatLE\n arr.readFloatBE = BP.readFloatBE\n arr.readDoubleLE = BP.readDoubleLE\n arr.readDoubleBE = BP.readDoubleBE\n arr.writeUInt8 = BP.writeUInt8\n arr.writeUIntLE = BP.writeUIntLE\n arr.writeUIntBE = BP.writeUIntBE\n arr.writeUInt16LE = BP.writeUInt16LE\n arr.writeUInt16BE = BP.writeUInt16BE\n arr.writeUInt32LE = BP.writeUInt32LE\n arr.writeUInt32BE = BP.writeUInt32BE\n arr.writeIntLE = BP.writeIntLE\n arr.writeIntBE = BP.writeIntBE\n arr.writeInt8 = BP.writeInt8\n arr.writeInt16LE = BP.writeInt16LE\n arr.writeInt16BE = BP.writeInt16BE\n arr.writeInt32LE = BP.writeInt32LE\n arr.writeInt32BE = BP.writeInt32BE\n arr.writeFloatLE = BP.writeFloatLE\n arr.writeFloatBE = BP.writeFloatBE\n arr.writeDoubleLE = BP.writeDoubleLE\n arr.writeDoubleBE = BP.writeDoubleBE\n arr.fill = BP.fill\n arr.inspect = BP.inspect\n arr.toArrayBuffer = BP.toArrayBuffer\n\n return arr\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","'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","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 lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n;(function (exports) {\n\t'use strict';\n\n var Arr = (typeof Uint8Array !== 'undefined')\n ? Uint8Array\n : Array\n\n\tvar PLUS = '+'.charCodeAt(0)\n\tvar SLASH = '/'.charCodeAt(0)\n\tvar NUMBER = '0'.charCodeAt(0)\n\tvar LOWER = 'a'.charCodeAt(0)\n\tvar UPPER = 'A'.charCodeAt(0)\n\tvar PLUS_URL_SAFE = '-'.charCodeAt(0)\n\tvar SLASH_URL_SAFE = '_'.charCodeAt(0)\n\n\tfunction decode (elt) {\n\t\tvar code = elt.charCodeAt(0)\n\t\tif (code === PLUS ||\n\t\t code === PLUS_URL_SAFE)\n\t\t\treturn 62 // '+'\n\t\tif (code === SLASH ||\n\t\t code === SLASH_URL_SAFE)\n\t\t\treturn 63 // '/'\n\t\tif (code < NUMBER)\n\t\t\treturn -1 //no match\n\t\tif (code < NUMBER + 10)\n\t\t\treturn code - NUMBER + 26 + 26\n\t\tif (code < UPPER + 26)\n\t\t\treturn code - UPPER\n\t\tif (code < LOWER + 26)\n\t\t\treturn code - LOWER + 26\n\t}\n\n\tfunction b64ToByteArray (b64) {\n\t\tvar i, j, l, tmp, placeHolders, arr\n\n\t\tif (b64.length % 4 > 0) {\n\t\t\tthrow new Error('Invalid string. Length must be a multiple of 4')\n\t\t}\n\n\t\t// the number of equal signs (place holders)\n\t\t// if there are two placeholders, than the two characters before it\n\t\t// represent one byte\n\t\t// if there is only one, then the three characters before it represent 2 bytes\n\t\t// this is just a cheap hack to not do indexOf twice\n\t\tvar len = b64.length\n\t\tplaceHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0\n\n\t\t// base64 is 4/3 + up to two characters of the original data\n\t\tarr = new Arr(b64.length * 3 / 4 - placeHolders)\n\n\t\t// if there are placeholders, only get up to the last complete 4 chars\n\t\tl = placeHolders > 0 ? b64.length - 4 : b64.length\n\n\t\tvar L = 0\n\n\t\tfunction push (v) {\n\t\t\tarr[L++] = v\n\t\t}\n\n\t\tfor (i = 0, j = 0; i < l; i += 4, j += 3) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))\n\t\t\tpush((tmp & 0xFF0000) >> 16)\n\t\t\tpush((tmp & 0xFF00) >> 8)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\tif (placeHolders === 2) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)\n\t\t\tpush(tmp & 0xFF)\n\t\t} else if (placeHolders === 1) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)\n\t\t\tpush((tmp >> 8) & 0xFF)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\treturn arr\n\t}\n\n\tfunction uint8ToBase64 (uint8) {\n\t\tvar i,\n\t\t\textraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes\n\t\t\toutput = \"\",\n\t\t\ttemp, length\n\n\t\tfunction encode (num) {\n\t\t\treturn lookup.charAt(num)\n\t\t}\n\n\t\tfunction tripletToBase64 (num) {\n\t\t\treturn encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)\n\t\t}\n\n\t\t// go through the array every three bytes, we'll deal with trailing stuff later\n\t\tfor (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {\n\t\t\ttemp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])\n\t\t\toutput += tripletToBase64(temp)\n\t\t}\n\n\t\t// pad the end with zeros, but make sure to not forget the extra bytes\n\t\tswitch (extraBytes) {\n\t\t\tcase 1:\n\t\t\t\ttemp = uint8[uint8.length - 1]\n\t\t\t\toutput += encode(temp >> 2)\n\t\t\t\toutput += encode((temp << 4) & 0x3F)\n\t\t\t\toutput += '=='\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\ttemp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])\n\t\t\t\toutput += encode(temp >> 10)\n\t\t\t\toutput += encode((temp >> 4) & 0x3F)\n\t\t\t\toutput += encode((temp << 2) & 0x3F)\n\t\t\t\toutput += '='\n\t\t\t\tbreak\n\t\t}\n\n\t\treturn output\n\t}\n\n\texports.toByteArray = b64ToByteArray\n\texports.fromByteArray = uint8ToBase64\n}(typeof exports === 'undefined' ? (this.base64js = {}) : exports))\n","\n/**\n * isArray\n */\n\nvar isArray = Array.isArray;\n\n/**\n * toString\n */\n\nvar str = Object.prototype.toString;\n\n/**\n * Whether or not the given `val`\n * is an array.\n *\n * example:\n *\n * isArray([]);\n * // > true\n * isArray(arguments);\n * // > false\n * isArray('');\n * // > false\n *\n * @param {mixed} val\n * @return {bool}\n */\n\nmodule.exports = isArray || function (val) {\n return !! val && '[object Array]' == str.call(val);\n};\n"]} \ No newline at end of file +{"version":3,"sources":["node_modules/grunt-browserify/node_modules/browserify/node_modules/browser-pack/_prelude.js","src/api-version.json","src/app.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/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/managers/key-names.js","src/managers/special-operations.js","src/managers/channel-manager.js","src/managers/run-strategies/strategies-map.js","node_modules/grunt-browserify/node_modules/browserify/node_modules/buffer/index.js","src/managers/run-strategies/multiplayer-strategy.js","src/managers/run-strategies/persistent-single-player-strategy.js","node_modules/grunt-browserify/node_modules/browserify/node_modules/buffer/node_modules/ieee754/index.js","node_modules/grunt-browserify/node_modules/browserify/node_modules/buffer/node_modules/base64-js/lib/b64.js","node_modules/grunt-browserify/node_modules/browserify/node_modules/buffer/node_modules/is-array/index.js"],"names":["F","util","factory","transport","store","service","manager","strategy","query","require","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","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","extend","addTrailingSlash","url","length","_w","val","then","p","Deferred","resolve","promise","seq","next","cur","list","splice","Array","prototype","slice","apply","arguments","seed","fail","MakeSeq","obj","res","__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","dtd","paramsCopy","urlNoIncludes","diff","oldSuccess","success","noop","oldError","error","currIncludes","includeOpts","currLength","variable","pop","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","ajax","publicAPI","ajaxOptions","splitGet","post","patch","put","delete","delimiter","head","epiVersion","API_PROTOCOL","HOST_API_MAPPING","forio.com","foriodev.com","publicExports","protocol","host","window","location","appPath","path","pathname","accountPath","accnt","projectPath","prj","versionPath","isLocalhost","getAPIPath","PROJECT_APIS","apiPath","urlService","serviceOptions","server","setEnv","env","property","set","ConfigService","StorageFactory","rutil","_pick","TransportFactory","VariablesService","synchronous","token","account","project","filter","autoRestore","urlConfig","getFilterURL","addAutoRestoreHeader","isFilterRunId","autorestoreOpts","X-AutoRestore","Authorization","setFilterOrThrowError","Error","publicAsyncAPI","create","createOptions","runApiParams","model","outputModifier","load","runID","filters","save","attributes","do","opsArgs","postOptions","prms","serial","opParams","me","$d","doSingleOp","op","shift","parallel","queue","i","done","publicSyncAPI","getCurrentConfig","vs","runService","getContents","filePath","folderType","getURL","attrs","root","domain","q","saveAs","remove","keys","userName","password","login","resp","status","statusMessage","postParams","logout","apiEndpoint","parseRunIdOrError","runId","replay","replayOptions","action","clone","apiBase","assignmentEndpoint","projectEndpoint","group","setIdFilterOrThrowError","validateModelOrThrowError","worldApiParams","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","keyNames","session","parse","EPI_SESSION_KEY","EPI_COOKIE_KEY","scope","fullUrl","processData","assetApiParams","scopeConfig","validateFilename","filename","validateUrlParams","partKeys","buildUrl","parts","upload","toLowerCase","FormData","urlOptions","getServiceOptions","files","fullPathFiles","file","assetUrl","setOptions","document","cookie","encodeURIComponent","cookieReg","RegExp","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","saveSession","userInfo","serialized","auth_token","getSession","isLocal","authAdapter","AuthAdapter","MemberAdapter","Buffer","_findUserInGroup","members","adapterOptions","outSuccess","outError","accountName","projectName","decodeToken","encoded","decode","atob","toString","handleGroupError","message","statusText","handleSuccess","access_token","userGroupOpts","getUserGroups","user_id","memberInfo","auth","userGroups","groupSelection","sessionInfo","filteredGroups","grep","resGroup","sessionInfoWithGroup","isFac","role","removeCookieFn","getToken","memberAdapter","getCurrentUserSessionInfo","buildStrategy","worldApi","WorldApi","world","_auth","getCurrentWorld","getCurrentRun","getAndRestoreLatestRun","currentWorldId","runOpts","rm","curUserId","curGroupName","getFromSettingsOrSessionOrError","sessionKeyName","EpicenterChannelManager","defaultCometOptions","urlOpts","getGroupChannel","baseTopic","getChannel","getWorldChannel","worldid","getUserChannel","userid","getPresenceChannel","channel","lastPingTime","PING_INTERVAL","subscribe","notification","incomingUserId","trigger","online","valueOf","setInterval","publish","now","getDataChannel","collection","oldsubs","topic","callback","context","callbackWithCleanData","payload","subType","date","actualData","topicResolver","channelOptions","makeName","channelName","newName","topics","subscriptionIds","opts","batch","returnObjs","warn","unsubscribe","on","event","off","ConditionalStrategy","Strategy","createIf","setRunInSession","sessionKey","sessionStore","makeSeq","Base","SessionStore","UrlService","STRATEGY_SESSION_KEY","condition","runOptions","runOptionsWithScope","userSession","freshlyCreated","runSession","_loadAndCheck","shouldCreate","msg","getResponseHeader","initialized","cometd","websocketEnabled","shareConnection","currentSubscriptions","_cometd","Cometd","isConnected","connectionBroken","connectionSucceeded","configure","addListener","wasConnected","successful","subs","resubscribe","handshake","subid","unsubs","removed","new-if-initialized","new-if-persisted","new-if-missing","always-new","multiplayer","persistent-single-player","none","typedArraySupport","Bar","Uint8Array","foo","subarray","byteLength","e","kMaxLength","TYPED_ARRAY_SUPPORT","fromNumber","fromString","fromObject","that","allocate","checked","string","encoding","write","object","isBuffer","fromBuffer","fromArray","TypeError","ArrayBuffer","buffer","fromTypedArray","fromArrayBuffer","fromArrayLike","fromJsonObject","copy","array","_augment","__proto__","_isBuffer","fromPool","poolSize","rootParent","RangeError","SlowBuffer","subject","buf","len","loweredCase","utf8ToBytes","base64ToBytes","slowToString","end","Infinity","hexSlice","utf8Slice","asciiSlice","binarySlice","base64Slice","utf16leSlice","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","ext","checkInt","max","objectWriteUInt16","littleEndian","objectWriteUInt32","checkIEEE754","writeFloat","noAssert","ieee754","writeDouble","base64clean","str","stringtrim","INVALID_BASE64_RE","n","units","leadSurrogate","charCodeAt","byteArray","c","hi","lo","toByteArray","src","dst","INSPECT_MAX_BYTES","compare","x","y","isEncoding","pos","item","equals","inspect","match","byteOffset","arrayIndexOf","foundIndex","readUInt8","v","writeUInt8","isFinite","swap","toJSON","_arr","newBuf","sliceLen","readUIntLE","mul","readUIntBE","readUInt16LE","readUInt16BE","readUInt32LE","readUInt32BE","readIntLE","pow","readIntBE","readInt8","readInt16LE","readInt16BE","readInt32LE","readInt32BE","readFloatLE","read","readFloatBE","readDoubleLE","readDoubleBE","writeUIntLE","writeUIntBE","floor","writeUInt16LE","writeUInt16BE","writeUInt32LE","writeUInt32BE","writeIntLE","limit","sub","writeIntBE","writeInt8","writeInt16LE","writeInt16BE","writeInt32LE","writeInt32BE","writeFloatLE","writeFloatBE","writeDoubleLE","writeDoubleBE","target","targetStart","_set","fill","toArrayBuffer","BP","toLocaleString","IdentityStrategy","WorldApiAdapter","_loadRun","loadRunFromWorld","serverError","StateApi","_store","stateApi","_restoreRun","_getAllRuns","user.id","scope.group","dateComp","latestRun","shouldReplay","isLE","mLen","nBytes","m","eLen","eMax","eBias","nBits","s","NaN","rt","abs","LN2","lookup","elt","code","PLUS","PLUS_URL_SAFE","SLASH","SLASH_URL_SAFE","NUMBER","UPPER","LOWER","b64ToByteArray","b64","L","l","tmp","placeHolders","Arr","uint8ToBase64","uint8","encode","num","tripletToBase64","temp","extraBytes","output","base64js"],"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.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","/**\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 && 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 = '?include='.length;\n var variable = include.pop();\n while (variable) {\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 + variable.length + 1 < diff) {\n currIncludes.push(variable);\n currLength += variable.length + 1;\n } else {\n currIncludes = [variable];\n includeOpts.push(currIncludes);\n currLength = '?include='.length + variable.length;\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 StorageFactory = require('../store/store-factory');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n // config || (config = configService.get());\n var store = new StorageFactory({ synchronous: true });\n\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: store.get('epicenter.project.token') || store.get('epicenter.token') || '',\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: '',\n\n /**\n * The project id. Defaults to empty string.\n * @type {String}\n */\n project: '',\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 var serviceOptions = $.extend({}, 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 {String} `folderType` One of Model|Static|Node\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getContents: function (filePath, folderType, options) {\n var path = 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 $.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 StorageFactory = require('../store/store-factory');\nvar qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n\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: '',\n\n /**\n * The project id. Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: '',\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: store.get('epicenter.project.token') || '',\n\n domain: 'forio.com',\n\n //Options to pass on to the underlying transport layer\n transport: {}\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 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 methods for logging in and logging out. On login, this service 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 * auth.logout();\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 /**\n * Logs user out from specified accounts.\n * Epicenter logout is not implemented yet, added 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 apiEndpoint = 'model/state';\n\nmodule.exports = function (config) {\n\n var defaults = {\n\n };\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(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');\nvar StorageFactory = require('../store/store-factory');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\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 store = new StorageFactory({ synchronous: true });\n\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: store.get('epicenter.project.token') || '',\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 var serviceOptions = $.extend({}, 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 // 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 $.extend(params, _pick(serviceOptions, ['account', 'project', 'group']));\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 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: '',\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: '',\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 var serviceOptions = $.extend({}, 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 _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: '',\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: '',\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(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 StorageFactory = require('../store/store-factory');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar keyNames = require('../managers/key-names');\n\nvar apiEndpoint = 'asset';\n\nmodule.exports = function (config) {\n var store = new StorageFactory({ synchronous: true });\n var session = JSON.parse(store.get(keyNames.EPI_SESSION_KEY) || '{}');\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: store.get(keyNames.EPI_COOKIE_KEY) || '',\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: session.groupName,\n /**\n * The user id. Defaults to session's `userId`.\n * @type {String}\n */\n userId: session.userId,\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 var serviceOptions = $.extend(true, {}, 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\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Name of collection\n * @type { string}\n */\n root: '/',\n\n domain: '.forio.com'\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\n document.cookie = encodeURIComponent(key) + '=' +\n encodeURIComponent(value) +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '');\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 cookieReg = new RegExp('(?:(?:^|.*;)\\\\s*' + encodeURIComponent(key).replace(/[\\-\\.\\+\\*]/g, '\\\\$&') + '\\\\s*\\\\=\\\\s*([^;]*).*$)|^.*$');\n var val = document.cookie.replace(cookieReg, '$1');\n val = decodeURIComponent(val) || 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\n document.cookie = encodeURIComponent(key) +\n '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '');\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 aKeys = document.cookie.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 ConfigService = require('../service/configuration-service');\nvar AuthAdapter = require('../service/auth-api-service');\nvar MemberAdapter = require('../service/member-api-adapter');\nvar StorageFactory = require('../store/store-factory');\nvar Buffer = require('buffer').Buffer;\nvar keyNames = require('./key-names');\n\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 EPI_COOKIE_KEY = keyNames.EPI_COOKIE_KEY;\nvar EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY;\nvar token;\nvar session;\n\nfunction saveSession(userInfo, store) {\n var serialized = JSON.stringify(userInfo);\n store.set(EPI_SESSION_KEY, serialized);\n\n //jshint camelcase: false\n //jscs:disable\n store.set(EPI_COOKIE_KEY, userInfo.auth_token);\n}\n\nfunction getSession(store) {\n var session = store.get(EPI_SESSION_KEY) || '{}';\n return JSON.parse(session);\n}\n\nfunction AuthManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n var urlConfig = new ConfigService(this.options).get('server');\n this.isLocal = urlConfig.isLocalhost();\n\n if (!this.options.account) {\n this.options.account = urlConfig.accountPath;\n }\n\n // null might specified to disable project filtering\n if (this.options.project === undefined) {\n this.options.project = urlConfig.projectPath;\n }\n\n this.store = new StorageFactory(this.options.store);\n session = getSession(this.store);\n token = this.store.get(EPI_COOKIE_KEY) || '';\n //jshint camelcase: false\n //jscs:disable\n this.authAdapter = new AuthAdapter(this.options, { token: session.auth_token });\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 groupSelection = group.groupId;\n data.groupSelection[adapterOptions.project] = groupSelection;\n var sessionInfoWithGroup = $.extend({}, sessionInfo, {\n 'groupId': group.groupId,\n 'groupName': group.name,\n 'isFac': _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator'\n });\n saveSession(sessionInfoWithGroup, _this.store);\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.\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 = $.extend(true, { token: token }, this.options, options);\n\n var removeCookieFn = function (response) {\n _this.store.remove(EPI_COOKIE_KEY, adapterOptions);\n _this.store.remove(EPI_SESSION_KEY, adapterOptions);\n token = '';\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 = $.extend(true, this.options, options);\n\n var $d = $.Deferred();\n if (token) {\n $d.resolve(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 = $.extend(true, { success: $.noop }, this.options, 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 * By default, session information is stored in a cookie in the browser. You can change this with the `store` configuration option.\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 getSession(this.store, options);\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 * * `server` Object with details about the Epicenter project for this Epicenter Channel Manager instance.\n * * `server.account` The Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `server.project` Epicenter project id.\n */\n\nvar ChannelManager = require('./channel-manager');\nvar classFrom = require('../util/inherit');\nvar urlService = require('../service/url-config-service');\n\nvar AuthManager = require('./auth-manager');\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 var userInfo = session.getCurrentUserSessionInfo();\n\n var defaults = {\n account: userInfo.account,\n project: userInfo.project,\n };\n var defaultCometOptions = $.extend(true, {}, defaults, userInfo, 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 this.options = defaultCometOptions;\n return __super.constructor.call(this, defaultCometOptions);\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');\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');\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');\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/users', 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');\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName');\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/users', 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 gc = cm.getDataChannel('survey-responses');\n * gc.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","'use strict';\n\nmodule.exports = {\n EPI_COOKIE_KEY: 'epicenter.project.token',\n EPI_SESSION_KEY: 'epicenter.user.session',\n STRATEGY_SESSION_KEY: 'epicenter-scenario'\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');\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 var defaultCometOptions = $.extend(true, {}, 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();\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","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\nvar base64 = require('base64-js')\nvar ieee754 = require('ieee754')\nvar isArray = require('is-array')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\nBuffer.poolSize = 8192 // not used by this implementation\n\nvar rootParent = {}\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 * - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property\n * on objects.\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\nfunction typedArraySupport () {\n function Bar () {}\n try {\n var arr = new Uint8Array(1)\n arr.foo = function () { return 42 }\n arr.constructor = Bar\n return arr.foo() === 42 && // typed array instances can be augmented\n arr.constructor === Bar && // constructor can be set\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\n/**\n * Class: Buffer\n * =============\n *\n * The Buffer constructor returns instances of `Uint8Array` that are augmented\n * with function properties for all the node `Buffer` API functions. We use\n * `Uint8Array` so that square bracket notation works as expected -- it returns\n * a single octet.\n *\n * By augmenting the instances, we can avoid modifying the `Uint8Array`\n * prototype.\n */\nfunction Buffer (arg) {\n if (!(this instanceof Buffer)) {\n // Avoid going through an ArgumentsAdaptorTrampoline in the common case.\n if (arguments.length > 1) return new Buffer(arg, arguments[1])\n return new Buffer(arg)\n }\n\n this.length = 0\n this.parent = undefined\n\n // Common case.\n if (typeof arg === 'number') {\n return fromNumber(this, arg)\n }\n\n // Slightly less common case.\n if (typeof arg === 'string') {\n return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8')\n }\n\n // Unusual.\n return fromObject(this, arg)\n}\n\nfunction fromNumber (that, length) {\n that = allocate(that, length < 0 ? 0 : checked(length) | 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) {\n for (var i = 0; i < length; i++) {\n that[i] = 0\n }\n }\n return that\n}\n\nfunction fromString (that, string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8'\n\n // Assumption: byteLength() return value is always < kMaxLength.\n var length = byteLength(string, encoding) | 0\n that = allocate(that, length)\n\n that.write(string, encoding)\n return that\n}\n\nfunction fromObject (that, object) {\n if (Buffer.isBuffer(object)) return fromBuffer(that, object)\n\n if (isArray(object)) return fromArray(that, object)\n\n if (object == null) {\n throw new TypeError('must start with number, buffer, array or string')\n }\n\n if (typeof ArrayBuffer !== 'undefined') {\n if (object.buffer instanceof ArrayBuffer) {\n return fromTypedArray(that, object)\n }\n if (object instanceof ArrayBuffer) {\n return fromArrayBuffer(that, object)\n }\n }\n\n if (object.length) return fromArrayLike(that, object)\n\n return fromJsonObject(that, object)\n}\n\nfunction fromBuffer (that, buffer) {\n var length = checked(buffer.length) | 0\n that = allocate(that, length)\n buffer.copy(that, 0, 0, length)\n return that\n}\n\nfunction fromArray (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\n// Duplicate of fromArray() to keep fromArray() monomorphic.\nfunction fromTypedArray (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n // Truncating the elements is probably not what people expect from typed\n // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior\n // of the old Buffer constructor.\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) {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n array.byteLength\n that = Buffer._augment(new Uint8Array(array))\n } else {\n // Fallback: Return an object instance of the Buffer class\n that = fromTypedArray(that, new Uint8Array(array))\n }\n return that\n}\n\nfunction fromArrayLike (that, array) {\n var length = checked(array.length) | 0\n that = allocate(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\n// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object.\n// Returns a zero-length buffer for inputs that don't conform to the spec.\nfunction fromJsonObject (that, object) {\n var array\n var length = 0\n\n if (object.type === 'Buffer' && isArray(object.data)) {\n array = object.data\n length = checked(array.length) | 0\n }\n that = allocate(that, length)\n\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n Buffer.prototype.__proto__ = Uint8Array.prototype\n Buffer.__proto__ = Uint8Array\n}\n\nfunction allocate (that, length) {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = Buffer._augment(new Uint8Array(length))\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n that.length = length\n that._isBuffer = true\n }\n\n var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1\n if (fromPool) that.parent = rootParent\n\n return that\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 (subject, encoding) {\n if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding)\n\n var buf = new Buffer(subject, encoding)\n delete buf.parent\n return buf\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 var i = 0\n var len = Math.min(x, y)\n while (i < len) {\n if (a[i] !== b[i]) break\n\n ++i\n }\n\n if (i !== len) {\n x = a[i]\n y = b[i]\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)) throw new TypeError('list argument must be an Array of Buffers.')\n\n if (list.length === 0) {\n return new Buffer(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 buf = new Buffer(length)\n var pos = 0\n for (i = 0; i < list.length; i++) {\n var item = list[i]\n item.copy(buf, pos)\n pos += item.length\n }\n return buf\n}\n\nfunction byteLength (string, encoding) {\n if (typeof string !== 'string') string = '' + string\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 // Deprecated\n case 'raw':\n case 'raws':\n return len\n case 'utf8':\n case 'utf-8':\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\n// pre-set for values that may exist in the future\nBuffer.prototype.length = undefined\nBuffer.prototype.parent = undefined\n\nfunction slowToString (encoding, start, end) {\n var loweredCase = false\n\n start = start | 0\n end = end === undefined || end === Infinity ? this.length : end | 0\n\n if (!encoding) encoding = 'utf8'\n if (start < 0) start = 0\n if (end > this.length) end = this.length\n if (end <= start) return ''\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\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 (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return 0\n return Buffer.compare(this, b)\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset) {\n if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff\n else if (byteOffset < -0x80000000) byteOffset = -0x80000000\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 if (val.length === 0) return -1 // special case: looking for empty string always fails\n return String.prototype.indexOf.call(this, val, byteOffset)\n }\n if (Buffer.isBuffer(val)) {\n return arrayIndexOf(this, val, byteOffset)\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)\n }\n\n function arrayIndexOf (arr, val, byteOffset) {\n var foundIndex = -1\n for (var i = 0; byteOffset + i < arr.length; i++) {\n if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) {\n if (foundIndex === -1) foundIndex = i\n if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex\n } else {\n foundIndex = -1\n }\n }\n return -1\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\n// `get` is deprecated\nBuffer.prototype.get = function get (offset) {\n console.log('.get() is deprecated. Access using array indexes instead.')\n return this.readUInt8(offset)\n}\n\n// `set` is deprecated\nBuffer.prototype.set = function set (v, offset) {\n console.log('.set() is deprecated. Access using array indexes instead.')\n return this.writeUInt8(v, offset)\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)) throw new Error('Invalid hex string')\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 var swap = encoding\n encoding = offset\n offset = length | 0\n length = swap\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 = Buffer._augment(this.subarray(start, end))\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 if (newBuf.length) newBuf.parent = this.parent || this\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 must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('value 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) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\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) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\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 = value < 0 ? 1 : 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\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 = value < 0 ? 1 : 0\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\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 (value > max || value < min) throw new RangeError('value is out of bounds')\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 target._set(this.subarray(start, start + len), targetStart)\n }\n\n return len\n}\n\n// fill(value, start=0, end=buffer.length)\nBuffer.prototype.fill = function fill (value, start, end) {\n if (!value) value = 0\n if (!start) start = 0\n if (!end) end = this.length\n\n if (end < start) throw new RangeError('end < start')\n\n // Fill 0 bytes; we're done\n if (end === start) return\n if (this.length === 0) return\n\n if (start < 0 || start >= this.length) throw new RangeError('start out of bounds')\n if (end < 0 || end > this.length) throw new RangeError('end out of bounds')\n\n var i\n if (typeof value === 'number') {\n for (i = start; i < end; i++) {\n this[i] = value\n }\n } else {\n var bytes = utf8ToBytes(value.toString())\n var len = bytes.length\n for (i = start; i < end; i++) {\n this[i] = bytes[i % len]\n }\n }\n\n return this\n}\n\n/**\n * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.\n * Added in Node 0.12. Only available in browsers that support ArrayBuffer.\n */\nBuffer.prototype.toArrayBuffer = function toArrayBuffer () {\n if (typeof Uint8Array !== 'undefined') {\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n return (new Buffer(this)).buffer\n } else {\n var buf = new Uint8Array(this.length)\n for (var i = 0, len = buf.length; i < len; i += 1) {\n buf[i] = this[i]\n }\n return buf.buffer\n }\n } else {\n throw new TypeError('Buffer.toArrayBuffer not supported in this browser')\n }\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar BP = Buffer.prototype\n\n/**\n * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods\n */\nBuffer._augment = function _augment (arr) {\n arr.constructor = Buffer\n arr._isBuffer = true\n\n // save reference to original Uint8Array set method before overwriting\n arr._set = arr.set\n\n // deprecated\n arr.get = BP.get\n arr.set = BP.set\n\n arr.write = BP.write\n arr.toString = BP.toString\n arr.toLocaleString = BP.toString\n arr.toJSON = BP.toJSON\n arr.equals = BP.equals\n arr.compare = BP.compare\n arr.indexOf = BP.indexOf\n arr.copy = BP.copy\n arr.slice = BP.slice\n arr.readUIntLE = BP.readUIntLE\n arr.readUIntBE = BP.readUIntBE\n arr.readUInt8 = BP.readUInt8\n arr.readUInt16LE = BP.readUInt16LE\n arr.readUInt16BE = BP.readUInt16BE\n arr.readUInt32LE = BP.readUInt32LE\n arr.readUInt32BE = BP.readUInt32BE\n arr.readIntLE = BP.readIntLE\n arr.readIntBE = BP.readIntBE\n arr.readInt8 = BP.readInt8\n arr.readInt16LE = BP.readInt16LE\n arr.readInt16BE = BP.readInt16BE\n arr.readInt32LE = BP.readInt32LE\n arr.readInt32BE = BP.readInt32BE\n arr.readFloatLE = BP.readFloatLE\n arr.readFloatBE = BP.readFloatBE\n arr.readDoubleLE = BP.readDoubleLE\n arr.readDoubleBE = BP.readDoubleBE\n arr.writeUInt8 = BP.writeUInt8\n arr.writeUIntLE = BP.writeUIntLE\n arr.writeUIntBE = BP.writeUIntBE\n arr.writeUInt16LE = BP.writeUInt16LE\n arr.writeUInt16BE = BP.writeUInt16BE\n arr.writeUInt32LE = BP.writeUInt32LE\n arr.writeUInt32BE = BP.writeUInt32BE\n arr.writeIntLE = BP.writeIntLE\n arr.writeIntBE = BP.writeIntBE\n arr.writeInt8 = BP.writeInt8\n arr.writeInt16LE = BP.writeInt16LE\n arr.writeInt16BE = BP.writeInt16BE\n arr.writeInt32LE = BP.writeInt32LE\n arr.writeInt32BE = BP.writeInt32BE\n arr.writeFloatLE = BP.writeFloatLE\n arr.writeFloatBE = BP.writeFloatBE\n arr.writeDoubleLE = BP.writeDoubleLE\n arr.writeDoubleBE = BP.writeDoubleBE\n arr.fill = BP.fill\n arr.inspect = BP.inspect\n arr.toArrayBuffer = BP.toArrayBuffer\n\n return arr\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","'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","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 lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n;(function (exports) {\n\t'use strict';\n\n var Arr = (typeof Uint8Array !== 'undefined')\n ? Uint8Array\n : Array\n\n\tvar PLUS = '+'.charCodeAt(0)\n\tvar SLASH = '/'.charCodeAt(0)\n\tvar NUMBER = '0'.charCodeAt(0)\n\tvar LOWER = 'a'.charCodeAt(0)\n\tvar UPPER = 'A'.charCodeAt(0)\n\tvar PLUS_URL_SAFE = '-'.charCodeAt(0)\n\tvar SLASH_URL_SAFE = '_'.charCodeAt(0)\n\n\tfunction decode (elt) {\n\t\tvar code = elt.charCodeAt(0)\n\t\tif (code === PLUS ||\n\t\t code === PLUS_URL_SAFE)\n\t\t\treturn 62 // '+'\n\t\tif (code === SLASH ||\n\t\t code === SLASH_URL_SAFE)\n\t\t\treturn 63 // '/'\n\t\tif (code < NUMBER)\n\t\t\treturn -1 //no match\n\t\tif (code < NUMBER + 10)\n\t\t\treturn code - NUMBER + 26 + 26\n\t\tif (code < UPPER + 26)\n\t\t\treturn code - UPPER\n\t\tif (code < LOWER + 26)\n\t\t\treturn code - LOWER + 26\n\t}\n\n\tfunction b64ToByteArray (b64) {\n\t\tvar i, j, l, tmp, placeHolders, arr\n\n\t\tif (b64.length % 4 > 0) {\n\t\t\tthrow new Error('Invalid string. Length must be a multiple of 4')\n\t\t}\n\n\t\t// the number of equal signs (place holders)\n\t\t// if there are two placeholders, than the two characters before it\n\t\t// represent one byte\n\t\t// if there is only one, then the three characters before it represent 2 bytes\n\t\t// this is just a cheap hack to not do indexOf twice\n\t\tvar len = b64.length\n\t\tplaceHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0\n\n\t\t// base64 is 4/3 + up to two characters of the original data\n\t\tarr = new Arr(b64.length * 3 / 4 - placeHolders)\n\n\t\t// if there are placeholders, only get up to the last complete 4 chars\n\t\tl = placeHolders > 0 ? b64.length - 4 : b64.length\n\n\t\tvar L = 0\n\n\t\tfunction push (v) {\n\t\t\tarr[L++] = v\n\t\t}\n\n\t\tfor (i = 0, j = 0; i < l; i += 4, j += 3) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))\n\t\t\tpush((tmp & 0xFF0000) >> 16)\n\t\t\tpush((tmp & 0xFF00) >> 8)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\tif (placeHolders === 2) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)\n\t\t\tpush(tmp & 0xFF)\n\t\t} else if (placeHolders === 1) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)\n\t\t\tpush((tmp >> 8) & 0xFF)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\treturn arr\n\t}\n\n\tfunction uint8ToBase64 (uint8) {\n\t\tvar i,\n\t\t\textraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes\n\t\t\toutput = \"\",\n\t\t\ttemp, length\n\n\t\tfunction encode (num) {\n\t\t\treturn lookup.charAt(num)\n\t\t}\n\n\t\tfunction tripletToBase64 (num) {\n\t\t\treturn encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)\n\t\t}\n\n\t\t// go through the array every three bytes, we'll deal with trailing stuff later\n\t\tfor (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {\n\t\t\ttemp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])\n\t\t\toutput += tripletToBase64(temp)\n\t\t}\n\n\t\t// pad the end with zeros, but make sure to not forget the extra bytes\n\t\tswitch (extraBytes) {\n\t\t\tcase 1:\n\t\t\t\ttemp = uint8[uint8.length - 1]\n\t\t\t\toutput += encode(temp >> 2)\n\t\t\t\toutput += encode((temp << 4) & 0x3F)\n\t\t\t\toutput += '=='\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\ttemp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])\n\t\t\t\toutput += encode(temp >> 10)\n\t\t\t\toutput += encode((temp >> 4) & 0x3F)\n\t\t\t\toutput += encode((temp << 2) & 0x3F)\n\t\t\t\toutput += '='\n\t\t\t\tbreak\n\t\t}\n\n\t\treturn output\n\t}\n\n\texports.toByteArray = b64ToByteArray\n\texports.fromByteArray = uint8ToBase64\n}(typeof exports === 'undefined' ? (this.base64js = {}) : exports))\n","\n/**\n * isArray\n */\n\nvar isArray = Array.isArray;\n\n/**\n * toString\n */\n\nvar str = Object.prototype.toString;\n\n/**\n * Whether or not the given `val`\n * is an array.\n *\n * example:\n *\n * isArray([]);\n * // > true\n * isArray(arguments);\n * // > false\n * isArray('');\n * // > false\n *\n * @param {mixed} val\n * @return {bool}\n */\n\nmodule.exports = isArray || function (val) {\n return !! val && '[object Array]' == str.call(val);\n};\n"]} \ No newline at end of file diff --git a/src/managers/auth-manager.js b/src/managers/auth-manager.js index 5aff931c..e20ba047 100644 --- a/src/managers/auth-manager.js +++ b/src/managers/auth-manager.js @@ -48,11 +48,10 @@ var defaults = { var EPI_COOKIE_KEY = keyNames.EPI_COOKIE_KEY; var EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY; -var store; var token; var session; -function saveSession(userInfo) { +function saveSession(userInfo, store) { var serialized = JSON.stringify(userInfo); store.set(EPI_SESSION_KEY, serialized); @@ -61,7 +60,7 @@ function saveSession(userInfo) { store.set(EPI_COOKIE_KEY, userInfo.auth_token); } -function getSession() { +function getSession(store) { var session = store.get(EPI_SESSION_KEY) || '{}'; return JSON.parse(session); } @@ -70,6 +69,8 @@ function AuthManager(options) { this.options = $.extend(true, {}, defaults, options); var urlConfig = new ConfigService(this.options).get('server'); + this.isLocal = urlConfig.isLocalhost(); + if (!this.options.account) { this.options.account = urlConfig.accountPath; } @@ -79,9 +80,9 @@ function AuthManager(options) { this.options.project = urlConfig.projectPath; } - store = new StorageFactory(this.options.store); - session = getSession(); - token = store.get(EPI_COOKIE_KEY) || ''; + this.store = new StorageFactory(this.options.store); + session = getSession(this.store); + token = this.store.get(EPI_COOKIE_KEY) || ''; //jshint camelcase: false //jscs:disable this.authAdapter = new AuthAdapter(this.options, { token: session.auth_token }); @@ -107,9 +108,9 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * * authMgr.login({ * account: 'acme-simulations', - * project: 'supply-chain-game', + * project: 'supply-chain-game', * userName: 'enduser1', - * password: 'passw0rd' + * password: 'passw0rd' * }) * .then(function(statusObj) { * // if enduser1 belongs to exactly one group @@ -117,8 +118,8 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * // continue here * }) * .fail(function(statusObj) { - * // if enduser1 belongs to multiple groups, - * // the login() call fails + * // if enduser1 belongs to multiple groups, + * // the login() call fails * // and returns all groups of which the user is a member * for (var i=0; i < statusObj.userGroups.length; i++) { * console.log(statusObj.userGroups[i].name, statusObj.userGroups[i].groupId); @@ -127,12 +128,12 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * * **Parameters** * - * @param {Object} `options` (Optional) Overrides for configuration options. If not passed in when creating an instance of the manager (`F.manager.AuthManager()`), these options should include: + * @param {Object} `options` (Optional) Overrides for configuration options. If not passed in when creating an instance of the manager (`F.manager.AuthManager()`), these options should include: * @param {string} `options.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). * @param {string} `options.userName` Email or username to use for logging in. * @param {string} `options.password` Password for specified `userName`. * @param {string} `options.project` (Optional) The **Project ID** for the project to log this user into. - * @param {string} `options.groupId` The id of the group to which `userName` belongs. Required for [end users](../../../glossary/#users) if the `project` is specified and if the end users are members of multiple [groups](../../../glossary/#groups), otherwise optional. + * @param {string} `options.groupId` The id of the group to which `userName` belongs. Required for [end users](../../../glossary/#users) if the `project` is specified and if the end users are members of multiple [groups](../../../glossary/#groups), otherwise optional. */ login: function (options) { var _this = this; @@ -142,6 +143,13 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { var outError = adapterOptions.error; var groupId = adapterOptions.groupId; + var accountName = (options && options.account) ? options.account : this.options.account; + var projectName = (options && options.project) ? options.project : this.options.project; + + if (this.options.store.root === undefined && accountName && projectName) { + this.store.serviceOptions.root = this.isLocal ? '/' : '/app/' + accountName + '/' + projectName; + } + var decodeToken = function (token) { var encoded = token.split('.')[1]; while (encoded.length % 4 !== 0) { @@ -165,7 +173,6 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { //jshint camelcase: false //jscs:disable token = response.access_token; - var userInfo = decodeToken(token); var userGroupOpts = $.extend(true, {}, adapterOptions, { success: $.noop, token: token }); _this.getUserGroups({ userId: userInfo.user_id, token: token }, userGroupOpts).done( function (memberInfo) { @@ -179,7 +186,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { }; // The group is not required if the user is not logging into a project if (!adapterOptions.project) { - saveSession(sessionInfo); + saveSession(sessionInfo, _this.store); outSuccess.apply(this, [data]); $d.resolve(data); return; @@ -209,7 +216,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { 'groupName': group.name, 'isFac': _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator' }); - saveSession(sessionInfoWithGroup); + saveSession(sessionInfoWithGroup, _this.store); outSuccess.apply(this, [data]); $d.resolve(data); } else { @@ -252,11 +259,12 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * @param {Object} `options` (Optional) Overrides for configuration options. */ logout: function (options) { + var _this = this; var adapterOptions = $.extend(true, { token: token }, this.options, options); var removeCookieFn = function (response) { - store.remove(EPI_COOKIE_KEY, adapterOptions); - store.remove(EPI_SESSION_KEY, adapterOptions); + _this.store.remove(EPI_COOKIE_KEY, adapterOptions); + _this.store.remove(EPI_SESSION_KEY, adapterOptions); token = ''; }; @@ -269,8 +277,8 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * **Example** * * authMgr.getToken() - * .then(function (token) { - * console.log('My token is ', token); + * .then(function (token) { + * console.log('My token is ', token); * }); * * **Parameters** @@ -298,8 +306,8 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * // get groups for current user * var sessionObj = authMgr.getCurrentUserSessionInfo(); * authMgr.getUserGroups({ userId: sessionObj.userId, token: sessionObj.auth_token }) - * .then(function (groups) { - * for (var i=0; i < groups.length; i++) + * .then(function (groups) { + * for (var i=0; i < groups.length; i++) * { console.log(groups[i].name); } * }); * @@ -339,7 +347,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * * *Important*: This method is synchronous. The session information is returned immediately in an object; no callbacks or promises are needed. * - * By default, session information is stored in a cookie in the browser. You can change this with the `store` configuration option. + * By default, session information is stored in a cookie in the browser. You can change this with the `store` configuration option. * * **Example** * @@ -349,7 +357,7 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { * @param {Object} `options` (Optional) Overrides for configuration options. */ getCurrentUserSessionInfo: function (options) { - return getSession(options); + return getSession(this.store, options); } }); diff --git a/src/store/cookie-store.js b/src/store/cookie-store.js index 10274980..117394a8 100644 --- a/src/store/cookie-store.js +++ b/src/store/cookie-store.js @@ -21,7 +21,7 @@ module.exports = function (config) { domain: '.forio.com' }; - var serviceOptions = $.extend({}, defaults, config); + this.serviceOptions = $.extend({}, defaults, config); var publicAPI = { // * TBD @@ -54,7 +54,7 @@ module.exports = function (config) { * cs.set({ name:'smith', age:'32' }); */ set: function (key, value, options) { - var setOptions = $.extend(true, {}, serviceOptions, options); + var setOptions = $.extend(true, {}, this.serviceOptions, options); var domain = setOptions.domain; var path = setOptions.root; @@ -91,7 +91,7 @@ module.exports = function (config) { * cs.remove('person'); */ remove: function (key, options) { - var remOptions = $.extend(true, {}, serviceOptions, options); + var remOptions = $.extend(true, {}, this.serviceOptions, options); var domain = remOptions.domain; var path = remOptions.root; diff --git a/tests/spec/test-auth-manager.js b/tests/spec/test-auth-manager.js index d96742fd..7e7758c9 100644 --- a/tests/spec/test-auth-manager.js +++ b/tests/spec/test-auth-manager.js @@ -1,6 +1,5 @@ (function () { 'use strict'; - describe('Auth Manager', function () { var server, token; before(function () { @@ -47,5 +46,28 @@ }); // TODO: Create some test, find a way for the fake server to auto respond synchronously inside a respond callback + describe('#setting cookies', 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' + }); + am.isLocal = false ; + am.login(); + am.store.serviceOptions.root.should.equal('/app/accountName/projectName'); + }); + }); + describe('#setting cookies', function () { + it ('creates cookie with the correct path name when passing in account info in login', function () { + var am = new F.manager.AuthManager(); + am.isLocal = false; + am.login({ + account: 'accountName', + project: 'projectName' + }); + am.store.serviceOptions.root.should.equal('/app/accountName/projectName'); + }); + }); + }); }());